Service 业务层
Service 层负责业务逻辑处理,是 Command 和 Database 之间的桥梁。
结构
每个业务模块对应一个 Service 文件:
src-tauri/src/services/
├── mod.rs # 模块导出
├── config.rs # 配置业务逻辑(ConfigService)
└── main_window_placement.rs # 主窗口显示器记忆与纠偏
示例
ConfigService 是无字段的单元结构体,方法都是关联函数,数据库引用通过参数传入(services/config.rs):
/// 配置管理服务
pub struct ConfigService;
impl ConfigService {
/// 获取所有配置
pub fn get_all(db: &Database) -> Result<Vec<AppConfig>, AppError> {
db.get_all_config()
}
/// 设置配置值
pub fn set(db: &Database, key: &str, value: &str) -> Result<(), AppError> {
if key.is_empty() {
return Err(AppError::InvalidInput("配置键不能为空".into()));
}
db.set_config(key, value)
}
/// 删除配置
pub fn delete(db: &Database, key: &str) -> Result<(), AppError> {
let deleted = db.delete_config(key)?;
if !deleted {
return Err(AppError::NotFound(format!("配置项 '{}' 不存在", key)));
}
Ok(())
}
}
Command 层这样调用:ConfigService::set(&state.db, &key, &value)。
主窗口显示器记忆
main_window_placement.rs 不访问数据库,负责记住主窗口所在的显示器,在冷启动、托盘唤回、二次启动、插拔副屏后把窗口放回原来的屏;记录持久化到 app_config_dir 下的 json 文件(开发版 main-window-placement-dev.json,正式版 main-window-placement.json)。对外入口:
| 函数 | 用途 |
|---|---|
init(app, will_show) | 启动时读取记录,把主窗口摆回上次的屏 |
show_main(app, source) | 唤回主窗口(还原 + 显示 + 聚焦 + 纠偏),托盘、二次启动、macOS Dock 都走它 |
capture_now(app, reason) | 立即记录一次当前位置 |
on_main_window_event(app, event) | 在 on_window_event 中处理主窗口的移动 / 缩放 / 缩放比例变化 |
新增「唤回主窗口」的入口时一律调用 show_main,不要手写 unminimize + show + set_focus,否则会绕过显示器纠偏。
规范
- Service 方法通过参数接收
&Database(来自state.db),不在 Service 内持有连接 - 使用
AppError作为错误类型(非CommandError) - 参数校验与业务判定(如“配置项不存在”)在 Service 层完成
- 复杂逻辑拆分为多个小方法
- 一个 Service 对应一个业务模块