diff --git a/src-tauri/src/commands/app.rs b/src-tauri/src/commands/app.rs index 1c3a41f..a9dd617 100644 --- a/src-tauri/src/commands/app.rs +++ b/src-tauri/src/commands/app.rs @@ -86,3 +86,20 @@ pub async fn register_url_protocol( Ok(IpcResponse::error("URL protocol registration is not supported on this platform")) } } + +#[tauri::command] +pub async fn app_quit( + app: AppHandle, + _state: tauri::State<'_, Arc>>, +) -> Result<(), String> { + app.exit(0); + Ok(()) +} + +#[tauri::command] +pub async fn app_restart( + app: AppHandle, + _state: tauri::State<'_, Arc>>, +) -> Result<(), String> { + app.restart(); +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index bb0c130..970d3f9 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -107,6 +107,8 @@ pub fn run() { http_server_stop, http_server_status, register_url_protocol, + app_quit, + app_restart, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 281cd3b..4f11313 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -68,6 +68,8 @@ export const Settings: React.FC<{ permission: permissionLevel }> = ({ permission const [settleDialogVisible, setSettleDialogVisible] = useState(false) const [urlRegisterLoading, setUrlRegisterLoading] = useState(false) + const [appQuitLoading, setAppQuitLoading] = useState(false) + const [appRestartLoading, setAppRestartLoading] = useState(false) const canAdmin = permission === "admin" const [messageApi, contextHolder] = message.useMessage() @@ -418,6 +420,45 @@ export const Settings: React.FC<{ permission: permissionLevel }> = ({ permission const currentYear = new Date().getFullYear() + const confirmQuitApp = () => { + Modal.confirm({ + title: t("settings.app.confirmQuitTitle"), + content: t("settings.app.confirmQuitContent"), + okText: t("settings.app.quit"), + okButtonProps: { danger: true }, + cancelText: t("common.cancel"), + onOk: async () => { + if (!(window as any).api) return + setAppQuitLoading(true) + try { + await (window as any).api.appQuit() + } catch (e: any) { + setAppQuitLoading(false) + messageApi.error(e?.message || t("settings.app.quitFailed")) + } + }, + }) + } + + const confirmRestartApp = () => { + Modal.confirm({ + title: t("settings.app.confirmRestartTitle"), + content: t("settings.app.confirmRestartContent"), + okText: t("settings.app.restart"), + cancelText: t("common.cancel"), + onOk: async () => { + if (!(window as any).api) return + setAppRestartLoading(true) + try { + await (window as any).api.appRestart() + } catch (e: any) { + setAppRestartLoading(false) + messageApi.error(e?.message || t("settings.app.restartFailed")) + } + }, + }) + } + const tabItems = [ { key: "appearance", @@ -967,13 +1008,32 @@ export const Settings: React.FC<{ permission: permissionLevel }> = ({ permission
- + + + +
+ +
+ {t("settings.app.title")} +
+
+ {t("settings.app.description")} +
+
+ + + +
), diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index e139f55..ea95a8e 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -263,6 +263,18 @@ "registerFailed": "Registration failed", "installerRequired": "Requires installed SecScore, may not work in development mode." }, + "app": { + "title": "App Controls", + "description": "Quickly restart or quit the app.", + "restart": "Restart App", + "quit": "Quit App", + "confirmRestartTitle": "Restart the app now?", + "confirmRestartContent": "The app will close and start again immediately.", + "confirmQuitTitle": "Quit the app now?", + "confirmQuitContent": "The app will exit immediately.", + "restartFailed": "Restart failed", + "quitFailed": "Quit failed" + }, "about": { "title": "About", "appName": "Education Points Management", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index f44f086..05025e7 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -263,6 +263,18 @@ "registerFailed": "注册失败", "installerRequired": "需要安装版 SecScore,开发模式下可能无效。" }, + "app": { + "title": "应用控制", + "description": "快速重启或退出应用。", + "restart": "重启应用", + "quit": "退出应用", + "confirmRestartTitle": "确认重启应用?", + "confirmRestartContent": "应用将立即关闭并重新启动。", + "confirmQuitTitle": "确认退出应用?", + "confirmQuitContent": "应用将立即退出。", + "restartFailed": "重启失败", + "quitFailed": "退出失败" + }, "about": { "title": "关于", "appName": "教育积分管理", diff --git a/src/preload/types.ts b/src/preload/types.ts index 5f2c8fb..8f1d8ea 100644 --- a/src/preload/types.ts +++ b/src/preload/types.ts @@ -304,6 +304,8 @@ const api = { data?: { registered: boolean } message?: string }> => invoke("register_url_protocol"), + appQuit: (): Promise => invoke("app_quit"), + appRestart: (): Promise => invoke("app_restart"), // Auto Score autoScoreGetRules: (): Promise<{ success: boolean; data: any[] }> =>