| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>视频生成测试</title>
- <style>
- * { margin: 0; padding: 0; box-sizing: border-box; }
- body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- padding: 20px;
- background: #f5f5f5;
- }
- .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); }
- h1 { text-align: center; margin-bottom: 30px; color: #333; }
-
- .form-group { margin-bottom: 20px; }
- label { display: block; margin-bottom: 8px; font-weight: 600; color: #333; }
- input[type="text"], textarea, input[type="file"] {
- width: 100%;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 8px;
- font-size: 14px;
- }
- textarea { min-height: 120px; resize: vertical; }
-
- button {
- width: 100%;
- padding: 14px;
- border: none;
- border-radius: 8px;
- font-size: 16px;
- font-weight: 600;
- cursor: pointer;
- margin-bottom: 10px;
- }
-
- .btn-primary { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; }
- .btn-secondary { background: #f5f5f5; color: #333; }
-
- button:hover { opacity: 0.9; }
- button:disabled { opacity: 0.5; cursor: not-allowed; }
-
- .result {
- margin-top: 20px;
- padding: 15px;
- background: #f9f9f9;
- border-radius: 8px;
- border-left: 4px solid #667eea;
- }
- .result h3 { margin-bottom: 10px; color: #333; }
- .result pre {
- background: #f5f5f5;
- padding: 10px;
- border-radius: 4px;
- overflow-x: auto;
- font-size: 12px;
- max-height: 300px;
- overflow-y: auto;
- }
-
- .status { padding: 10px; border-radius: 8px; margin-top: 15px; text-align: center; }
- .status.loading { background: #fff3cd; color: #856404; }
- .status.success { background: #d4edda; color: #155724; }
- .status.error { background: #f8d7da; color: #721c24; }
- </style>
- </head>
- <body>
- <div class="container">
- <h1>🎬 视频生成测试</h1>
-
- <div class="form-group">
- <label>视频标题:</label>
- <input type="text" id="title" value="测试视频" placeholder="输入视频标题">
- </div>
-
- <div class="form-group">
- <label>上传图片 (支持多选):</label>
- <input type="file" id="imageInput" accept="image/*" multiple>
- <div id="imagePreview" style="margin-top: 10px;"></div>
- </div>
-
- <div class="form-group">
- <label>上传音频:</label>
- <input type="file" id="audioInput" accept="audio/*">
- </div>
-
- <button class="btn-primary" onclick="testAPI()">1. 测试API连接</button>
- <button class="btn-primary" onclick="uploadAndCreate()">2. 上传文件并创建项目</button>
- <button class="btn-secondary" onclick="getProjectList()">3. 获取项目列表</button>
-
- <div id="result" class="result" style="display: none;">
- <h3>结果:</h3>
- <pre id="resultContent"></pre>
- </div>
-
- <div id="status" class="status" style="display: none;"></div>
- </div>
-
- <script>
- const API_BASE = 'http://localhost:3000/api';
-
- function showStatus(message, type) {
- const status = document.getElementById('status');
- status.textContent = message;
- status.className = 'status ' + type;
- status.style.display = 'block';
- }
-
- function showResult(data) {
- const result = document.getElementById('result');
- const content = document.getElementById('resultContent');
- result.style.display = 'block';
- content.textContent = JSON.stringify(data, null, 2);
- }
-
- async function testAPI() {
- showStatus('正在测试API连接...', 'loading');
- try {
- const res = await fetch(API_BASE + '/video/projects');
- const data = await res.json();
- showStatus('API连接成功!', 'success');
- showResult({ message: 'API连接测试成功', data });
- } catch (error) {
- showStatus('API连接失败: ' + error.message, 'error');
- showResult({ error: error.message, hint: '请确保后端服务已启动 (npm run dev)' });
- }
- }
-
- async function uploadAndCreate() {
- const title = document.getElementById('title').value;
- const imageInput = document.getElementById('imageInput');
- const audioInput = document.getElementById('audioInput');
-
- if (!title) {
- showStatus('请输入视频标题', 'error');
- return;
- }
-
- if (imageInput.files.length === 0) {
- showStatus('请选择至少一张图片', 'error');
- return;
- }
-
- showStatus('正在上传文件...', 'loading');
-
- try {
- // 1. 上传图片
- const imageUrls = [];
- for (let i = 0; i < imageInput.files.length; i++) {
- const file = imageInput.files[i];
- const formData = new FormData();
- formData.append('file', file);
- formData.append('type', 'image');
- formData.append('name', file.name);
- formData.append('category', 'custom');
-
- const res = await fetch(API_BASE + '/video/materials/upload', {
- method: 'POST',
- body: formData
- });
-
- if (!res.ok) throw new Error('图片上传失败');
-
- const data = await res.json();
- imageUrls.push(data.data?.url || `/uploads/materials/${file.name}`);
- showStatus(`图片 ${i + 1}/${imageInput.files.length} 上传成功`, 'loading');
- }
-
- // 2. 上传音频(如果有)
- let audioUrl = '';
- if (audioInput.files.length > 0) {
- const file = audioInput.files[0];
- const formData = new FormData();
- formData.append('file', file);
- formData.append('type', 'audio');
- formData.append('name', file.name);
- formData.append('category', 'custom');
-
- const res = await fetch(API_BASE + '/video/materials/upload', {
- method: 'POST',
- body: formData
- });
-
- if (!res.ok) throw new Error('音频上传失败');
-
- const data = await res.json();
- audioUrl = data.data?.url || `/uploads/materials/${file.name}`;
- showStatus('音频上传成功', 'loading');
- }
-
- // 3. 创建项目
- const projectData = {
- title: title,
- config: {
- video: { width: 720, height: 1280, fps: 30 },
- kenburns: { enabled: true, minZoom: 1.0, maxZoom: 1.2, zoomCurve: 'ease-in-out' },
- audio: { url: audioUrl, volume: 1.0 },
- images: imageUrls.map(url => ({ url, duration: 5, transition: 'fade' })),
- subtitle: { text: title, position: 'bottom', fontSize: 24, fontColor: 'white' }
- }
- };
-
- showStatus('正在创建项目...', 'loading');
- const createRes = await fetch(API_BASE + '/video/projects', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(projectData)
- });
-
- const createData = await createRes.json();
-
- if (createData.success) {
- showStatus('项目创建成功!', 'success');
- showResult({
- message: '视频项目创建成功!',
- project: createData.data,
- images: imageUrls,
- audio: audioUrl
- });
- } else {
- throw new Error(createData.error || '创建失败');
- }
-
- } catch (error) {
- showStatus('操作失败: ' + error.message, 'error');
- showResult({ error: error.message });
- }
- }
-
- async function getProjectList() {
- showStatus('正在获取项目列表...', 'loading');
- try {
- const res = await fetch(API_BASE + '/video/projects?pageSize=10');
- const data = await res.json();
- showStatus('获取成功!', 'success');
- showResult({ message: '项目列表', projects: data.data });
- } catch (error) {
- showStatus('获取失败: ' + error.message, 'error');
- showResult({ error: error.message });
- }
- }
-
- // 图片预览
- document.getElementById('imageInput').addEventListener('change', function(e) {
- const preview = document.getElementById('imagePreview');
- preview.innerHTML = '';
-
- Array.from(this.files).forEach(file => {
- const reader = new FileReader();
- reader.onload = function(e) {
- const img = document.createElement('img');
- img.src = e.target.result;
- img.style.cssText = 'width: 80px; height: 80px; object-fit: cover; border-radius: 8px; margin-right: 10px;';
- preview.appendChild(img);
- };
- reader.readAsDataURL(file);
- });
- });
- </script>
- </body>
- </html>
|