初始提交:浏览器首页 MyHomePage 全栈项目
# 项目概述 个人浏览器首页导航应用,支持书签分类管理、搜索引擎快捷搜索、 必应每日壁纸轮播、前后端分离部署,适配 1Panel 服务器(Docker 模式)。 # 技术栈 - 前端:Vue 3 + TypeScript + Vite + Pinia + Capacitor(Android 打包) - 后端:.NET 8 + SqlSugar(多数据库) + SQLite/MySQL + Swashbuckle - 部署:1Panel 应用商店自定义应用(Docker Compose 模式) # 项目结构 - backend/ .NET 8 API 后端(8 个 Controller + 15 个 Service) - frontend/ Vue 3 前端(19 个组件 + 9 个 API 模块 + 5 个 Store) - docker/ Docker 部署文件(后端镜像 + Nginx 反代) - docs/ 部署手册(1Panel 实战版) - scripts/ E2E 测试脚本 # 已实现功能 - 书签管理:增删改查 + 树形分类 + 拖拽排序 + 主色自适应 - 搜索引擎:8 个内置引擎 + 自定义引擎 + favicon 自动抓取 - 必应壁纸:每日轮播 + 多分辨率自动选择 + 1.6MP 质量优先 - 全局设置:主题/行为/数据/工具 4 分类 + 跨设备同步 - 文件上传:图标/书签/通用(容器持久化 + 跨域 URL 拼接) - 同步:基于变更日志的设备间数据同步 - 跨域部署:前后端分离 + runtime config.json 无需重新编译 # 进度记录 - 已完成 P0~P52 共 53 个开发节点(详细见 说明文档.md) - 当前版本:v1.0 部署就绪 # 部署文档 - README.md:项目说明 + 快速开始 - 说明文档.md:完整开发进度(中文) - docs/DEPLOY.md:1Panel 部署手册(Docker 模式)
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
using MyHomePage.Api.Common;
|
||||
using MyHomePage.Api.Models.Dtos;
|
||||
using MyHomePage.Api.Models.Entities;
|
||||
using SqlSugar;
|
||||
|
||||
namespace MyHomePage.Api.Services;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SettingService : ISettingService
|
||||
{
|
||||
private const int DefaultId = 1;
|
||||
private static readonly HashSet<string> AllowedThemeModes = new(StringComparer.OrdinalIgnoreCase) { "dark", "light", "auto" };
|
||||
private static readonly HashSet<string> AllowedBackgroundTypes = new(StringComparer.OrdinalIgnoreCase) { "preset", "custom", "solid" };
|
||||
// ===== P34 360 壁纸切换间隔合法值(分钟)=====
|
||||
private static readonly HashSet<int> AllowedWallpaperIntervals = new() { 0, 1, 5, 15, 30, 60 };
|
||||
|
||||
private readonly ISqlSugarClient _db;
|
||||
private readonly SyncLogHelper _sync;
|
||||
|
||||
public SettingService(ISqlSugarClient db, SyncLogHelper sync)
|
||||
{
|
||||
_db = db;
|
||||
_sync = sync;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SettingDto> GetAsync()
|
||||
{
|
||||
var entity = await _db.Queryable<Setting>().InSingleAsync(DefaultId);
|
||||
if (entity is null)
|
||||
{
|
||||
// 兜底:写入默认值
|
||||
entity = new Setting { Id = DefaultId };
|
||||
await _db.Insertable(entity).ExecuteCommandAsync();
|
||||
}
|
||||
return ToDto(entity);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SettingDto> UpdateAsync(SettingUpdateRequest request)
|
||||
{
|
||||
var entity = await _db.Queryable<Setting>().InSingleAsync(DefaultId);
|
||||
if (entity is null)
|
||||
{
|
||||
entity = new Setting { Id = DefaultId };
|
||||
await _db.Insertable(entity).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.ThemeMode))
|
||||
{
|
||||
if (!AllowedThemeModes.Contains(request.ThemeMode)) throw new BusinessException("不支持的主题模式", 400);
|
||||
entity.ThemeMode = request.ThemeMode;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(request.AccentColor))
|
||||
{
|
||||
if (request.AccentColor.Length > 16) throw new BusinessException("主色调格式错误", 400);
|
||||
entity.AccentColor = request.AccentColor;
|
||||
}
|
||||
if (request.BackgroundImage is not null) entity.BackgroundImage = request.BackgroundImage;
|
||||
if (!string.IsNullOrEmpty(request.BackgroundType))
|
||||
{
|
||||
if (!AllowedBackgroundTypes.Contains(request.BackgroundType)) throw new BusinessException("不支持的背景类型", 400);
|
||||
entity.BackgroundType = request.BackgroundType;
|
||||
}
|
||||
if (request.OpenLinksInNewTab.HasValue) entity.OpenLinksInNewTab = request.OpenLinksInNewTab.Value ? 1 : 0;
|
||||
if (request.OpenSearchInNewTab.HasValue) entity.OpenSearchInNewTab = request.OpenSearchInNewTab.Value ? 1 : 0;
|
||||
|
||||
// ===== P34 360 壁纸模式 =====
|
||||
if (request.WallpaperEnabled.HasValue) entity.WallpaperEnabled = request.WallpaperEnabled.Value ? 1 : 0;
|
||||
if (request.WallpaperCategoryId is not null) entity.WallpaperCategoryId = request.WallpaperCategoryId;
|
||||
if (request.WallpaperInterval.HasValue)
|
||||
{
|
||||
if (!AllowedWallpaperIntervals.Contains(request.WallpaperInterval.Value))
|
||||
throw new BusinessException("不支持的壁纸切换间隔(允许:0/1/5/15/30/60 分钟)", 400);
|
||||
entity.WallpaperInterval = request.WallpaperInterval.Value;
|
||||
}
|
||||
|
||||
entity.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||
await _sync.WriteAsync("setting", entity.Id, "update");
|
||||
return ToDto(entity);
|
||||
}
|
||||
|
||||
private static SettingDto ToDto(Setting s) => SettingDto.FromEntity(s);}
|
||||
Reference in New Issue
Block a user