From f6cf1daae57c4751291264032d4a0698f62ba2f6 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 05:55:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=9D=A2=E6=9D=BF=20?= =?UTF-8?q?HTTPS=20=E8=AF=81=E4=B9=A6=E6=89=8B=E5=8A=A8=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E6=8C=89=E9=92=AE=20(#1334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * feat: 添加面板证书手动刷新按钮 在面板设置安全标签页中,当 HTTPS 模式为 ACME 时, 在保存按钮右侧显示「刷新证书」按钮,点击后通过 已有的 ObtainCert 服务方法重新签发证书并重启面板。 Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> * feat: 当 HTTPS 设置有未保存修改时禁用刷新证书按钮 追踪 https/acme/public_ip 的已保存状态,当用户修改这些 设置但未保存时,禁用「刷新证书」按钮,保存后恢复可用。 Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> --- internal/route/http.go | 1 + web/src/api/panel/setting/index.ts | 4 ++- web/src/views/setting/IndexView.vue | 44 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/internal/route/http.go b/internal/route/http.go index c02252a9..e2d3432f 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -492,6 +492,7 @@ func (route *Http) Register(r *chi.Mux) { r.Get("/", route.setting.Get) r.Post("/", route.setting.Update) r.Post("/cert", route.setting.UpdateCert) + r.Post("/obtain_cert", route.setting.ObtainCert) }) r.Route("/systemctl", func(r chi.Router) { diff --git a/web/src/api/panel/setting/index.ts b/web/src/api/panel/setting/index.ts index d491458a..0d9999ef 100644 --- a/web/src/api/panel/setting/index.ts +++ b/web/src/api/panel/setting/index.ts @@ -4,5 +4,7 @@ export default { // 获取设置 list: (): any => http.Get('/setting'), // 保存设置 - update: (settings: any): any => http.Post('/setting', settings) + update: (settings: any): any => http.Post('/setting', settings), + // 刷新证书 + obtainCert: (): any => http.Post('/setting/obtain_cert') } diff --git a/web/src/views/setting/IndexView.vue b/web/src/views/setting/IndexView.vue index 2ff216c7..9ee934a8 100644 --- a/web/src/views/setting/IndexView.vue +++ b/web/src/views/setting/IndexView.vue @@ -19,6 +19,23 @@ const permissionStore = usePermissionStore() const currentTab = ref('base') const createModal = ref(false) +// 记录已保存的 HTTPS 相关设置,用于判断是否有未保存的修改 +const savedHttpsState = ref({ https: false, acme: false, public_ip: '[]' }) +const httpsSettingsDirty = computed(() => { + return ( + model.value.https !== savedHttpsState.value.https || + model.value.acme !== savedHttpsState.value.acme || + JSON.stringify(model.value.public_ip) !== savedHttpsState.value.public_ip + ) +}) +const snapshotHttpsState = () => { + savedHttpsState.value = { + https: model.value.https, + acme: model.value.acme, + public_ip: JSON.stringify(model.value.public_ip) + } +} + const { data: model } = useRequest(setting.list, { initialData: { name: '', @@ -48,6 +65,9 @@ const { data: model } = useRequest(setting.list, { } }) +// 数据加载完成后快照 HTTPS 状态 +watch(model, () => snapshotHttpsState(), { once: true, deep: true }) + const handleSave = () => { if (model.value.entrance.trim() === '') { model.value.entrance = '/' @@ -55,6 +75,9 @@ const handleSave = () => { useRequest(setting.update(model.value)).onSuccess(({ data }) => { window.$message.success($gettext('Saved successfully')) + // 更新 HTTPS 快照 + snapshotHttpsState() + // 更新语言设置 if (model.value.locale !== themeStore.locale) { themeStore.setLocale(model.value.locale) @@ -79,6 +102,19 @@ const handleSave = () => { }) } +const handleObtainCert = () => { + useRequest(setting.obtainCert()).onSuccess(() => { + window.$message.success($gettext('Certificate refreshed successfully')) + window.$message.info($gettext('Panel is restarting, page will refresh in 5 seconds')) + setTimeout(() => { + const hostname = window.location.hostname + const port = model.value.port + const entrance = model.value.entrance || '/' + window.location.href = `https://${hostname}:${port}${entrance}` + }, 5000) + }) +} + const handleCreate = () => { createModal.value = true } @@ -106,6 +142,14 @@ const handleCreate = () => { {{ $gettext('Save') }} + + {{ $gettext('Refresh Certificate') }} +