diff --git a/src/main/java/com/imutil/controller/AdminController.java b/src/main/java/com/imutil/controller/AdminController.java
index e826196..62e5c9b 100644
--- a/src/main/java/com/imutil/controller/AdminController.java
+++ b/src/main/java/com/imutil/controller/AdminController.java
@@ -15,12 +15,20 @@ import com.imutil.mapper.UsageStatMapper;
import com.imutil.service.AdminUserService;
import com.imutil.service.SourceAppService;
import com.imutil.tencent.TencentImClient;
+import com.imutil.entity.ImMessage;
import com.imutil.entity.MigrateTask;
import com.imutil.service.MigrateService;
+import com.imutil.mapper.ImMessageMapper;
import org.noear.solon.core.handle.UploadedFile;
import java.nio.charset.StandardCharsets;
+import java.time.format.DateTimeFormatter;
+import java.time.LocalDate;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
@@ -59,6 +67,9 @@ public class AdminController {
@Inject
private DistQueueMapper distQueueMapper;
+ @Inject
+ private ImMessageMapper imMessageMapper;
+
@Inject
private UsageStatMapper usageStatMapper;
@@ -520,6 +531,150 @@ public class AdminController {
* @param title 页面标题
* @param active 侧边栏高亮项(home/tenant/grant/queue/usage)
*/
+ // ==================== 消息记录 ====================
+
+ /**
+ * 消息记录列表(已分发消息查询)
+ *
+ * 默认最近 7 天 + 已分发(dist_status=1);带 msg_time 范围走分区裁剪。
+ */
+ @Get
+ @Mapping("/messages")
+ public Object messagesPage(@Param(defaultValue = "") String tenantId,
+ @Param(required = false) Integer convType,
+ @Param(defaultValue = "1") Integer distStatus,
+ @Param(defaultValue = "") String dateFrom,
+ @Param(defaultValue = "") String dateTo,
+ @Param(defaultValue = "") String keyword,
+ @Param(defaultValue = "1") int page,
+ @Param(defaultValue = "20") int size) {
+ // 默认时间窗:最近 7 天(带 msg_time 范围触发分区裁剪,避免全分区扫描)
+ OffsetDateTime now = OffsetDateTime.now();
+ OffsetDateTime from = parseDateStart(dateFrom, now.minusDays(7));
+ OffsetDateTime to = parseDateEnd(dateTo, now);
+ int safePage = Math.max(1, page);
+ int safeSize = size <= 0 ? 20 : Math.min(size, 200);
+ int offset = (safePage - 1) * safeSize;
+
+ String tid = (tenantId == null || tenantId.isEmpty()) ? null : tenantId;
+ String kw = (keyword == null || keyword.isEmpty()) ? null : keyword;
+ List rawRows = imMessageMapper.selectMessagePage(tid, convType, distStatus, from, to, kw, offset, safeSize);
+ long total = imMessageMapper.countMessages(tid, convType, distStatus, from, to, kw);
+ int totalPages = (int) ((total + safeSize - 1) / Math.max(1, safeSize));
+
+ // 转成 Map 并预格式化时间(FreeMarker 对 java.time OffsetDateTime 格式化支持不稳,Controller 端处理)
+ DateTimeFormatter fmtDisp = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ DateTimeFormatter fmtIso = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSxxx");
+ List