新增: 批注/备注/对齐分布/形状扩充/video 元素——编辑器能力增强
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user