diff --git a/admin/dashboard/blueprints/robot.py b/admin/dashboard/blueprints/robot.py
index 064dbbb..f6a50fa 100644
--- a/admin/dashboard/blueprints/robot.py
+++ b/admin/dashboard/blueprints/robot.py
@@ -97,8 +97,9 @@ def _load_recent_group_summaries(server, group_id: str, limit: int = 3) -> list:
设计说明:
1. 群画像适合给“结论”,但运营者往往还想看到最近几期总结到底说了什么;
- 2. 这里不把整段长文原样吐给前端,而是裁成可扫读的短摘要,避免弹窗过重;
- 3. 若没有总结记录,返回空列表,由前端优雅降级。
+ 2. 默认卡片仍使用短摘要,避免详情页被大段文本挤占;
+ 3. 同时补充完整总结正文,供前端弹窗按需展开查看;
+ 4. 若没有总结记录,返回空列表,由前端优雅降级。
"""
summary_db = getattr(server, "message_summary_db", None)
if summary_db is None:
@@ -124,6 +125,9 @@ def _load_recent_group_summaries(server, group_id: str, limit: int = 3) -> list:
"summary_type": str(row.get("summary_type") or "").strip(),
"source_message_count": int(row.get("source_message_count") or 0),
"last_generated_at": str(row.get("last_generated_at") or "").strip(),
+ # 详情弹窗需要查看完整总结正文;这里保留原文,不做截断。
+ "summary_text": raw_summary,
+ # 卡片区域继续展示压缩后的摘要,避免详情首屏信息密度过高。
"summary_excerpt": normalized_summary[:180] + ("..." if len(normalized_summary) > 180 else ""),
})
return result
diff --git a/admin/dashboard/templates/contacts_management.html b/admin/dashboard/templates/contacts_management.html
index 5122f6e..0ef67fe 100644
--- a/admin/dashboard/templates/contacts_management.html
+++ b/admin/dashboard/templates/contacts_management.html
@@ -349,10 +349,24 @@
-
{% raw %}{{ item.period_key || '-' }}{% endraw %}
-
{% raw %}{{ item.source_message_count || 0 }}{% endraw %} 条消息
+
+ {% raw %}{{ item.period_key || '-' }}{% endraw %}
+ {% raw %}{{ formatSummaryTypeLabel(item.summary_type) }}{% endraw %}
+
+
+ {% raw %}{{ item.source_message_count || 0 }}{% endraw %} 条消息
+
+ 查看全文
+
+
{% raw %}{{ item.summary_excerpt || '暂无摘要内容' }}{% endraw %}
+
{% raw %}{{ item.last_generated_at || '暂无生成时间' }}{% endraw %}
当前还没有可展示的群总结记录
@@ -850,6 +864,21 @@
+
+
+
+ {% raw %}{{ currentSummaryRecord.period_key || '-' }}{% endraw %}
+ {% raw %}{{ formatSummaryTypeLabel(currentSummaryRecord.summary_type) }}{% endraw %}
+ {% raw %}{{ currentSummaryRecord.source_message_count || 0 }}{% endraw %} 条
+ {% raw %}{{ currentSummaryRecord.last_generated_at || '-' }}{% endraw %}
+
+
+
完整总结
+
{% raw %}{{ currentSummaryRecord.summary_text || '暂无可展示的总结正文' }}{% endraw %}
+
+
+
+
true" class="detail-avatar">
@@ -1053,6 +1082,9 @@
groupAnnouncementSyncing: false,
groupInsight: null,
groupInsightLoading: false,
+ // 群总结正文采用弹窗承载,避免详情区被长文本撑满。
+ summaryDetailDialogVisible: false,
+ currentSummaryRecord: null,
groupMembersList: [], groupMembersCurrentPage: 1, groupMembersPageSize: 10, groupMemberSearchQuery: '', groupMembersLoading: false,
memberContextDialogVisible: false, memberContextLoading: false, memberContext: null, currentContextMember: {},
memberContextEnabled: false,
@@ -1217,6 +1249,9 @@
// 切换群时恢复默认折叠态,保持“手动展开再看”的交互习惯。
this.groupPermissionsCollapsed = true;
this.groupWelcomeCollapsed = true;
+ // 群总结详情挂在当前群上下文里,因此切群时要清空旧弹窗与旧正文。
+ this.summaryDetailDialogVisible = false;
+ this.currentSummaryRecord = null;
this.groupDetailDialogVisible = true;
// 进入群详情时先加载群资料,保证群主/公告/管理员信息第一时间可见。
this.loadGroupProfile(group.wxid);
@@ -1225,6 +1260,27 @@
this.loadGroupInsights(group.wxid);
this.loadGroupWelcomeConfig(group.wxid);
},
+ formatSummaryTypeLabel(summaryType) {
+ const normalizedType = String(summaryType || '').trim().toLowerCase();
+ // 这里把后端枚举名映射成更像运营视角的文案,避免把内部字段直接暴露给页面。
+ if (!normalizedType) return '常规总结';
+ const labelMap = {
+ daily: '日总结',
+ weekly: '周总结',
+ monthly: '月总结',
+ manual: '手动总结'
+ };
+ return labelMap[normalizedType] || summaryType;
+ },
+ openSummaryDetailDialog(summaryItem) {
+ if (!summaryItem || !summaryItem.summary_text) {
+ this.$message.info('当前总结还没有完整内容可查看');
+ return;
+ }
+ // 只读弹窗复制一份当前记录,避免后续列表刷新时把弹窗内容一并抖掉。
+ this.currentSummaryRecord = { ...summaryItem };
+ this.summaryDetailDialogVisible = true;
+ },
viewUserDetails(user) { this.currentUser = user; this.userDetailDialogVisible = true; },
viewOfficialDetails(official) { this.currentOfficial = official; this.officialDetailDialogVisible = true; },
viewPublicDetails(publicFriend) { this.currentPublic = publicFriend; this.publicDetailDialogVisible = true; },
@@ -2106,11 +2162,33 @@
gap: 10px;
margin-bottom: 8px;
}
+ .ops-summary-head-main {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ }
+ .ops-summary-head-side {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-shrink: 0;
+ }
.ops-summary-period {
font-size: 13px;
font-weight: 700;
color: #0f172a;
}
+ .ops-summary-type {
+ display: inline-flex;
+ align-items: center;
+ padding: 2px 8px;
+ border-radius: 999px;
+ background: rgba(37,99,235,0.08);
+ color: #1d4ed8;
+ font-size: 11px;
+ line-height: 1.4;
+ }
.ops-summary-meta {
font-size: 11px;
color: #94a3b8;
@@ -2120,6 +2198,33 @@
color: #475569;
line-height: 1.7;
}
+ .ops-summary-time {
+ margin-top: 8px;
+ font-size: 11px;
+ color: #94a3b8;
+ }
+ .summary-detail-body {
+ margin-top: 16px;
+ }
+ .summary-detail-title {
+ margin-bottom: 10px;
+ font-size: 13px;
+ font-weight: 700;
+ color: #334155;
+ }
+ .summary-detail-text {
+ padding: 14px 16px;
+ border-radius: 14px;
+ border: 1px solid rgba(148,163,184,0.14);
+ background: rgba(248,250,252,0.92);
+ color: #334155;
+ line-height: 1.8;
+ font-size: 13px;
+ white-space: pre-wrap;
+ word-break: break-word;
+ max-height: 420px;
+ overflow-y: auto;
+ }
.feature-chip-list { display: flex; gap: 8px; flex-wrap: wrap; min-height: 60px; align-items: flex-start; }
.empty-inline, .detail-inline-note { font-size: 12px; color: #64748b; }
.group-announcement-wrap { display: flex; gap: 12px; align-items: flex-start; justify-content: space-between; }