This commit is contained in:
Baobhan Sith
2025-04-17 20:26:30 +08:00
parent 09cba0b3d3
commit 9eb0bcc5f3
40 changed files with 2607 additions and 326 deletions
@@ -0,0 +1,55 @@
import * as appearanceRepository from '../repositories/appearance.repository';
import { AppearanceSettings, UpdateAppearanceDto } from '../types/appearance.types';
import * as terminalThemeRepository from '../repositories/terminal-theme.repository'; // 需要验证 activeTerminalThemeId
/**
* 获取外观设置
* @returns Promise<AppearanceSettings>
*/
export const getSettings = async (): Promise<AppearanceSettings> => {
return appearanceRepository.getAppearanceSettings();
};
/**
* 更新外观设置
* @param settingsDto 更新数据
* @returns Promise<boolean> 是否成功更新
*/
export const updateSettings = async (settingsDto: UpdateAppearanceDto): Promise<boolean> => {
// 验证 activeTerminalThemeId (如果提供了)
if (settingsDto.activeTerminalThemeId !== undefined && settingsDto.activeTerminalThemeId !== null) {
const themeIdNum = parseInt(settingsDto.activeTerminalThemeId, 10);
if (isNaN(themeIdNum)) {
throw new Error(`无效的终端主题 ID 格式: ${settingsDto.activeTerminalThemeId}`);
}
try {
const themeExists = await terminalThemeRepository.findThemeById(themeIdNum);
if (!themeExists) {
throw new Error(`指定的终端主题 ID 不存在: ${settingsDto.activeTerminalThemeId}`);
}
} catch (e: any) { // Catch potential errors from findThemeById as well
console.error(`验证终端主题 ID (${settingsDto.activeTerminalThemeId}) 时出错:`, e.message);
// Rethrow a more specific error or the original one
throw new Error(`验证终端主题 ID 时出错: ${e.message || settingsDto.activeTerminalThemeId}`);
}
} else if (settingsDto.hasOwnProperty('activeTerminalThemeId')) {
// Handle explicit setting to null/undefined (meaning reset to default/no theme)
// The repository update logic handles null/undefined correctly, so no specific validation needed here.
// We just need to ensure the key exists in the DTO if it's meant to be cleared.
}
// 验证透明度值 (如果提供了)
if (settingsDto.terminalBackgroundOpacity !== undefined && (settingsDto.terminalBackgroundOpacity < 0 || settingsDto.terminalBackgroundOpacity > 1)) {
throw new Error('终端背景透明度必须在 0 和 1 之间');
}
if (settingsDto.pageBackgroundOpacity !== undefined && (settingsDto.pageBackgroundOpacity < 0 || settingsDto.pageBackgroundOpacity > 1)) {
throw new Error('页面背景透明度必须在 0 和 1 之间');
}
// TODO: 如果实现了背景图片上传,这里需要处理文件路径或 URL 的验证/保存逻辑
return appearanceRepository.updateAppearanceSettings(settingsDto);
};
// 注意:背景图片上传/处理逻辑需要根据最终决定(URL vs 上传)来添加。
@@ -0,0 +1,88 @@
import * as terminalThemeRepository from '../repositories/terminal-theme.repository';
import { TerminalTheme, CreateTerminalThemeDto, UpdateTerminalThemeDto } from '../types/terminal-theme.types';
// import { validate } from 'class-validator'; // 移除导入
import type { ITheme } from 'xterm';
/**
* 获取所有终端主题
* @returns Promise<TerminalTheme[]>
*/
export const getAllThemes = async (): Promise<TerminalTheme[]> => {
return terminalThemeRepository.findAllThemes();
};
/**
* 根据 ID 获取单个终端主题
* @param id 主题 ID (SQLite 数字 ID)
* @returns Promise<TerminalTheme | null>
*/
export const getThemeById = async (id: number): Promise<TerminalTheme | null> => {
if (isNaN(id)) {
throw new Error('无效的主题 ID');
}
return terminalThemeRepository.findThemeById(id);
};
/**
* 创建新终端主题
* @param themeDto 创建数据
* @returns Promise<TerminalTheme>
*/
export const createNewTheme = async (themeDto: CreateTerminalThemeDto): Promise<TerminalTheme> => {
// 移除验证相关的注释
// 简单验证 themeData 结构 (确保基本字段存在)
if (!themeDto.themeData || typeof themeDto.themeData.background !== 'string' || typeof themeDto.themeData.foreground !== 'string') {
throw new Error('无效的主题数据格式');
}
return terminalThemeRepository.createTheme(themeDto);
};
/**
* 更新终端主题
* @param id 主题 ID (SQLite 数字 ID)
* @param themeDto 更新数据
* @returns Promise<boolean> 是否成功更新
*/
export const updateExistingTheme = async (id: number, themeDto: UpdateTerminalThemeDto): Promise<boolean> => {
if (isNaN(id)) {
throw new Error('无效的主题 ID');
}
// 可选:验证 themeDto
if (!themeDto.name || !themeDto.themeData || typeof themeDto.themeData.background !== 'string' || typeof themeDto.themeData.foreground !== 'string') {
throw new Error('无效的主题更新数据');
}
return terminalThemeRepository.updateTheme(id, themeDto);
};
/**
* 删除终端主题
* @param id 主题 ID (SQLite 数字 ID)
* @returns Promise<boolean> 是否成功删除
*/
export const deleteExistingTheme = async (id: number): Promise<boolean> => {
if (isNaN(id)) {
throw new Error('无效的主题 ID');
}
return terminalThemeRepository.deleteTheme(id);
};
/**
* 导入终端主题
* @param themeData 主题数据对象 (ITheme)
* @param name 主题名称
* @returns Promise<TerminalTheme>
*/
export const importTheme = async (themeData: ITheme, name: string): Promise<TerminalTheme> => {
if (!name) {
throw new Error('导入主题时必须提供名称');
}
// 验证导入的数据结构是否符合 ITheme (简化验证)
if (typeof themeData.background !== 'string' || typeof themeData.foreground !== 'string') {
throw new Error('导入的主题数据格式无效');
}
const dto: CreateTerminalThemeDto = { name, themeData };
return createNewTheme(dto);
};
// 注意:导出功能通常在 Controller 层处理,根据 ID 获取主题数据后,设置响应头并发送 JSON 文件。