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未找到
`);
}
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;