From f9ba5173893a67c0710b3b8b53dc49c2e5544525 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=98=8A=E5=A4=A9?= <442384644@qq.com>
Date: Fri, 23 Oct 2026 14:09:35 +0800
Subject: [PATCH] =?UTF-8?q?fix(=E9=80=9A=E7=9F=A5=E6=97=A5=E5=BF=97):=20?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BB=9F=E8=AE=A1=E6=81=92=E4=B8=BA=200?=
=?UTF-8?q?=E3=80=81=E7=8A=B6=E6=80=81=E7=AD=9B=E9=80=89=E4=B8=A2=E5=A4=B1?=
=?UTF-8?q?=E5=B9=B6=E8=A1=A5=E5=85=A8=E5=88=97=E8=A1=A8=E5=88=86=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
后端
- NoticeLogDao::getStatistics() 原实现复用同一个查询构造器,where 条件累积,
导致 failed 恒为 0、success 含全部状态;改为每次基于独立条件 count。
- 抽出 buildWhere() 统一组装条件,列表与统计共用;统计不叠加状态条件。
- status=0(待发送)是合法筛选值,原 empty() 判断会丢弃,改为 isset + 非空串判断。
- page/limit 做整数与上限(100)校验,避免非法分页参数。
- 列表接口返回 { list, count },供前端分页使用。
前端
- 补充分页组件,搜索/重置/清理后回到第一页并同时刷新列表与统计。
- 兼容列表接口旧格式(数组)与新格式({ list, count })。
---
.../notification/NoticeLogController.php | 10 ++--
backend/app/dao/message/NoticeLogDao.php | 24 ++++++---
.../message/admin/NoticeLogServices.php | 50 +++++++++++++------
.../pages/setting/notification/log/index.vue | 49 +++++++++++++++---
4 files changed, 100 insertions(+), 33 deletions(-)
diff --git a/backend/app/adminapi/controller/setting/notification/NoticeLogController.php b/backend/app/adminapi/controller/setting/notification/NoticeLogController.php
index 9fe5b4a0d..3c24d3852 100644
--- a/backend/app/adminapi/controller/setting/notification/NoticeLogController.php
+++ b/backend/app/adminapi/controller/setting/notification/NoticeLogController.php
@@ -35,10 +35,11 @@ class NoticeLogController extends AuthController
['start_time', ''],
['end_time', ''],
]);
- $page = $this->request->get('page', 1);
- $limit = $this->request->get('limit', 20);
+ $page = max(1, (int)$this->request->get('page', 1));
+ $limit = (int)$this->request->get('limit', 20);
+ $limit = $limit > 0 && $limit <= 100 ? $limit : 20;
- return app('json')->success($this->services->getList($filter, (int)$page, (int)$limit));
+ return app('json')->success($this->services->getList($filter, $page, $limit));
}
public function detail(int $id)
@@ -55,7 +56,10 @@ class NoticeLogController extends AuthController
public function statistics()
{
+ // 与列表保持同一套筛选条件(状态筛选不参与统计)
$filter = $this->request->getMore([
+ ['mark', ''],
+ ['uid', ''],
['channel_key', ''],
['start_time', ''],
['end_time', ''],
diff --git a/backend/app/dao/message/NoticeLogDao.php b/backend/app/dao/message/NoticeLogDao.php
index 5cd31ef69..3553eedce 100644
--- a/backend/app/dao/message/NoticeLogDao.php
+++ b/backend/app/dao/message/NoticeLogDao.php
@@ -32,16 +32,26 @@ class NoticeLogDao extends BaseDao
->toArray();
}
+ /**
+ * 统计符合条件的记录数
+ * @param array $where
+ * @return int
+ */
+ public function getCount(array $where): int
+ {
+ return (int)$this->getModel()->where($where)->count();
+ }
+
public function getStatistics(array $where): array
{
- $query = $this->getModel()->where($where);
- $total = $query->count();
- $success = $query->where('status', NoticeLog::STATUS_SUCCESS)->count();
- $failed = $query->where('status', NoticeLog::STATUS_FAILED)->count();
+ // 每次 count 都基于独立的查询构造器,避免 where 条件累积(原实现复用 $query,导致 failed 恒为 0)
+ $total = $this->getCount($where);
+ $success = $this->getCount(array_merge($where, ['status' => NoticeLog::STATUS_SUCCESS]));
+ $failed = $this->getCount(array_merge($where, ['status' => NoticeLog::STATUS_FAILED]));
return [
- 'total' => (int) $total,
- 'success' => (int) $success,
- 'failed' => (int) $failed,
+ 'total' => $total,
+ 'success' => $success,
+ 'failed' => $failed,
'success_rate' => $total > 0 ? round($success / $total * 100, 2) : 0,
];
}
diff --git a/backend/app/services/message/admin/NoticeLogServices.php b/backend/app/services/message/admin/NoticeLogServices.php
index d458f2a4c..090e688b9 100644
--- a/backend/app/services/message/admin/NoticeLogServices.php
+++ b/backend/app/services/message/admin/NoticeLogServices.php
@@ -24,26 +24,48 @@ class NoticeLogServices extends BaseService
$this->dao = $dao;
}
- public function getList(array $filter = [], int $page = 1, int $limit = 20): array
+ /**
+ * 组装查询条件
+ * @param array $filter 筛选条件
+ * @param bool $withStatus 是否附加状态条件(统计口径不按状态过滤,否则成功/失败恒为 0)
+ * @return array
+ */
+ protected function buildWhere(array $filter, bool $withStatus = true): array
{
$where = [];
if (!empty($filter['mark'])) {
- $where['mark'] = $filter['mark'];
+ $where['mark'] = trim((string)$filter['mark']);
}
if (!empty($filter['uid'])) {
- $where['uid'] = $filter['uid'];
+ $where['uid'] = (int)$filter['uid'];
}
if (!empty($filter['channel_key'])) {
$where['channel_key'] = $filter['channel_key'];
}
- if (!empty($filter['status'])) {
- $where['status'] = $filter['status'];
+ // 状态 0(待发送)是合法筛选值,不能用 empty 判断,否则会被丢弃
+ if ($withStatus && isset($filter['status']) && $filter['status'] !== '' && $filter['status'] !== null) {
+ $where['status'] = (int)$filter['status'];
}
if (!empty($filter['start_time']) && !empty($filter['end_time'])) {
- $where['send_time'] = [$filter['start_time'], $filter['end_time']];
+ $where['send_time'] = [(int)$filter['start_time'], (int)$filter['end_time']];
}
+ return $where;
+ }
- return $this->dao->getList($where, '*', $page, $limit);
+ /**
+ * 发送记录列表
+ * @param array $filter
+ * @param int $page
+ * @param int $limit
+ * @return array{list: array, count: int}
+ */
+ public function getList(array $filter = [], int $page = 1, int $limit = 20): array
+ {
+ $where = $this->buildWhere($filter);
+ return [
+ 'list' => $this->dao->getList($where, '*', $page, $limit),
+ 'count' => $this->dao->getCount($where),
+ ];
}
public function getDetail(int $id): array
@@ -52,16 +74,14 @@ class NoticeLogServices extends BaseService
return $info ? $info->toArray() : [];
}
+ /**
+ * 发送统计(与列表使用同一套筛选条件,状态筛选除外)
+ * @param array $filter
+ * @return array
+ */
public function getStatistics(array $filter = []): array
{
- $where = [];
- if (!empty($filter['channel_key'])) {
- $where['channel_key'] = $filter['channel_key'];
- }
- if (!empty($filter['start_time']) && !empty($filter['end_time'])) {
- $where['send_time'] = [$filter['start_time'], $filter['end_time']];
- }
- return $this->dao->getStatistics($where);
+ return $this->dao->getStatistics($this->buildWhere($filter, false));
}
public function createLog(string $mark, int $uid, string $channelKey, string $channelName, string $title = '', string $content = ''): int
diff --git a/frontend/admin/src/pages/setting/notification/log/index.vue b/frontend/admin/src/pages/setting/notification/log/index.vue
index 9d7d87f95..63edc4b04 100644
--- a/frontend/admin/src/pages/setting/notification/log/index.vue
+++ b/frontend/admin/src/pages/setting/notification/log/index.vue
@@ -33,7 +33,7 @@