feat: 添加自定义终端html背景的功能

This commit is contained in:
Baobhan Sith
2025-05-27 15:32:37 +08:00
parent e11cc66114
commit 81b26cd696
14 changed files with 1503 additions and 67 deletions
@@ -189,3 +189,166 @@ export const removeTerminalBackgroundController = async (req: Request, res: Resp
res.status(500).json({ message: '移除终端背景失败', error: error.message });
}
};
// --- HTML 预设主题控制器方法 ---
// GET /api/v1/appearance/html-presets/local
export const listLocalHtmlPresetsController = async (req: Request, res: Response): Promise<void> => {
try {
// 现在获取所有主题,包括预设和自定义,它们将带有 type 属性
const allThemes = await appearanceService.listAllHtmlThemes();
res.status(200).json(allThemes); // 直接返回带有 type 的列表
} catch (error: any) {
res.status(500).json({ message: '获取 HTML 主题列表失败', error: error.message });
}
};
// GET /api/v1/appearance/html-presets/local/:themeName
export const getLocalHtmlPresetContentController = async (req: Request, res: Response): Promise<void> => {
try {
const themeName = req.params.themeName;
let content: string | null = null;
let found = false;
// 1. 尝试作为用户自定义主题获取
try {
content = await appearanceService.getUserCustomHtmlThemeContent(themeName);
found = true;
} catch (customError: any) {
if (!customError.message.includes('未找到')) {
// 如果不是 "未找到" 错误,则直接抛出
throw customError;
}
// 如果是 "未找到",则继续尝试预设主题
}
// 2. 如果用户自定义主题未找到,尝试作为预设主题获取
if (!found) {
try {
content = await appearanceService.getPresetHtmlThemeContent(themeName);
found = true;
} catch (presetError: any) {
if (!presetError.message.includes('未找到')) {
throw presetError;
}
// 如果预设也未找到,此时才真正是 404
}
}
if (found && content !== null) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.status(200).send(content);
} else {
res.status(404).json({ message: `主题 '${themeName}' 未找到` });
}
} catch (error: any) {
// 通用错误处理
res.status(500).json({ message: `获取主题 '${req.params.themeName}' 内容失败`, error: error.message });
}
};
// POST /api/v1/appearance/html-presets/local
export const createLocalHtmlPresetController = async (req: Request, res: Response): Promise<void> => {
try {
const { name, content } = req.body;
if (!name || !content) {
res.status(400).json({ message: '主题名称和内容不能为空' });
return;
}
// "本地创建" 现在总是创建用户自定义主题
await appearanceService.createUserCustomHtmlTheme(name, content);
res.status(201).json({ message: '用户自定义 HTML 主题创建成功' });
} catch (error: any) {
res.status(500).json({ message: '创建用户自定义 HTML 主题失败', error: error.message });
}
};
// PUT /api/v1/appearance/html-presets/local/:themeName
export const updateLocalHtmlPresetController = async (req: Request, res: Response): Promise<void> => {
try {
const themeName = req.params.themeName;
const { content } = req.body;
if (content === undefined) {
res.status(400).json({ message: '主题内容不能为空' });
return;
}
// "本地更新" 现在总是更新用户自定义主题
await appearanceService.updateUserCustomHtmlTheme(themeName, content);
res.status(200).json({ message: '用户自定义 HTML 主题更新成功' });
} catch (error: any) {
if (error.message.includes('未找到')) {
res.status(404).json({ message: error.message });
} else {
res.status(500).json({ message: '更新用户自定义 HTML 主题失败', error: error.message });
}
}
};
// DELETE /api/v1/appearance/html-presets/local/:themeName
export const deleteLocalHtmlPresetController = async (req: Request, res: Response): Promise<void> => {
try {
const themeName = req.params.themeName;
// "本地删除" 现在总是删除用户自定义主题
await appearanceService.deleteUserCustomHtmlTheme(themeName);
res.status(200).json({ message: '用户自定义 HTML 主题删除成功' });
} catch (error: any) {
if (error.message.includes('未找到')) {
res.status(404).json({ message: error.message });
} else {
res.status(500).json({ message: '删除用户自定义 HTML 主题失败', error: error.message });
}
}
};
// GET /api/v1/appearance/html-presets/remote/repository-url
export const getRemoteHtmlPresetsRepositoryUrlController = async (req: Request, res: Response): Promise<void> => {
try {
const url = await appearanceService.getRemoteHtmlPresetsRepositoryUrl();
res.status(200).json({ url });
} catch (error: any) {
res.status(500).json({ message: '获取远程 HTML 主题仓库链接失败', error: error.message });
}
};
// PUT /api/v1/appearance/html-presets/remote/repository-url
export const updateRemoteHtmlPresetsRepositoryUrlController = async (req: Request, res: Response): Promise<void> => {
try {
const { url } = req.body;
// 注意:允许 url 为 null 或空字符串以清除设置
if (url === undefined) {
res.status(400).json({ message: 'URL 不能为空或 undefined' });
return;
}
await appearanceService.updateRemoteHtmlPresetsRepositoryUrl(url);
res.status(200).json({ message: '远程 HTML 主题仓库链接更新成功' });
} catch (error: any) {
res.status(500).json({ message: '更新远程 HTML 主题仓库链接失败', error: error.message });
}
};
// GET /api/v1/appearance/html-presets/remote/list
export const listRemoteHtmlPresetsController = async (req: Request, res: Response): Promise<void> => {
try {
const repoUrl = req.query.repoUrl as string | undefined;
const presets = await appearanceService.listRemoteHtmlPresets(repoUrl);
res.status(200).json(presets);
} catch (error: any) {
res.status(500).json({ message: '获取远程 HTML 主题列表失败', error: error.message });
}
};
// GET /api/v1/appearance/html-presets/remote/content
export const getRemoteHtmlPresetContentController = async (req: Request, res: Response): Promise<void> => {
try {
const fileUrl = req.query.fileUrl as string;
if (!fileUrl) {
res.status(400).json({ message: 'fileUrl 查询参数不能为空' });
return;
}
const content = await appearanceService.getRemoteHtmlPresetContent(fileUrl);
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.status(200).send(content);
} catch (error: any) {
res.status(500).json({ message: '获取远程 HTML 主题内容失败', error: error.message });
}
};
@@ -36,4 +36,22 @@ router.delete('/background/page', appearanceController.removePageBackgroundContr
// DELETE /api/v1/appearance/background/terminal - 删除终端背景图片
router.delete('/background/terminal', appearanceController.removeTerminalBackgroundController);
// HTML 预设主题相关路由 /api/v1/appearance/html-presets
const htmlPresetsRouter = express.Router();
// 本地 HTML 主题接口 /api/v1/appearance/html-presets/local
htmlPresetsRouter.get('/local', appearanceController.listLocalHtmlPresetsController);
htmlPresetsRouter.get('/local/:themeName', appearanceController.getLocalHtmlPresetContentController);
htmlPresetsRouter.post('/local', appearanceController.createLocalHtmlPresetController);
htmlPresetsRouter.put('/local/:themeName', appearanceController.updateLocalHtmlPresetController);
htmlPresetsRouter.delete('/local/:themeName', appearanceController.deleteLocalHtmlPresetController);
// 远程 GitHub HTML 主题接口 /api/v1/appearance/html-presets/remote
htmlPresetsRouter.get('/remote/repository-url', appearanceController.getRemoteHtmlPresetsRepositoryUrlController);
htmlPresetsRouter.put('/remote/repository-url', appearanceController.updateRemoteHtmlPresetsRepositoryUrlController);
htmlPresetsRouter.get('/remote/list', appearanceController.listRemoteHtmlPresetsController);
htmlPresetsRouter.get('/remote/content', appearanceController.getRemoteHtmlPresetContentController);
router.use('/html-presets', htmlPresetsRouter);
export default router;