feat: add topic summaries and growth profiles

This commit is contained in:
2026-07-31 15:34:03 +08:00
parent 884dc765ad
commit 3e60a6da42
22 changed files with 1040 additions and 5 deletions

View File

@@ -1571,6 +1571,38 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
<div><span>消息数</span><strong>{{ chatDetail.session.messageCount }}</strong></div>
</section>
<h3 class="detail-title">主题会话</h3>
<el-collapse v-if="chatDetail.topics?.length" class="topic-summary-collapse">
<el-collapse-item
v-for="topic in chatDetail.topics"
:key="topic.id"
:title="`#${topic.id} ${topic.title} / ${topic.status}`"
>
<section class="topic-summary-card">
<div class="topic-summary-meta">
<span>核心问题{{ topic.coreQuestion }}</span>
<span>消息数{{ topic.messageCount }}</span>
<span>Token{{ topic.tokenInput }}/{{ topic.tokenOutput }}</span>
<span>额度{{ topic.quotaDeducted ? '已计入' : '不计入' }}</span>
<span>开始{{ topic.startedAt }}</span>
<span>结束{{ topic.endedAt || '-' }}</span>
</div>
<template v-if="topic.summary">
<pre>{{ topic.summary.summary }}</pre>
<div class="topic-summary-fields">
<p v-if="topic.summary.mainEvents"><strong>主要事件</strong>{{ topic.summary.mainEvents }}</p>
<p v-if="topic.summary.emotions"><strong>情绪</strong>{{ topic.summary.emotions }}</p>
<p v-if="topic.summary.bodyFeelings"><strong>身体感受</strong>{{ topic.summary.bodyFeelings }}</p>
<p v-if="topic.summary.recommendedHomework"><strong>推荐功课</strong>{{ topic.summary.recommendedHomework }}</p>
<p v-if="topic.summary.nextObservation"><strong>下一步观察</strong>{{ topic.summary.nextObservation }}</p>
</div>
</template>
<el-empty v-else description="该主题尚未沉淀摘要" :image-size="60" />
</section>
</el-collapse-item>
</el-collapse>
<el-empty v-else description="该会话暂无主题记录" :image-size="64" />
<h3 class="detail-title">完整对话</h3>
<AdminPagination
class="chat-detail-pagination top"

View File

@@ -2042,6 +2042,64 @@ textarea {
font-size: 16px;
}
.topic-summary-collapse {
margin-bottom: 14px;
}
.topic-summary-card {
display: grid;
gap: 12px;
}
.topic-summary-meta {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
color: #667a73;
font-size: 12px;
}
.topic-summary-meta span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.topic-summary-card pre {
margin: 0;
padding: 12px;
border: 1px solid #dfe8e5;
border-radius: 10px;
background: #f8fbfa;
color: #34453f;
font: inherit;
font-size: 13px;
line-height: 1.75;
white-space: pre-wrap;
}
.topic-summary-fields {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.topic-summary-fields p {
margin: 0;
padding: 10px 12px;
border-radius: 10px;
background: #f6f8f7;
color: #53645e;
font-size: 13px;
line-height: 1.65;
}
.topic-summary-fields strong {
display: block;
margin-bottom: 4px;
color: #203b32;
}
.conversation-list {
display: grid;
gap: 12px;

View File

@@ -396,6 +396,42 @@ export interface ChatDetail {
messages: ChatMessageRecord[];
messagesPage?: PageResult<ChatMessageRecord>;
aiLogs: AiLogRecord[];
topics?: TopicSessionRecord[];
}
export interface TopicSummaryRecord {
id: number;
topicSessionId: number;
userId: number;
summary: string;
mainEvents?: string | null;
emotions?: string | null;
bodyFeelings?: string | null;
beliefs?: string | null;
recommendedHomework?: string | null;
insights?: string | null;
nextObservation?: string | null;
modelName?: string | null;
status: string;
errorMessage?: string | null;
generatedAt: string;
}
export interface TopicSessionRecord {
id: number;
userId: number;
chatSessionId: number;
title: string;
coreQuestion: string;
status: string;
messageCount: number;
tokenInput: number;
tokenOutput: number;
quotaDeducted: boolean;
recommendedHomework?: string | null;
startedAt: string;
endedAt?: string | null;
summary?: TopicSummaryRecord | null;
}
export interface QuestionInsightSummary {