auto-save 2026-04-13 18:59 (+1)
This commit is contained in:
185
web/lib/mock-data.ts
Normal file
185
web/lib/mock-data.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
export type MeetingStatus =
|
||||
| 'pending'
|
||||
| 'uploading'
|
||||
| 'transcribing'
|
||||
| 'summarizing'
|
||||
| 'done'
|
||||
| 'failed'
|
||||
|
||||
export type Meeting = {
|
||||
id: string
|
||||
title: string
|
||||
date: string // ISO
|
||||
duration: number // seconds
|
||||
participants?: string[]
|
||||
status: MeetingStatus
|
||||
progress?: number // 0-100
|
||||
chunksDone?: number
|
||||
chunksTotal?: number
|
||||
summary?: {
|
||||
keyPoints: string[]
|
||||
todos: { text: string; owner?: string; due?: string }[]
|
||||
decisions: string[]
|
||||
keywords: string[]
|
||||
preview: string
|
||||
}
|
||||
transcript?: Array<{
|
||||
time: number // seconds
|
||||
speaker: string
|
||||
text: string
|
||||
}>
|
||||
}
|
||||
|
||||
export const mockMeetings: Meeting[] = [
|
||||
{
|
||||
id: 'm1',
|
||||
title: '与客户对齐定价',
|
||||
date: '2026-04-13T14:30:00',
|
||||
duration: 4980,
|
||||
participants: ['张三', '李四', '客户王总'],
|
||||
status: 'transcribing',
|
||||
progress: 60,
|
||||
chunksDone: 3,
|
||||
chunksTotal: 5,
|
||||
},
|
||||
{
|
||||
id: 'm2',
|
||||
title: '团队周会',
|
||||
date: '2026-04-13T10:00:00',
|
||||
duration: 2700,
|
||||
participants: ['张三', '李四', '王五'],
|
||||
status: 'done',
|
||||
summary: {
|
||||
keyPoints: [
|
||||
'A 项目完成 80%,进入最后测试阶段',
|
||||
'B 项目本周进入功能测试',
|
||||
'下周聚焦 A 项目上线准备,需对齐运营',
|
||||
],
|
||||
todos: [
|
||||
{ text: '整理 A 项目上线 checklist', owner: '张三', due: '周五前' },
|
||||
{ text: '协调运营团队对接会', owner: '李四', due: '明天' },
|
||||
{ text: 'B 项目性能压测报告', owner: '王五' },
|
||||
],
|
||||
decisions: [
|
||||
'A 项目上线时间定为下周三',
|
||||
'B 项目延后一周,优先保质量',
|
||||
],
|
||||
keywords: ['周会', '进度', '上线', 'A项目', 'B项目'],
|
||||
preview:
|
||||
'本周关键进展:A 项目完成 80%,进入最后测试阶段;B 项目本周进入功能测试。下周聚焦 A 项目上线准备,需要协调运营团队对接...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'm3',
|
||||
title: '产品 Review',
|
||||
date: '2026-04-12T16:00:00',
|
||||
duration: 3120,
|
||||
participants: ['产品经理', '设计师', '工程团队'],
|
||||
status: 'done',
|
||||
summary: {
|
||||
keyPoints: [
|
||||
'确定 Q2 产品路线图三个重点方向',
|
||||
'移动端体验优化优先级最高',
|
||||
'AI 功能纳入 Q3 规划',
|
||||
],
|
||||
todos: [
|
||||
{ text: '出 Q2 PRD 初稿', owner: '产品经理', due: '下周一' },
|
||||
{ text: '设计 Mobile 重构方案', owner: '设计师' },
|
||||
],
|
||||
decisions: ['Q2 聚焦移动端', 'AI 功能推迟到 Q3'],
|
||||
keywords: ['产品', 'Q2', '路线图', '移动端', 'AI'],
|
||||
preview:
|
||||
'讨论 Q2 产品路线图,确定三个重点:1) 移动端体验优化作为最高优先级;2) 后台管理 UI 重构;3) AI 辅助功能纳入 Q3 规划...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'm4',
|
||||
title: '架构评审 · API 网关方案',
|
||||
date: '2026-04-11T14:00:00',
|
||||
duration: 5400,
|
||||
participants: ['技术负责人', '后端团队'],
|
||||
status: 'done',
|
||||
summary: {
|
||||
keyPoints: [
|
||||
'选型确定 Kong + 自研插件方案',
|
||||
'Rate limiting 复用 Redis 集群',
|
||||
'灰度发布走 Canary',
|
||||
],
|
||||
todos: [
|
||||
{ text: '写 Kong POC', owner: '小明', due: '下周五' },
|
||||
{ text: '梳理现有 API 清单', owner: '小红' },
|
||||
],
|
||||
decisions: ['不走 Envoy,Kong 生态更成熟', '灰度走 Canary 5%/25%/50%/100%'],
|
||||
keywords: ['架构', 'API网关', 'Kong', '灰度', 'Redis'],
|
||||
preview:
|
||||
'今天主要对齐 API 网关的选型方向,在 Kong 和 Envoy 之间做了对比。最终决定 Kong + 自研插件,主要考虑到 Kong 的生态更成熟,团队学习成本更低...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'm5',
|
||||
title: '用户访谈 · A 类客户',
|
||||
date: '2026-04-10T15:30:00',
|
||||
duration: 3600,
|
||||
status: 'failed',
|
||||
},
|
||||
]
|
||||
|
||||
export function getMeeting(id: string): Meeting | undefined {
|
||||
return mockMeetings.find((m) => m.id === id)
|
||||
}
|
||||
|
||||
export function formatDuration(seconds: number): string {
|
||||
const h = Math.floor(seconds / 3600)
|
||||
const m = Math.floor((seconds % 3600) / 60)
|
||||
const s = seconds % 60
|
||||
if (h > 0) return `${h}h ${m}min`
|
||||
return `${m}min`
|
||||
}
|
||||
|
||||
export function formatTime(seconds: number): string {
|
||||
const h = Math.floor(seconds / 3600)
|
||||
const m = Math.floor((seconds % 3600) / 60)
|
||||
const s = Math.floor(seconds % 60)
|
||||
if (h > 0) {
|
||||
return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
|
||||
}
|
||||
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export function groupByDate(meetings: Meeting[]): Record<string, Meeting[]> {
|
||||
const groups: Record<string, Meeting[]> = {}
|
||||
for (const m of meetings) {
|
||||
const day = m.date.slice(0, 10)
|
||||
if (!groups[day]) groups[day] = []
|
||||
groups[day].push(m)
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
export function dateLabel(day: string): string {
|
||||
const today = new Date()
|
||||
const todayStr = today.toISOString().slice(0, 10)
|
||||
const yesterday = new Date(today)
|
||||
yesterday.setDate(today.getDate() - 1)
|
||||
const yesterdayStr = yesterday.toISOString().slice(0, 10)
|
||||
|
||||
if (day === todayStr) return '今天 · ' + day
|
||||
if (day === yesterdayStr) return '昨天 · ' + day
|
||||
return day
|
||||
}
|
||||
|
||||
export const mockTranscript = [
|
||||
{ time: 0, speaker: '张三', text: '大家好,今天主要是对齐一下 Q2 的定价方案,pipeline 基本已经 ready 了。' },
|
||||
{ time: 15, speaker: '李四', text: 'OK, 我这边准备了三个档位的方案,分别是 Basic / Pro / Ultra,对应不同的客户规模。' },
|
||||
{ time: 35, speaker: '客户王总', text: '我们比较关心 Pro 档的 SLA 具体怎么定义,还有超出 quota 之后的处理方式。' },
|
||||
{ time: 58, speaker: '李四', text: 'Pro 档 SLA 我们承诺 99.9% 可用性,超出 quota 按标准价格 0.01 per request 计费。' },
|
||||
{ time: 90, speaker: '张三', text: '关于 SLA,我建议我们再明确一下 downtime 的定义,尤其是计划内维护是否算。' },
|
||||
{ time: 110, speaker: '客户王总', text: '同意,计划内维护应该提前通知,并且不计入 SLA。' },
|
||||
{ time: 130, speaker: '李四', text: '好的,这块我回去更新一下合同模板,会议纪要里也会明确写出来。' },
|
||||
{ time: 155, speaker: '张三', text: '另外 Pro 档的折扣,我们能给到什么力度?客户这边期望是 15%。' },
|
||||
{ time: 180, speaker: '客户王总', text: '15% 是我们的底线,毕竟首年采购量会比较大。' },
|
||||
{ time: 205, speaker: '李四', text: '10% 是我们目前政策能给到的上限,15% 需要走特批流程。' },
|
||||
{ time: 230, speaker: '张三', text: '那就走特批,客户关系比单次毛利重要。我今天去找 CEO 签字。' },
|
||||
{ time: 260, speaker: '客户王总', text: '感谢。那就这样,合同草稿我们希望周五之前能收到。' },
|
||||
{ time: 280, speaker: '李四', text: '没问题,周五前一定出。' },
|
||||
]
|
||||
6
web/lib/utils.ts
Normal file
6
web/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
Reference in New Issue
Block a user