新增: 批注/备注/对齐分布/形状扩充/video 元素——编辑器能力增强

This commit is contained in:
lxy
2026-08-25 12:30:39 +08:00
parent af5211d46d
commit 5d3046b653
14 changed files with 1984 additions and 55 deletions
+12 -7
View File
@@ -13,7 +13,7 @@ import { normSegments } from './richtext'
import { isTauri, aiProxy, aiProxyStream } from './bridge'
const SEP = '%%PPT_JSON%%' // 对话模式中,自然语言回复与结构化操作的分隔标记
const VALID_TYPES = ['title', 'text', 'list', 'stat', 'quote', 'image', 'shape', 'chart', 'card', 'table', 'code', 'formula'] as const
const VALID_TYPES = ['title', 'text', 'list', 'stat', 'quote', 'image', 'video', 'shape', 'chart', 'card', 'table', 'code', 'formula'] as const
/* 智谱/通用错误码 → 可操作提示 */
const ERROR_HINTS: Record<string, string> = {
@@ -40,12 +40,12 @@ const SYS_BASE =
'幻灯片模型:\n' +
'{ "slides": [ { "background": "bg|panel|primary|accent|g-primary|g-deep|g-soft", "elements": [ 元素, ... ] } ] }\n' +
'背景:bg/panel=浅底;primary/accent=纯色深底;g-primary=主→强调渐变(深)g-deep=深色渐变;g-soft=浅色渐变。\n\n' +
'元素类型 typetitle 标题 | text 正文 | list 列表 | stat 数据 | quote 金句 | image 图片 | shape 形状 | chart 图表 | card 卡片 | table 表格 | code 代码 | formula 公式\n' +
'元素类型 typetitle 标题 | text 正文 | list 列表 | stat 数据 | quote 金句 | image 图片 | video 视频 | shape 形状 | chart 图表 | card 卡片 | table 表格 | code 代码 | formula 公式\n' +
'元素:{ "type":..., "x":数字,"y":数字,"w":数字,"h":数字 (0-100), "content":字符串, "style":{...} }\n' +
' - title/text/list/quotecontent 为文字,list 用 \\n 分多行\n' +
' - statcontent 为大数字(如 "65%")style.label 为说明\n' +
' - cardcontent 第一行=标题、其余行=正文;style.accent=顶部色条键,style.icon=emoji 图标\n' +
' - shapestyle.shapeType=rect|circle|trianglestyle.fill=颜色键,style.gradient=true 渐变,style.opacity=0~1\n' +
' - shapestyle.shapeType=rect|circle|ellipse|triangle|diamond|pentagon|hexagon|star|arrow|chevron|bubblestyle.fill=颜色键,style.gradient=true 渐变,style.opacity=0~1\n' +
' - chartcontent 为 JSON,两种格式:\n' +
' 单系列:[{"label":"","value":数字}, ...]\n' +
' 多系列:{"series":["Q1","Q2"], "items":[{"label":"华东","values":[120,150]}, ...]}\n' +
@@ -56,7 +56,8 @@ const SYS_BASE =
' - tablecontent 为 Markdown 管道表格字符串(首行表头,用 | 分列,换行分行),style.header=true 首行加粗\n' +
' - codecontent 为代码文本(保留符原样,不要转义),style.lang=语言如 js/python(可选)\n' +
' - formulacontent 为 LaTeX 公式字符串(不含 $$ 分隔符),如 "E = mc^2"、"\\sum_{i=1}^n x_i"\n' +
' - imagecontent 留空\n\n' +
' - imagecontent 留空\n' +
' - videocontent 填视频 URL\n\n' +
'可选 segments 字段(结构化富文本,同一行内不同片段可有不同样式):\n' +
' segments: [[ {"text":"华东 "}, {"text":"增长 23%","bold":true,"color":"accent"} ], ...]\n' +
' 每个 segment 支持:bold/italic/underline/strike/color(主题键或#hex)/highlight(黄底)/code/sup/sub/fontSize/link\n' +
@@ -106,11 +107,12 @@ function deckContext(currentIdx: number, selectedEl?: SlideElement | null): stri
const deck: Deck = store.getDeck()
/** 图片/超长 content 脱敏:base64 会撑爆上下文,替换为占位说明 */
const sanitizeEl = (el: SlideElement): SlideElement => {
if (el.type === 'image') {
if (el.type === 'image' || el.type === 'video') {
const src = el.content || ''
const label = el.type === 'video' ? '视频' : '图片'
const desc = src.startsWith('data:')
? `[图片 base64 ${Math.round(src.length / 1024)}KB]`
: (src ? `[图片URL: ${src.slice(0, 80)}${src.length > 80 ? '…' : ''}]` : '[空图片]')
? `[${label} base64 ${Math.round(src.length / 1024)}KB]`
: (src ? `[${label}URL: ${src.slice(0, 80)}${src.length > 80 ? '…' : ''}]` : `[空${label}]`)
return { ...el, content: desc }
}
if (el.content && el.content.length > 2000) {
@@ -415,6 +417,9 @@ function normStyle(st: any): ElementStyle {
if (out.grid != null) out.grid = !!out.grid
if (out.header != null) out.header = !!out.header
if (out.inline != null) out.inline = !!out.inline
if (out.autoplay != null) out.autoplay = !!out.autoplay
if (out.loop != null) out.loop = !!out.loop
if (out.muted != null) out.muted = !!out.muted
if (typeof out.lang === 'string' && out.lang.length > 16) out.lang = out.lang.slice(0, 16)
;['color', 'fill', 'accent', 'labelColor'].forEach(k => {
if (validColor(out[k]) === undefined && out[k] != null) delete out[k]