新增: 批注/备注/对齐分布/形状扩充/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
+26 -3
View File
@@ -9,6 +9,7 @@ import {
scanFiles, readEntries,
aiAnalyzeDocument,
fileToImageElement, imagesToSlideElements,
fileToVideoElement,
ACCEPT_ATTR,
type FileEntry, type ImportReport,
describeReport
@@ -31,18 +32,21 @@ const analyzeDone = ref(false) // AI 分析完成
const analyzeProgress = ref('') // AI 分析进度文案
const analyzeError = ref('') // AI 分析错误
const showImages = ref(true)
const showVideos = ref(true)
const showDocs = ref(true)
/* ---------- 过滤后的文件 ---------- */
const filteredEntries = computed(() => {
return entries.value.filter(e => {
if (e.kind === 'image' && !showImages.value) return false
if (e.kind === 'video' && !showVideos.value) return false
if (e.kind === 'document' && !showDocs.value) return false
return true
})
})
const imageEntries = computed(() => filteredEntries.value.filter(e => e.kind === 'image'))
const videoEntries = computed(() => filteredEntries.value.filter(e => e.kind === 'video'))
const docEntries = computed(() => filteredEntries.value.filter(e => e.kind === 'document'))
const unsupportedCount = computed(() => entries.value.filter(e => e.kind === 'unsupported').length)
@@ -115,7 +119,7 @@ async function handleFiles(fl: FileList | null) {
const scanned = await scanFiles(fl)
entries.value = scanned
// 读取文件原始内容
if (scanned.some(e => e.kind === 'image' || e.kind === 'document')) {
if (scanned.some(e => e.kind === 'image' || e.kind === 'video' || e.kind === 'document')) {
await readEntries(scanned)
}
loaded.value = true
@@ -165,9 +169,10 @@ async function runAiAnalysis() {
/* ---------- 执行导入 ---------- */
function doImport() {
const images = imageEntries.value.filter(e => e.data)
const videos = videoEntries.value.filter(e => e.data)
const docs = docEntries.value.filter(e => e.slides && e.slides.length > 0)
if (images.length === 0 && docs.length === 0) {
if (images.length === 0 && videos.length === 0 && docs.length === 0) {
// 如果有文档但还没 AI 分析,先分析
if (docEntries.value.filter(d => d.data && !d.slides).length > 0) {
void runAiAnalysis() // fire-and-forget:分析完成后 UI 自动更新按钮
@@ -209,6 +214,21 @@ function doImport() {
}
}
// 1.5 视频 → 当前幻灯片(每个视频一页,元素铺满合理区域)
if (videos.length > 0) {
for (const v of videos) {
const el = fileToVideoElement(v.file, v.data!)
if (videos.length === 1) {
store.addElement('video', { content: el.content, x: el.x, y: el.y, w: el.w, h: el.h, style: el.style }, batch)
insertedImages++
} else {
// 多视频:一视频一页
store.appendSlide({ id: `s-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, background: 'bg', elements: [el] }, batch)
insertedSlides++
}
}
}
// 2. AI 生成的幻灯片 → 追加到 deck
if (docs.length > 0) {
for (const d of docs) {
@@ -313,6 +333,7 @@ function textPreview(data: string, maxLen = 80): string {
<!-- 过滤 -->
<div class="filter-bar">
<label class="chk"><input type="checkbox" v-model="showImages" /> 🖼 图片 ({{ imageEntries.length }})</label>
<label class="chk"><input type="checkbox" v-model="showVideos" /> 🎬 视频 ({{ videoEntries.length }})</label>
<label class="chk"><input type="checkbox" v-model="showDocs" /> 📄 文档 ({{ docEntries.length }})</label>
</div>
@@ -332,12 +353,14 @@ function textPreview(data: string, maxLen = 80): string {
<!-- 文件列表 -->
<div class="file-list">
<div v-for="(entry, i) in filteredEntries" :key="i" class="file-item" :class="entry.kind">
<span class="file-icon">{{ entry.kind === 'image' ? '🖼' : '📄' }}</span>
<span class="file-icon">{{ entry.kind === 'image' ? '🖼' : entry.kind === 'video' ? '🎬' : '📄' }}</span>
<span class="file-name" :title="entry.name">{{ entry.name }}</span>
<span class="file-size">{{ fmtSize(entry.file.size) }}</span>
<span class="file-status">
<!-- 图片 -->
<template v-if="entry.kind === 'image' && entry.data"> 图片就绪</template>
<!-- 视频 -->
<template v-else-if="entry.kind === 'video' && entry.data"> 视频就绪</template>
<!-- 文档AI 分析结果 -->
<template v-else-if="entry.kind === 'document' && entry.slides"> AI {{ entry.slides.length }} </template>
<template v-else-if="entry.kind === 'document' && entry.data && analyzeDone"> 待分析</template>