功能 文件 说明 幻灯片显隐 routes.py, PptResult.vue, ppt-api.ts 每页可点击隐藏/恢复,隐藏页在缩略图中半透明显示,页码标注隐藏数量 DeckContract 快照 renderer.py, celery_tasks.py, ppt_session.py 生成时保存完整 deck JSON 到文件系统,供版本化回溯 版本化生成 celery_tasks.py, task_service.py, routes.py POST /preview/:id/regenerate → 递增版本号 → 用 deck 重新渲染 → 追加到版本历史,不覆盖旧版 版本历史 UI PptResult.vue 右栏显示版本列表(版本号/页数/时间),当前版本高亮标记 数据库迁移 migrate_025.py 新增 deck_contract_path、versions_json 字段 阶段 4:UI 重构 功能 文件 说明 保险绿主题 PptPage.vue, PptGenerate.vue, PptResult.vue, PptSlideCanvas.vue 主色从 #2563eb 蓝改为 #3B7A57 保险绿,背景暖灰 #f0f7f3 生成决策展示 PptGenerate.vue 新增"系统决策"区域,展示检测场景、选用模板、计划书数量、险种类型、保司 骨架屏加载 PptResult.vue preview_status=none/generating 时显示骨架屏 + 加载动画,不再显示静态 fallback 新增后端接口(本轮) 方法 路径 功能 POST /ppt/preview/:id/regenerate 基于编辑内容生成新版本 PUT /ppt/preview/:id/slide/:index 增加 hidden 字段支持 新增 Celery 任务 任务名 说明 insurance.regenerate_ppt 读取 DeckContract → 应用编辑 → 重新渲染 → 保存新版本
221 lines
5.3 KiB
TypeScript
221 lines
5.3 KiB
TypeScript
/**
|
|
* PPT 生成模块 API 封装
|
|
*/
|
|
import api from './api'
|
|
|
|
export interface PptSession {
|
|
id: string
|
|
user_id: string
|
|
status: string
|
|
files: Array<{ path: string; name: string; type: string }>
|
|
extractions: Array<{
|
|
pdfName: string
|
|
planType: string
|
|
status: string
|
|
productName: string
|
|
data: any
|
|
error?: string
|
|
yearCount: number
|
|
}>
|
|
chatHistory: Array<{ role: string; content: string }>
|
|
ppt_path?: string
|
|
slide_count?: number
|
|
preview_status?: 'none' | 'generating' | 'ready' | 'failed'
|
|
slides_json_path?: string
|
|
quality_report?: QualityReport
|
|
created_at: string
|
|
}
|
|
|
|
export interface SlideShape {
|
|
id: string
|
|
type: 'textbox' | 'rect' | 'image' | 'table' | 'group'
|
|
x: number
|
|
y: number
|
|
w: number
|
|
h: number
|
|
fill?: string
|
|
lineColor?: string
|
|
lineWidth?: number
|
|
paragraphs?: SlideParagraph[]
|
|
rows?: Array<Array<{ text: string; bold: boolean; fontSize: number }>>
|
|
children?: SlideShape[]
|
|
}
|
|
|
|
export interface SlideParagraph {
|
|
text: string
|
|
fontSize: number
|
|
bold: boolean
|
|
color: string
|
|
align: 'left' | 'center' | 'right' | 'justify'
|
|
}
|
|
|
|
export interface SlideData {
|
|
index: number
|
|
background: string
|
|
shapes: SlideShape[]
|
|
hidden?: boolean
|
|
}
|
|
|
|
export interface SlidesJson {
|
|
width: number
|
|
height: number
|
|
slideCount: number
|
|
slides: SlideData[]
|
|
}
|
|
|
|
export interface QualityCheckItem {
|
|
key: string
|
|
status: 'pass' | 'fail' | 'warn'
|
|
message: string
|
|
page: number | null
|
|
}
|
|
|
|
export interface QualityManualItem {
|
|
key: string
|
|
confirmed: boolean
|
|
message: string
|
|
}
|
|
|
|
export interface QualityReport {
|
|
auto: QualityCheckItem[]
|
|
manual: QualityManualItem[]
|
|
summary: { pass: number; fail: number; warn: number; manualPending: number }
|
|
}
|
|
|
|
export interface ExtractionResult {
|
|
sessionId: string
|
|
status: string
|
|
extractions: Array<{
|
|
pdfName: string
|
|
planType: string
|
|
status: string
|
|
productName: string
|
|
yearCount: number
|
|
error?: string
|
|
}>
|
|
message: string
|
|
}
|
|
|
|
export interface GenerateResult {
|
|
sessionId: string
|
|
status: string
|
|
downloadUrl?: string
|
|
slideCount: number
|
|
}
|
|
|
|
export const pptApi = {
|
|
/** 上传 PDF 文件 */
|
|
upload(formData: FormData) {
|
|
return api.post('/ppt/upload', formData, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
})
|
|
},
|
|
|
|
/** 触发 AI 解析 */
|
|
parse(sessionId: string) {
|
|
return api.post(`/ppt/parse/${sessionId}`)
|
|
},
|
|
|
|
/** 获取 AI 解析进度 */
|
|
getParseStatus(sessionId: string) {
|
|
return api.get(`/ppt/parse/${sessionId}/status`)
|
|
},
|
|
|
|
/** 获取会话状态 */
|
|
getSession(sessionId: string) {
|
|
return api.get(`/ppt/session/${sessionId}`)
|
|
},
|
|
|
|
/** AI 对话 */
|
|
chat(sessionId: string, message: string) {
|
|
return api.post(`/ppt/chat/${sessionId}`, { message })
|
|
},
|
|
|
|
/** 生成 PPT */
|
|
generate(sessionId: string, params: {
|
|
theme?: string
|
|
templateId?: string
|
|
companyId?: string
|
|
style?: string
|
|
useMaskedData?: boolean
|
|
}) {
|
|
return api.post(`/ppt/generate/${sessionId}`, params)
|
|
},
|
|
|
|
/** 验证提取数据 */
|
|
validate(sessionId: string) {
|
|
return api.get(`/ppt/validate/${sessionId}`)
|
|
},
|
|
|
|
/** 保存用户修改后的提取数据 */
|
|
updateExtractions(sessionId: string, extractions: any[]) {
|
|
return api.put(`/ppt/session/${sessionId}/extractions`, { extractions })
|
|
},
|
|
|
|
/** 获取渲染选项 */
|
|
getRenderOptions() {
|
|
return api.get('/ppt/render-options')
|
|
},
|
|
|
|
/** 匹配公司知识库 */
|
|
matchCompany(params: { productName?: string; companyHint?: string; companyId?: string }) {
|
|
return api.post('/ppt/company-kb/match', params)
|
|
},
|
|
|
|
/** 获取下载链接 */
|
|
getDownloadUrl(sessionId: string) {
|
|
return `/insurance/ppt/download/${sessionId}`
|
|
},
|
|
|
|
/** 下载 PPT 文件(带认证) */
|
|
async downloadPpt(sessionId: string): Promise<Blob> {
|
|
const response = await api.get(`/ppt/download/${sessionId}`, {
|
|
responseType: 'blob',
|
|
})
|
|
return response.data
|
|
},
|
|
|
|
/** 获取历史记录列表 */
|
|
getHistory(params?: { page?: number; page_size?: number; company_id?: string; action_type?: string }) {
|
|
return api.get('/ppt/history', { params })
|
|
},
|
|
|
|
/** 获取历史详情 */
|
|
getHistoryDetail(id: number) {
|
|
return api.get(`/ppt/history/${id}`)
|
|
},
|
|
|
|
/** 重新下载历史文件 */
|
|
async reDownloadHistory(id: number): Promise<Blob> {
|
|
const response = await api.get(`/ppt/history/${id}/re-download`, {
|
|
responseType: 'blob',
|
|
})
|
|
return response.data
|
|
},
|
|
|
|
/** 获取幻灯片预览数据(结构化 JSON + 质量报告) */
|
|
getPreview(sessionId: string) {
|
|
return api.get(`/ppt/preview/${sessionId}`)
|
|
},
|
|
|
|
/** 更新指定页的编辑内容 */
|
|
updateSlideEdit(sessionId: string, slideIndex: number, shapes: any[]) {
|
|
return api.put(`/ppt/preview/${sessionId}/slide/${slideIndex}`, { shapes })
|
|
},
|
|
|
|
/** 更新幻灯片显隐状态 */
|
|
updateSlideHidden(sessionId: string, slideIndex: number, hidden: boolean) {
|
|
return api.put(`/ppt/preview/${sessionId}/slide/${slideIndex}`, { hidden })
|
|
},
|
|
|
|
/** 更新人工质量确认项 */
|
|
updateQualityConfirm(sessionId: string, key: string, confirmed: boolean) {
|
|
return api.put(`/ppt/preview/${sessionId}/quality-confirm`, { key, confirmed })
|
|
},
|
|
|
|
/** 基于当前编辑内容重新生成新版本 */
|
|
regenerateVersion(sessionId: string) {
|
|
return api.post(`/ppt/preview/${sessionId}/regenerate`)
|
|
},
|
|
}
|