diff --git a/apps/web/index.html b/apps/web/index.html
index 0907937..e91e72c 100644
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -3,6 +3,7 @@
+
SubTracker
diff --git a/apps/web/src/pages/SettingsPage.vue b/apps/web/src/pages/SettingsPage.vue
index 1e102a1..eb29ed5 100644
--- a/apps/web/src/pages/SettingsPage.vue
+++ b/apps/web/src/pages/SettingsPage.vue
@@ -455,9 +455,6 @@
启用 AI 能力
-
- AI 能力总开关控制识别与连接测试;AI 总结可单独开启或关闭。
-
@@ -559,9 +556,23 @@
允许通过通知验证码找回密码
+
+
+
+
+
+
+ 需先启用至少一个直达通知渠道
+
@@ -850,6 +861,7 @@ const savingGotifySettings = ref(false)
const savingWebhookSettings = ref(false)
const savingAiSettings = ref(false)
const savingCredentials = ref(false)
+const savingForgotPasswordToggle = ref(false)
const sourceCurrency = ref('USD')
const targetCurrency = ref('CNY')
const converterAmount = ref(1)
@@ -1369,6 +1381,25 @@ async function submitCredentialsChange() {
}
}
+async function handleForgotPasswordToggleChange(value: boolean) {
+ if (savingForgotPasswordToggle.value) return
+ const previousValue = settingsForm.forgotPasswordEnabled
+ settingsForm.forgotPasswordEnabled = value
+ savingForgotPasswordToggle.value = true
+ try {
+ const result = await api.updateSettings({
+ forgotPasswordEnabled: value
+ })
+ applySavedSettings(result)
+ message.success(value ? '找回密码已开启' : '找回密码已关闭')
+ } catch (error) {
+ settingsForm.forgotPasswordEnabled = previousValue
+ message.error(error instanceof Error ? error.message : '找回密码设置保存失败')
+ } finally {
+ savingForgotPasswordToggle.value = false
+ }
+}
+
async function testEmail() {
if (!validateEmailSettings('test')) return
try {
@@ -1630,6 +1661,10 @@ function previewSettingsReminderRules() {
min-height: 34px;
}
+.switch-disabled-wrapper {
+ display: inline-flex;
+}
+
.label-with-tip {
display: inline-flex;
align-items: center;
diff --git a/apps/web/tests/unit/components/app-layout.test.ts b/apps/web/tests/unit/components/app-layout.test.ts
index 577985f..e05eab0 100644
--- a/apps/web/tests/unit/components/app-layout.test.ts
+++ b/apps/web/tests/unit/components/app-layout.test.ts
@@ -5,6 +5,7 @@ describe('app layout sidebar behavior', () => {
it('keeps desktop sidebar fixed and menu independently scrollable', () => {
const source = readFileSync('src/App.vue', 'utf8')
const globalStyle = readFileSync('src/style.css', 'utf8')
+ const html = readFileSync('index.html', 'utf8')
expect(source).toContain('content-style="overflow: visible;"')
expect(source).toContain('class="desktop-sider"')
@@ -21,5 +22,7 @@ describe('app layout sidebar behavior', () => {
expect(globalStyle).toContain('background: #111827;')
expect(globalStyle).toContain('#app {')
expect(globalStyle).toContain('background: var(--app-bg);')
+ expect(html).toContain('rel="icon"')
+ expect(html).toContain('/src/assets/brand-logo.png')
})
})
diff --git a/apps/web/tests/unit/components/settings-import-export.test.ts b/apps/web/tests/unit/components/settings-import-export.test.ts
index 2f852fd..751e7cf 100644
--- a/apps/web/tests/unit/components/settings-import-export.test.ts
+++ b/apps/web/tests/unit/components/settings-import-export.test.ts
@@ -46,9 +46,9 @@ describe('settings import export section', () => {
expect(source).toContain('title="AI 能力设置"')
expect(source).toContain('启用 AI 能力')
expect(source).toContain('AI 总结')
- expect(source).toContain('AI 能力总开关控制识别与连接测试;AI 总结可单独开启或关闭')
expect(source).toContain('自定义识别提示词')
expect(source).toContain('自定义总结提示词')
+ expect(source).not.toContain('AI 能力总开关控制识别与连接测试;AI 总结可单独开启或关闭')
expect(source).not.toContain('title="AI 识别设置"')
expect(source).not.toContain('启用 AI 识别')
})
@@ -74,7 +74,10 @@ describe('settings import export section', () => {
expect(source).toContain('允许通过通知验证码找回密码')
expect(source).toContain('settingsForm.forgotPasswordEnabled')
expect(source).toContain('forgotPasswordToggleUnlocked')
- expect(source).toContain(":disabled=\"!forgotPasswordToggleUnlocked\"")
+ expect(source).toContain('savingForgotPasswordToggle')
+ expect(source).toContain('handleForgotPasswordToggleChange')
+ expect(source).toContain('需先启用至少一个直达通知渠道')
+ expect(source).toContain("@update:value=\"handleForgotPasswordToggleChange\"")
expect(source).toContain('switch-group switch-group--single')
expect(source).toContain('switch-inline-label')
expect(source).toContain('label="新密码"')