diff --git a/frontend/sidebar/src/components/SummaryCard.tsx b/frontend/sidebar/src/components/SummaryCard.tsx index c1c7c32..8474838 100644 --- a/frontend/sidebar/src/components/SummaryCard.tsx +++ b/frontend/sidebar/src/components/SummaryCard.tsx @@ -1,5 +1,6 @@ /** * 每日总结卡片渲染组件(summary / summary-search 页面共用) + * 样式:对话气泡(学员咨询左 / 老师解答右)+ 跟进建议卡片 + 灰色标签 */ export interface SummaryItem { @@ -31,46 +32,89 @@ export function SummaryCard({ item }: { item: SummaryItem }) { const parsed = parseSummary(item.summary) const hasStructure = parsed.sections.length > 0 || parsed.tags.length > 0 + // 按区块类型归类:学员咨询(左气泡) / 老师解答(右气泡) / 跟进建议(卡片) / 其它(通用卡片) + const customerItems: string[] = [] + const teacherItems: string[] = [] + const todoItems: string[] = [] + let hasTodoSection = false + const otherSections: SummarySection[] = [] + + for (const section of parsed.sections) { + if (section.title.includes('核心诉求')) { + customerItems.push(...section.items) + } else if (section.title.includes('处理结果')) { + teacherItems.push(...section.items) + } else if (section.title.includes('待办') || section.title.includes('后续')) { + hasTodoSection = true + todoItems.push(...section.items.filter(t => !isNoneText(t))) + } else { + otherSections.push(section) + } + } + return (
- {/* 头部 */} + {/* 元信息行:日期 · 顾问 | 咨询跟进 */}
-
- - - {item.msgTime || formatDate(item.createdAt)} - -
-
- - - {item.staffName || item.staffId || '未知老师'} +
+ {formatCnDate(item)} + · + + 顾问 {item.staffName || item.staffId || '未知老师'}
+ 咨询跟进
{hasStructure ? ( <> - {parsed.sections.map((section, idx) => ( - + {/* 对话式总结:学员咨询左气泡,老师解答右气泡(同侧多条合并为一个气泡并编号) */} + {(customerItems.length > 0 || teacherItems.length > 0) && ( +
+ {customerItems.length > 0 && } + {teacherItems.length > 0 && } +
+ )} + + {/* 跟进建议卡片 */} + {hasTodoSection && } + + {/* 其它区块通用展示 */} + {otherSections.map((section, idx) => ( + ))} - {parsed.tags.length > 0 && } + + {/* 关键标签 */} + {parsed.tags.length > 0 && } ) : ( -
+
{item.summary || item.messageContext || '无内容'}
)} @@ -78,45 +122,164 @@ export function SummaryCard({ item }: { item: SummaryItem }) { ) } -function SectionBlock({ section }: { section: SummarySection }) { - const config = getSectionConfig(section.title) - const showTitle = displaySectionTitle(section.title) - +function BubbleRow({ side, items }: { side: 'left' | 'right'; items: string[] }) { + const isLeft = side === 'left' + // 多条消息合并为一个气泡,前面加 1. 2. 3. 编号 + const text = items.length > 1 + ? items.map((t, i) => `${i + 1}. ${t}`).join('\n') + : items[0] return ( -
+
+ {isLeft ? : }
- {config.icon} - {showTitle} + {text}
-
- {section.items.map((text, idx) => ( -
-
- {section.title.includes('核心诉求') ? ( - - ) : section.title.includes('处理结果') ? ( - - ) : section.title.includes('待办') ? ( - - ) : ( - - )} +
+ ) +} + +function StudentAvatar() { + return ( +
+ + + + +
+ ) +} + +function TeacherAvatar() { + return ( +
+ + + + + + +
+ ) +} + +function TodoCard({ items }: { items: string[] }) { + return ( +
+
+
+ + + +
+ 跟进建议 + + {items.length > 0 ? `${items.length} 项待办` : '暂无待办'} + +
+ {items.length > 0 ? ( +
+ {items.map((text, idx) => ( +
+
+ {idx + 1} +
+
+ {text} +
+ ))} +
+ ) : ( +
暂无待办事项
+ )} +
+ ) +} + +function GenericSection({ section }: { section: SummarySection }) { + return ( +
+
{section.title}
+
+ {section.items.map((text, idx) => ( +
+ width: 6, + height: 6, + borderRadius: '50%', + background: '#1677ff', + marginTop: 7, + flexShrink: 0 + }} /> +
{text}
@@ -126,148 +289,26 @@ function SectionBlock({ section }: { section: SummarySection }) { ) } -function TagList({ tags }: { tags: string[] }) { +function TagRow({ tags }: { tags: string[] }) { return ( -
-
- 🏷️ - 关键标签 -
-
- {tags.map((tag, idx) => ( - - #{tag} - - ))} -
+
+ {tags.map((tag, idx) => ( + + {tag} + + ))}
) } -function getSectionConfig(title: string) { - if (title.includes('核心诉求')) { - return { icon: '📝', titleColor: '#1677ff' } - } - if (title.includes('处理结果')) { - return { icon: '✅', titleColor: '#52c41a' } - } - if (title.includes('待办') || title.includes('后续')) { - return { icon: '⏰', titleColor: '#fa8c16' } - } - return { icon: '•', titleColor: '#666' } -} - -function displaySectionTitle(title: string) { - if (title.includes('核心诉求')) return '学员咨询' - if (title.includes('处理结果')) return '老师解答' - if (title.includes('待办')) return '跟进建议' - return title -} - -function NumberBadge({ n }: { n: number }) { - return ( -
- {n} -
- ) -} - -function GreenCheck() { - return ( -
- ✓ -
- ) -} - -function OrangeClock() { - return ( -
- 🕐 -
- ) -} - -function Dot({ color }: { color: string }) { - return ( -
- ) -} - -function CalendarIcon() { - return ( - - - - - - - ) -} - -function UserIcon() { - return ( - - - - - ) +function isNoneText(t: string) { + return /^(无|暂无|没有|无。|暂无。|没有。|无建议|暂不需要)$/.test(t.trim()) } function parseSummary(text?: string): ParsedSummary { @@ -367,8 +408,15 @@ function cleanText(s: string): string { return s.replace(/\*\*/g, '').trim() } -function formatDate(timestamp?: number) { - if (!timestamp) return '-' - const date = new Date(timestamp) - return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` +function formatCnDate(item: SummaryItem): string { + if (item.msgTime) { + const m = item.msgTime.match(/(\d{4})[-\/年](\d{1,2})[-\/月](\d{1,2})/) + if (m) return `${parseInt(m[2], 10)}月${parseInt(m[3], 10)}日` + return item.msgTime + } + if (item.createdAt) { + const d = new Date(item.createdAt) + return `${d.getMonth() + 1}月${d.getDate()}日` + } + return '-' }