import express from 'express'; import githubService from '../services/githubService.js'; import memoryStorageService from '../services/memoryStorageService.js'; const router = express.Router(); // 选择存储服务 const getStorageService = () => { // 如果GitHub Token未配置,使用内存存储 if (!process.env.GITHUB_TOKEN) { return memoryStorageService; } return githubService; }; // 生成HTML页面来显示PPT幻灯片 const generateSlideHTML = (pptData, slideIndex, title) => { const slide = pptData.slides[slideIndex]; const theme = pptData.theme || {}; // 渲染幻灯片元素 const renderElements = (elements) => { if (!elements || elements.length === 0) return ''; return elements.map(element => { const style = ` position: absolute; left: ${element.left}px; top: ${element.top}px; width: ${element.width}px; height: ${element.height}px; transform: rotate(${element.rotate || 0}deg); z-index: ${element.zIndex || 1}; `; switch (element.type) { case 'text': return `
${element.content || ''}
`; case 'image': return `
`; case 'shape': const shapeStyle = element.fill ? `background-color: ${element.fill};` : ''; const borderStyle = element.outline ? `border: ${element.outline.width || 1}px ${element.outline.style || 'solid'} ${element.outline.color || '#000'};` : ''; return `
`; default: return `
`; } }).join(''); }; return ` ${title} - 第${slideIndex + 1}页
${renderElements(slide.elements)}
`; }; // 公开访问PPT页面 - 返回HTML页面 router.get('/view/:userId/:pptId/:slideIndex?', async (req, res, next) => { try { const { userId, pptId, slideIndex = 0 } = req.params; const querySlideIndex = req.query.slide ? parseInt(req.query.slide) : parseInt(slideIndex); const fileName = `${pptId}.json`; const storageService = getStorageService(); let pptData = null; // 如果是GitHub服务,尝试所有仓库 if (storageService === githubService && storageService.repositories) { for (let i = 0; i < storageService.repositories.length; i++) { try { const result = await storageService.getFile(userId, fileName, i); if (result) { pptData = result.content; break; } } catch (error) { continue; } } } else { // 内存存储服务 const result = await storageService.getFile(userId, fileName); if (result) { pptData = result.content; } } if (!pptData) { return res.status(404).send(` PPT未找到

PPT未找到

请检查链接是否正确

`); } const slideIdx = querySlideIndex; if (slideIdx >= pptData.slides.length || slideIdx < 0) { return res.status(404).send(` 幻灯片未找到

幻灯片未找到

请检查幻灯片索引是否正确

`); } // 返回HTML页面 const htmlContent = generateSlideHTML(pptData, slideIdx, pptData.title); res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.send(htmlContent); } catch (error) { next(error); } }); // API接口:获取PPT数据和指定幻灯片(JSON格式) router.get('/api-view/:userId/:pptId/:slideIndex?', async (req, res, next) => { try { const { userId, pptId, slideIndex = 0 } = req.params; const fileName = `${pptId}.json`; const storageService = getStorageService(); let pptData = null; // 如果是GitHub服务,尝试所有仓库 if (storageService === githubService && storageService.repositories) { for (let i = 0; i < storageService.repositories.length; i++) { try { const result = await storageService.getFile(userId, fileName, i); if (result) { pptData = result.content; break; } } catch (error) { continue; } } } else { // 内存存储服务 const result = await storageService.getFile(userId, fileName); if (result) { pptData = result.content; } } if (!pptData) { return res.status(404).json({ error: 'PPT not found' }); } const slideIdx = parseInt(slideIndex); if (slideIdx >= pptData.slides.length || slideIdx < 0) { return res.status(404).json({ error: 'Slide not found' }); } // 返回PPT数据和指定幻灯片 res.json({ id: pptData.id, title: pptData.title, theme: pptData.theme, currentSlide: pptData.slides[slideIdx], slideIndex: slideIdx, totalSlides: pptData.slides.length, isPublicView: true }); } catch (error) { next(error); } }); // 获取完整PPT数据(只读模式) router.get('/ppt/:userId/:pptId', async (req, res, next) => { try { const { userId, pptId } = req.params; const fileName = `${pptId}.json`; const storageService = getStorageService(); let pptData = null; // 如果是GitHub服务,尝试所有仓库 if (storageService === githubService && storageService.repositories) { for (let i = 0; i < storageService.repositories.length; i++) { try { const result = await storageService.getFile(userId, fileName, i); if (result) { pptData = result.content; break; } } catch (error) { continue; } } } else { // 内存存储服务 const result = await storageService.getFile(userId, fileName); if (result) { pptData = result.content; } } if (!pptData) { return res.status(404).json({ error: 'PPT not found' }); } // 返回只读版本的PPT数据 res.json({ ...pptData, isPublicView: true, readOnly: true }); } catch (error) { next(error); } }); // 生成PPT分享链接 router.post('/generate-share-link', async (req, res, next) => { try { const { userId, pptId, slideIndex = 0 } = req.body; if (!userId || !pptId) { return res.status(400).json({ error: 'User ID and PPT ID are required' }); } // 验证PPT是否存在 const fileName = `${pptId}.json`; const storageService = getStorageService(); let pptExists = false; // 如果是GitHub服务,尝试所有仓库 if (storageService === githubService && storageService.repositories) { for (let i = 0; i < storageService.repositories.length; i++) { try { const result = await storageService.getFile(userId, fileName, i); if (result) { pptExists = true; break; } } catch (error) { continue; } } } else { // 内存存储服务 const result = await storageService.getFile(userId, fileName); if (result) { pptExists = true; } } if (!pptExists) { return res.status(404).json({ error: 'PPT not found' }); } const baseUrl = process.env.PUBLIC_URL || req.get('host'); const protocol = process.env.NODE_ENV === 'production' ? 'https' : req.protocol; const shareLinks = { // 单页分享链接 slideUrl: `${protocol}://${baseUrl}/api/public/view/${userId}/${pptId}/${slideIndex}`, // 完整PPT分享链接 pptUrl: `${protocol}://${baseUrl}/api/public/ppt/${userId}/${pptId}`, // 前端查看链接 viewUrl: `${protocol}://${baseUrl}/public/${userId}/${pptId}/${slideIndex}` }; res.json(shareLinks); } catch (error) { next(error); } }); export default router;