npm package: @koi-br/ppt-editor-sdk
Description: 一个功能强大的PPT编辑器SDK，支持在线编辑、预览和导出PPT
Author: br
Latest version: 2.2.15

# @koi-br/ppt-editor-sdk：PPT编辑器SDK - v2

> 一个功能强大的在线PPT编辑器SDK，基于Vue 3 + TypeScript开发，支持在线编辑、预览和导出PPT。

[![npm version](https://badge.fury.io/js/@koi-br%2Fppt-editor-sdk.svg)](https://badge.fury.io/js/@koi-br%2Fppt-editor-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub](https://img.shields.io/github/stars/koi-br/ppt-editor-sdk?style=social)](https://github.com/koi-br/ppt-editor-sdk)
## ✨ 特性

- 🎨 **完整编辑界面** - 工具栏、属性面板、幻灯片缩略图、幻灯片编辑器
- 📝 **丰富元素支持** - 文字、图形、图片、表格、图表、公式
- 🎭 **动画和演示** - 幻灯片切换动画、元素动画效果
- 🎨 **主题系统** - 背景、渐变、字体、颜色样式系统
- 📤 **多种导出** - JSON、PPTX、PDF、图片等格式
- 🔧 **TypeScript** - 完整的类型定义支持
- 📱 **响应式** - 支持桌面和移动端
- ⚡ **Vue 3** - 基于最新Vue 3 + Pinia架构，支持Vue 3 Composition API
- 💾 **自动保存** - 可配置的自动保存功能
- 🔗 **在线编辑** - 支持在线编辑、预览和导出PPT，支持导入PPTX文件
- 🔗 **演示模式** - 支持演示模式，支持幻灯片切换动画、元素动画效果

## 📦 安装

### NPM安装

```bash
npm install @koi-br/ppt-editor-sdk
```

### CDN引入

```html
<!-- 引入依赖 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue-router@4/dist/vue-router.global.js"></script>
<script src="https://unpkg.com/pinia@2/dist/pinia.iife.js"></script>

<!-- 引入PPT编辑器SDK -->
<script src="https://unpkg.com/@koi-br/ppt-editor-sdk/dist/ppt-editor-sdk.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@koi-br/ppt-editor-sdk/dist/ppt-editor-sdk.css">
```

## 🚀 快速开始

### 运行示例

```bash
npm run dev
```

详细的运行指南请查看：
- [快速启动指南](./QUICK_START.md) - 简单快速的启动方式
- [完整使用指南](./USAGE_GUIDE.md) - 详细的使用文档

### Vue 3项目中使用

#### 方式一：使用完整版SDK类（推荐）

```vue
<template>
  <div class="ppt-editor-wrapper">
    <!-- SDK状态显示 -->
    <div class="status-panel">
      <h3>📊 SDK状态</h3>
      <p><strong>状态:</strong> <span :class="statusClass">{{ sdkStatus }}</span></p>
      <p><strong>幻灯片数量:</strong> {{ slideCount }}</p>
      <p><strong>当前幻灯片:</strong> {{ currentSlideId }}</p>
      <p><strong>最后操作:</strong> {{ lastAction }}</p>
    </div>

    <!-- 控制按钮 -->
    <div class="controls">
      <button @click="testLoadData" :disabled="!pptInstance">测试加载数据</button>
      <button @click="testExportData" :disabled="!pptInstance">测试导出数据</button>
      <button @click="testAddSlide" :disabled="!pptInstance">测试添加幻灯片</button>
      <button @click="testPresentation" :disabled="!pptInstance">测试演示模式</button>
      <button @click="getSDKInfo" :disabled="!pptInstance">获取SDK信息</button>
    </div>

    <!-- PPT编辑器容器 -->
    <div ref="pptContainer" class="ppt-container">
      <div v-if="!pptInstance" class="loading">
        正在初始化完整功能PPT编辑器...
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { 
  PPTEditorSDK,
  type PPTData, 
  type PPTInstance
} from '@koi-br/ppt-editor-sdk'

// 响应式状态
const pptContainer = ref<HTMLElement>()
const sdkStatus = ref('准备初始化...')
const slideCount = ref(0)
const currentSlideId = ref('-')
const lastAction = ref('等待初始化')
const isError = ref(false)

let pptSDK: PPTEditorSDK | null = null
let pptInstance: PPTInstance | null = null

// 计算属性
const statusClass = computed(() => ({
  'success': sdkStatus.value.includes('✅'),
  'error': isError.value
}))

// 更新状态显示
const updateStatus = (action = '') => {
  if (pptInstance) {
    slideCount.value = pptInstance.getSlideCount()
    const currentSlide = pptInstance.getCurrentSlide()
    currentSlideId.value = currentSlide?.id || 'N/A'
  }
  if (action) {
    lastAction.value = action
  }
}

// 初始化SDK - 基于test-fixed-sdk.html的成功实现
onMounted(async () => {
  try {
    console.log('🚀 开始初始化完整功能PPT编辑器SDK...')
    sdkStatus.value = '初始化中...'
    
    // 创建SDK实例 - 完全按照test-fixed-sdk.html的方式
    pptSDK = new PPTEditorSDK({
      container: '#ppt-editor', // 使用选择器，与HTML测试文件一致
      autoLoadSample: true, // 自动加载示例数据
      onReady: (instance) => {
        console.log('✅ SDK准备就绪回调触发')
        updateStatus('SDK准备就绪')
      },
      onChange: (data) => {
        console.log('📊 数据变化:', data)
        updateStatus('数据已变化')
      },
      onError: (error) => {
        console.error('❌ SDK错误:', error)
        sdkStatus.value = '❌ 初始化失败'
        isError.value = true
      }
    })

    // 初始化SDK
    pptInstance = await pptSDK.init()
    
    sdkStatus.value = '✅ 已就绪'
    isError.value = false
    updateStatus('SDK初始化完成')
    
    console.log('🎉 完整功能PPT编辑器SDK初始化成功！')
    console.log('📝 可用方法:', Object.keys(pptInstance))
    
  } catch (error) {
    console.error('❌ SDK初始化失败:', error)
    sdkStatus.value = '❌ 初始化失败'
    isError.value = true
  }
})

// 组件销毁时清理资源
onUnmounted(() => {
  if (pptSDK) {
    pptSDK.destroy()
    pptSDK = null
    pptInstance = null
  }
})

// 测试加载数据 - 与HTML测试文件完全一致
const testLoadData = async () => {
  if (!pptInstance) return alert('SDK未初始化')
  
  const testData = {
    title: '测试PPT数据',
    slides: [
      {
        id: 'test-slide-1',
        elements: [
          {
            type: 'text',
            id: 'test-text-1',
            left: 100,
            top: 100,
            width: 600,
            height: 100,
            content: '<h1 style="color: #e74c3c; text-align: center;">🧪 测试数据加载成功！</h1>',
            rotate: 0,
            defaultFontName: 'Microsoft YaHei',
            defaultColor: '#e74c3c'
          }
        ],
        background: {
          type: 'solid',
          color: '#f8f9fa'
        }
      }
    ]
  }
  
  try {
    await pptInstance.loadData(testData)
    updateStatus('测试数据加载')
    alert('✅ 测试数据加载成功！')
  } catch (error) {
    alert('❌ 加载失败: ' + error.message)
  }
}

// 测试导出数据
const testExportData = () => {
  if (!pptInstance) return alert('SDK未初始化')
  
  try {
    const data = pptInstance.getData()
    console.log('📤 导出的数据:', data)
    
    updateStatus('数据导出')
    alert(`✅ 数据导出成功！\n幻灯片数量: ${data.slides.length}\n请查看控制台获取详细数据`)
  } catch (error) {
    alert('❌ 导出失败: ' + error.message)
  }
}

// 测试添加幻灯片 - 与HTML测试文件完全一致
const testAddSlide = () => {
  if (!pptInstance) return alert('SDK未初始化')
  
  try {
    pptInstance.addSlide({
      id: `test-slide-${Date.now()}`,
      elements: [
        {
          type: 'text',
          id: `test-text-${Date.now()}`,
          left: 100,
          top: 200,
          width: 600,
          height: 100,
          content: '<h2 style="text-align: center;">🆕 新添加的幻灯片</h2>',
          rotate: 0,
          defaultFontName: 'Microsoft YaHei',
          defaultColor: '#333'
        }
      ],
      background: {
        type: 'solid',
        color: '#ffffff'
      }
    })
    
    updateStatus('添加新幻灯片')
    alert('✅ 新幻灯片添加成功！')
  } catch (error) {
    alert('❌ 添加失败: ' + error.message)
  }
}

// 测试演示模式
const testPresentation = () => {
  if (!pptInstance) return alert('SDK未初始化')
  
  try {
    // 简单切换演示模式（这里只是测试API调用）
    pptInstance.enterPresentation()
    
    setTimeout(() => {
      pptInstance.exitPresentation()
      updateStatus('演示模式测试')
      alert('✅ 演示模式切换测试完成！')
    }, 2000)
    
  } catch (error) {
    alert('❌ 演示模式测试失败: ' + error.message)
  }
}

// 获取SDK信息
const getSDKInfo = () => {
  if (!pptInstance) return alert('SDK未初始化')
  
  try {
    const slideCount = pptInstance.getSlideCount()
    const currentSlide = pptInstance.getCurrentSlide()
    const data = pptInstance.getData()
    
    const info = `
📊 SDK信息:
• 幻灯片总数: ${slideCount}
• 当前幻灯片ID: ${currentSlide?.id || 'N/A'}
• 当前幻灯片元素数: ${currentSlide?.elements?.length || 0}
• 数据标题: ${data.title || 'N/A'}
• 导出时间: ${data.exportTime || 'N/A'}
    `.trim()
    
    updateStatus('获取SDK信息')
    alert(info)
    console.log('📊 详细SDK信息:', { slideCount, currentSlide, data })
  } catch (error) {
    alert('❌ 获取信息失败: ' + error.message)
  }
}
</script>

<style scoped>
.ppt-editor-wrapper {
  padding: 20px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: #f5f5f5;
}

.status-panel {
  background: white;
  padding: 15px;
  border-radius: 8px;
  margin-bottom: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.status-panel h3 {
  margin-top: 0;
  color: #333;
}

.success {
  color: #67c23a;
  font-weight: bold;
}

.error {
  color: #f56c6c;
  font-weight: bold;
}

.controls {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.controls button {
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  background-color: #42b883;
  color: white;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.2s;
}

.controls button:hover:not(:disabled) {
  background-color: #369870;
  transform: translateY(-1px);
}

.controls button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.ppt-container {
  width: 100%;
  height: 800px;
  border: 2px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  background-color: white;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: 18px;
  color: #666;
}
</style>
```