前置群列表运营速览摘要

变更项:
1. 新增群列表层批量运营速览接口,输出健康度、核心成员、待激活成员和简短运营摘要。
2. 在通讯录管理的群组列表中增加运营速览列,把成员分层摘要信号前置到列表层。
3. 保留详情页原有完整群洞察内容,不将完整成员明细直接搬到列表层,继续采用列表筛群、详情看明细的结构。
This commit is contained in:
liuwei
2026-05-06 11:50:11 +08:00
parent b618bcc30d
commit 63d5a5e716
2 changed files with 188 additions and 1 deletions

View File

@@ -82,6 +82,30 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="运营速览" min-width="340">
<template slot-scope="scope">
<div class="group-preview-cell" v-if="scope.row.ops_preview">
<div class="group-preview-tags">
<el-tag size="mini" type="warning" effect="plain">健康度 {% raw %}{{ scope.row.ops_preview.health_score }}{% endraw %}</el-tag>
<el-tag size="mini" type="success" effect="plain">核心成员 {% raw %}{{ (scope.row.ops_preview.core_member_names || []).length }}{% endraw %}</el-tag>
<el-tag size="mini" type="info" effect="plain">待激活 {% raw %}{{ scope.row.ops_preview.activation_candidate_count || 0 }}{% endraw %}</el-tag>
</div>
<div class="group-preview-members" v-if="(scope.row.ops_preview.core_member_names || []).length">
核心成员:{% raw %}{{ scope.row.ops_preview.core_member_names.join('、') }}{% endraw %}
</div>
<div class="group-preview-members" v-else>
核心成员:暂无稳定核心成员信号
</div>
<div class="group-preview-members" v-if="(scope.row.ops_preview.activation_candidate_names || []).length">
待激活:{% raw %}{{ scope.row.ops_preview.activation_candidate_names.join('、') }}{% endraw %}
</div>
<div class="group-preview-summary">{% raw %}{{ scope.row.ops_preview.summary_excerpt || '暂无运营摘要' }}{% endraw %}</div>
</div>
<div v-else class="group-preview-empty">
暂无运营速览数据
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="220">
<template slot-scope="scope">
<div class="action-row">
@@ -998,6 +1022,9 @@
publicList: [],
headImages: {},
statistics: { total: 0, groups: 0, personal: 0, official: 0, public: 0 },
// 群列表层只展示“成员分层摘要信号”,不把完整成员明细直接塞到列表里。
// 这样能先帮助筛群,再通过详情页看完整洞察。
groupOpsPreviewMap: {},
groupDetailDialogVisible: false,
userDetailDialogVisible: false,
officialDetailDialogVisible: false,
@@ -1131,9 +1158,11 @@
return {
wxid,
name,
robot_status: managed.robot_status || 'disabled'
robot_status: managed.robot_status || 'disabled',
ops_preview: null
};
});
this.loadGroupOpsPreview(this.groupsList.map(item => item.wxid));
} else {
this.$message.error('加载群组数据失败');
}
@@ -1146,6 +1175,26 @@
axios.get('/contacts/api/public').then(response => { if (response.data.success) { const publicFriends = response.data.data.public; this.publicList = Object.entries(publicFriends).map(([wxid, name]) => ({ wxid, name })); } }).catch(error => { console.error('加载公共好友数据失败:', error); this.$message.error('加载公共好友数据失败'); });
axios.get('/contacts/api/head_images').then(response => { if (response.data.success) this.headImages = response.data.data.head_images; }).catch(error => { console.error('加载联系人头像数据失败:', error); this.$message.error('加载联系人头像数据失败'); });
},
loadGroupOpsPreview(groupIds) {
const cleanIds = Array.isArray(groupIds) ? groupIds.filter(Boolean).slice(0, 30) : [];
if (!cleanIds.length) {
this.groupOpsPreviewMap = {};
return;
}
axios.post('/robot/api/groups/ops_preview', { group_ids: cleanIds }).then(response => {
if (!response.data.success) {
return;
}
const previewMap = (response.data.data && response.data.data.preview_map) || {};
this.groupOpsPreviewMap = previewMap;
this.groupsList = this.groupsList.map(item => ({
...item,
ops_preview: previewMap[item.wxid] || null
}));
}).catch(error => {
console.error('加载群运营速览失败:', error);
});
},
updateContacts() {
this.$message.info('正在更新通讯录...');
// 通讯录刷新已改成后台异步任务:
@@ -1927,6 +1976,31 @@
.entity-avatar--group { background: rgba(16,185,129,0.12); color: #10b981; }
.entity-title { font-size: 14px; font-weight: 600; color: #0f172a; }
.entity-subtitle { margin-top: 4px; font-size: 12px; color: #94a3b8; }
.group-preview-cell {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 0;
}
.group-preview-tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.group-preview-members {
font-size: 12px;
color: #475569;
line-height: 1.6;
}
.group-preview-summary {
font-size: 12px;
color: #64748b;
line-height: 1.7;
}
.group-preview-empty {
font-size: 12px;
color: #94a3b8;
}
.action-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pagination-container { margin-top: 20px; text-align: right; }
.group-insight-section { margin-top: 20px; }