增强群运营分析2.0首版展示能力
变更项: 1. 在现有群详情接口中追加群画像摘要、成员分层、动作建议和最近群总结数据,保留原有健康度、趋势、排行与运营建议结构。 2. 为后台服务补充 message_summary 数据访问对象,复用现有群总结数据作为群运营分析输入。 3. 在通讯录管理的群详情面板中新增群画像摘要、成员分层和可执行动作建议卡片,保持旧页面内容不删除,仅做加法增强。
This commit is contained in:
@@ -262,6 +262,140 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!--
|
||||
群运营分析 2.0 先走“加法增强”:
|
||||
1. 老的健康度、趋势、排行继续保留;
|
||||
2. 新增群画像摘要,用更接近运营语言的方式解释群状态;
|
||||
3. 这样即使后面要调整 2.0 结构,也不会影响旧洞察面板。
|
||||
-->
|
||||
<div class="detail-section">
|
||||
<div class="section-title">
|
||||
<h3>群画像摘要</h3>
|
||||
</div>
|
||||
<el-row :gutter="16" class="detail-panels">
|
||||
<el-col :span="14">
|
||||
<el-card class="detail-card detail-card--profile" shadow="never">
|
||||
<div slot="header" class="detail-card-header">
|
||||
<span>群定位与讨论风格</span>
|
||||
<span class="detail-card-sub">2.0 增强摘要</span>
|
||||
</div>
|
||||
<div class="ops-profile-title">{% raw %}{{ groupInsight.ops_profile.group_identity || '综合交流型群' }}{% endraw %}</div>
|
||||
<div class="feature-chip-list">
|
||||
<el-tag
|
||||
v-for="tag in (groupInsight.ops_profile.profile_tags || [])"
|
||||
:key="tag"
|
||||
size="small"
|
||||
type="info"
|
||||
effect="plain">
|
||||
{% raw %}{{ tag }}{% endraw %}
|
||||
</el-tag>
|
||||
<span v-if="!(groupInsight.ops_profile.profile_tags || []).length" class="empty-inline">暂无群画像标签</span>
|
||||
</div>
|
||||
<div class="ops-profile-summary">{% raw %}{{ groupInsight.ops_profile.summary_text || '暂无群画像摘要' }}{% endraw %}</div>
|
||||
<div class="ops-topic-block">
|
||||
<div class="ops-subtitle">高频主题</div>
|
||||
<div class="feature-chip-list">
|
||||
<el-tag
|
||||
v-for="topic in (groupInsight.ops_profile.focus_topics || [])"
|
||||
:key="topic"
|
||||
size="small"
|
||||
type="success"
|
||||
effect="plain">
|
||||
{% raw %}{{ topic }}{% endraw %}
|
||||
</el-tag>
|
||||
<span v-if="!(groupInsight.ops_profile.focus_topics || []).length" class="empty-inline">暂无高频主题</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ops-topic-block" v-if="(groupInsight.ops_profile.unresolved_points || []).length">
|
||||
<div class="ops-subtitle">待跟进问题</div>
|
||||
<div class="ops-bullet-list">
|
||||
<div v-for="item in groupInsight.ops_profile.unresolved_points" :key="item" class="ops-bullet-item">
|
||||
{% raw %}{{ item }}{% endraw %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-card class="detail-card" shadow="never">
|
||||
<div slot="header" class="detail-card-header">
|
||||
<span>最近群总结</span>
|
||||
<span class="detail-card-sub">复用现有 message_summary</span>
|
||||
</div>
|
||||
<div class="ops-summary-timeline" v-if="(groupInsight.recent_summaries || []).length">
|
||||
<div v-for="item in groupInsight.recent_summaries" :key="`${item.summary_type}-${item.period_key}`" class="ops-summary-item">
|
||||
<div class="ops-summary-head">
|
||||
<span class="ops-summary-period">{% raw %}{{ item.period_key || '-' }}{% endraw %}</span>
|
||||
<span class="ops-summary-meta">{% raw %}{{ item.source_message_count || 0 }}{% endraw %} 条消息</span>
|
||||
</div>
|
||||
<div class="ops-summary-excerpt">{% raw %}{{ item.summary_excerpt || '暂无摘要内容' }}{% endraw %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-inline">当前还没有可展示的群总结记录</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
成员分层主要服务“下一步看谁”:
|
||||
1. 核心成员强调谁在带讨论;
|
||||
2. 高价值成员强调谁值得重点关注;
|
||||
3. 待激活成员强调谁最适合做轻量召回。
|
||||
-->
|
||||
<div class="detail-section">
|
||||
<div class="section-title">
|
||||
<h3>成员分层</h3>
|
||||
</div>
|
||||
<el-row :gutter="16" class="detail-panels detail-panels--triple">
|
||||
<el-col :span="8">
|
||||
<el-card class="detail-card" shadow="never">
|
||||
<div slot="header" class="detail-card-header">
|
||||
<span>核心成员</span>
|
||||
<span class="detail-card-sub">近30天发言核心</span>
|
||||
</div>
|
||||
<div class="ops-member-list" v-if="(groupInsight.ops_members.core_members || []).length">
|
||||
<div v-for="item in groupInsight.ops_members.core_members" :key="item.wxid" class="ops-member-item">
|
||||
<div class="ops-member-name">{% raw %}{{ item.display_name }}{% endraw %}</div>
|
||||
<div class="ops-member-meta">消息数 {% raw %}{{ item.message_count }}{% endraw %} · {% raw %}{{ item.activity_level || '未分层' }}{% endraw %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-inline">暂无核心成员数据</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card class="detail-card" shadow="never">
|
||||
<div slot="header" class="detail-card-header">
|
||||
<span>高价值成员</span>
|
||||
<span class="detail-card-sub">最近一期身价快照</span>
|
||||
</div>
|
||||
<div class="ops-member-list" v-if="(groupInsight.ops_members.value_rank_members || []).length">
|
||||
<div v-for="item in groupInsight.ops_members.value_rank_members" :key="item.wxid" class="ops-member-item">
|
||||
<div class="ops-member-name">{% raw %}{{ item.display_name }}{% endraw %}</div>
|
||||
<div class="ops-member-meta">#{% raw %}{{ item.rank_no }}{% endraw %} · {% raw %}{{ item.title || '成员' }}{% endraw %} · 分值 {% raw %}{{ item.score }}{% endraw %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-inline">暂无高价值成员快照</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card class="detail-card" shadow="never">
|
||||
<div slot="header" class="detail-card-header">
|
||||
<span>待激活成员</span>
|
||||
<span class="detail-card-sub">近7~30天边缘活跃</span>
|
||||
</div>
|
||||
<div class="ops-member-list" v-if="(groupInsight.ops_members.activation_candidates || []).length">
|
||||
<div v-for="item in groupInsight.ops_members.activation_candidates" :key="item.wxid" class="ops-member-item">
|
||||
<div class="ops-member-name">{% raw %}{{ item.display_name }}{% endraw %}</div>
|
||||
<div class="ops-member-meta">距今 {% raw %}{{ item.inactivity_days }}{% endraw %} 天未发言</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-inline">暂无待激活成员</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<div class="section-title">
|
||||
<h3>运营建议</h3>
|
||||
@@ -280,6 +414,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
旧版运营建议更偏诊断提示;
|
||||
新增的动作建议更偏“下一步怎么做”。
|
||||
两层同时保留,便于后续比较哪种信息对你更有用。
|
||||
-->
|
||||
<div class="detail-section">
|
||||
<div class="section-title">
|
||||
<h3>可执行动作建议</h3>
|
||||
</div>
|
||||
<el-row :gutter="16" class="detail-panels detail-panels--double">
|
||||
<el-col :span="12" v-for="(item, index) in (groupInsight.ops_actions || [])" :key="`${item.type}-${index}`">
|
||||
<el-card class="detail-card action-card" shadow="never">
|
||||
<div class="action-card-type">{% raw %}{{ item.type || 'action' }}{% endraw %}</div>
|
||||
<div class="action-card-title">{% raw %}{{ item.title }}{% endraw %}</div>
|
||||
<div class="action-card-summary">{% raw %}{{ item.summary }}{% endraw %}</div>
|
||||
<div class="action-card-detail">{% raw %}{{ item.detail }}{% endraw %}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="16" class="detail-panels">
|
||||
<el-col :span="12">
|
||||
<el-card class="detail-card" shadow="never">
|
||||
@@ -1810,11 +1965,87 @@
|
||||
display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;
|
||||
}
|
||||
.detail-panels .el-col { margin-bottom: 16px; }
|
||||
.detail-panels--triple .el-col,
|
||||
.detail-panels--double .el-col { margin-bottom: 16px; }
|
||||
.detail-card { border-radius: 18px; }
|
||||
.detail-card--profile {
|
||||
background: linear-gradient(180deg, rgba(14,165,233,0.08), rgba(255,255,255,0.98));
|
||||
}
|
||||
.detail-card-header {
|
||||
display: flex; align-items: center; justify-content: space-between; font-weight: 600; color: #0f172a;
|
||||
}
|
||||
.detail-card-sub { font-size: 12px; color: #94a3b8; font-weight: 500; }
|
||||
.ops-profile-title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.ops-profile-summary {
|
||||
margin-top: 14px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 14px;
|
||||
background: rgba(255,255,255,0.78);
|
||||
border: 1px solid rgba(148,163,184,0.12);
|
||||
color: #334155;
|
||||
line-height: 1.8;
|
||||
font-size: 13px;
|
||||
}
|
||||
.ops-topic-block {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.ops-subtitle {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #475569;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.ops-bullet-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.ops-bullet-item {
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
background: rgba(248,250,252,0.9);
|
||||
color: #475569;
|
||||
border: 1px solid rgba(148,163,184,0.12);
|
||||
line-height: 1.6;
|
||||
font-size: 12px;
|
||||
}
|
||||
.ops-summary-timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.ops-summary-item {
|
||||
padding: 14px 14px 12px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(180deg, rgba(248,250,252,0.9), rgba(255,255,255,0.98));
|
||||
border: 1px solid rgba(148,163,184,0.12);
|
||||
}
|
||||
.ops-summary-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.ops-summary-period {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
.ops-summary-meta {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
.ops-summary-excerpt {
|
||||
font-size: 12px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.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; }
|
||||
@@ -1822,6 +2053,66 @@
|
||||
.detail-inline-note { margin-top: 12px; line-height: 1.6; }
|
||||
.suggestion-list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.suggestion-item { border-radius: 14px; }
|
||||
.ops-member-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.ops-member-item {
|
||||
padding: 12px 14px;
|
||||
border-radius: 14px;
|
||||
background: rgba(248,250,252,0.9);
|
||||
border: 1px solid rgba(148,163,184,0.12);
|
||||
}
|
||||
.ops-member-name {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.ops-member-meta {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.action-card {
|
||||
min-height: 180px;
|
||||
background: linear-gradient(180deg, rgba(249,115,22,0.06), rgba(255,255,255,0.98));
|
||||
}
|
||||
.action-card-type {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 24px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(249,115,22,0.12);
|
||||
color: #c2410c;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .04em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.action-card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.action-card-summary {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.action-card-detail {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.peak-hour-list { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
|
||||
.peak-hour-item {
|
||||
min-width: 132px; padding: 12px 14px; border-radius: 14px;
|
||||
@@ -1946,6 +2237,8 @@
|
||||
.page-hero-actions, .detail-tags { justify-content: flex-start; }
|
||||
.hero-search, .group-search { width: 100%; }
|
||||
.diagnosis-grid { grid-template-columns: 1fr; }
|
||||
.detail-panels--triple .el-col,
|
||||
.detail-panels--double .el-col { width: 100%; }
|
||||
.chat-header-card { flex-direction: column; align-items: flex-start; }
|
||||
.chat-header-actions { justify-content: flex-start; }
|
||||
.message-content { max-width: 92%; }
|
||||
|
||||
Reference in New Issue
Block a user