fix: settings save button and multiple UI bugs

- Fix duplicate :min attributes on a-input-number (webPort, subPort, tgCpu)
- Fix mismatched closing tags (a-input/a-switch instead of a-input-number)
- Fix twoFactorEnable toggle receiving MouseEvent instead of boolean
- Fix noise input handlers referencing undefined global `event`
- Add error handling to settings change detection polling loop
- Bump version to v1.5.4-beta
This commit is contained in:
root 2026-04-24 15:44:48 +08:00
parent 5ec81ea3d0
commit 582037ae70
8 changed files with 62 additions and 12 deletions

View file

@ -1 +1 @@
v1.5.3-beta
v1.5.4-beta

View file

@ -0,0 +1,49 @@
# 2026-04-24 Fix Settings Save Button and UI Bugs
## Problem
Settings page save button would not enable when user changed settings.
## Root Cause Analysis
Systematic debugging found multiple UI bugs affecting the settings page:
1. **Duplicate `:min` attributes on `a-input-number`** (3 locations)
- `general.html:42` — webPort had `:min="1" :min="65535"` (second should be `:max`)
- `subscription/general.html:43` — subPort had same issue
- `telegram.html:64` — tgCpu had `:min="0" :min="100"` (second should be `:max`)
2. **Mismatched closing tags**
- `general.html:42``<a-input-number>` closed with `</a-input>`
- `telegram.html:64``<a-input-number>` closed with `</a-switch>`
3. **twoFactorEnable toggle broken** (`security.html:39`)
- Used `@click="toggleTwoFactor" :checked="..."` instead of proper event handling
- `@click` passes MouseEvent as first arg, not the boolean toggle value
- Method expected boolean but received Event → always truthy → always triggered enable flow
4. **Noise input handlers referenced undefined `event`** (`json.html:91,99`)
- `(value) => updateNoisePacket(index, event.target.value)``event` is not defined
- Arrow function parameter named `value` but code accessed global `event`
5. **Polling loop had no error handling** (`settings.html:653-656`)
- Any error in the `while(true)` loop would silently stop change detection
## Changes
- Fixed `:min`/`:max` attributes on all `a-input-number` components
- Fixed closing tags to match opening tags
- Changed twoFactorEnable to use `@click.prevent="toggleTwoFactor(!allSetting.twoFactorEnable)"`
- Updated `toggleTwoFactor` method to only set `twoFactorEnable` on success
- Fixed noise input handlers to use `(e) => ... e.target.value`
- Added try/catch around polling loop comparison
## Files Modified
- `web/html/settings/panel/general.html` — webPort input fix
- `web/html/settings/panel/subscription/general.html` — subPort input fix
- `web/html/settings/panel/telegram.html` — tgCpu input fix
- `web/html/settings/panel/security.html` — twoFactorEnable toggle fix
- `web/html/settings/panel/subscription/json.html` — noise input handler fix
- `web/html/settings.html` — toggleTwoFactor method + polling error handling
## Verification
- Visual inspection of all modified templates
- Confirmed `ObjectUtil.equals()` shallow comparison works correctly with Vue 2 reactivity
- Confirmed `AllSetting` class properties match Go struct fields

View file

@ -396,11 +396,9 @@
confirm: (success) => {
if (success) {
Vue.prototype.$message['success']('{{ i18n "pages.settings.security.twoFactorModalSetSuccess" }}')
this.allSetting.twoFactorToken = newTwoFactorToken
this.allSetting.twoFactorEnable = true
}
this.allSetting.twoFactorEnable = success
}
})
} else {
@ -412,7 +410,6 @@
confirm: (success) => {
if (success) {
Vue.prototype.$message['success']('{{ i18n "pages.settings.security.twoFactorModalDeleteSuccess" }}')
this.allSetting.twoFactorEnable = false
this.allSetting.twoFactorToken = ""
}
@ -655,7 +652,11 @@
}
while (true) {
await PromiseUtil.sleep(1000);
this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting);
try {
this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting);
} catch (e) {
console.error('Settings change detection error:', e);
}
}
}
});

View file

@ -39,7 +39,7 @@
<template #title>{{ i18n "pages.settings.panelPort"}}</template>
<template #description>{{ i18n "pages.settings.panelPortDesc"}}</template>
<template #control>
<a-input-number :min="1" :min="65535" v-model="allSetting.webPort" :style="{ width: '100%' }"></a-input>
<a-input-number :min="1" :max="65535" v-model="allSetting.webPort" :style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">

View file

@ -36,7 +36,7 @@
<template #title>{{ i18n "pages.settings.security.twoFactorEnable" }}</template>
<template #description>{{ i18n "pages.settings.security.twoFactorEnableDesc" }}</template>
<template #control>
<a-switch @click="toggleTwoFactor" :checked="allSetting.twoFactorEnable"></a-switch>
<a-switch :checked="allSetting.twoFactorEnable" @click.prevent="toggleTwoFactor(!allSetting.twoFactorEnable)"></a-switch>
</template>
</a-setting-list-item>
</a-collapse-panel>

View file

@ -40,7 +40,7 @@
<template #title>{{ i18n "pages.settings.subPort"}}</template>
<template #description>{{ i18n "pages.settings.subPortDesc"}}</template>
<template #control>
<a-input-number v-model="allSetting.subPort" :min="1" :min="65535"
<a-input-number v-model="allSetting.subPort" :min="1" :max="65535"
:style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>

View file

@ -88,7 +88,7 @@
<template #title>Packet</template>
<template #control>
<a-input type="text" :value="noise.packet"
@input="(value) => updateNoisePacket(index, event.target.value)"
@input="(e) => updateNoisePacket(index, e.target.value)"
placeholder="5-10"></a-input>
</template>
</a-setting-list-item>
@ -96,7 +96,7 @@
<template #title>Delay (ms)</template>
<template #control>
<a-input type="text" :value="noise.delay"
@input="(value) => updateNoiseDelay(index, event.target.value)"
@input="(e) => updateNoiseDelay(index, e.target.value)"
placeholder="10-20"></a-input>
</template>
</a-setting-list-item>

View file

@ -61,7 +61,7 @@
<template #title>{{ i18n "pages.settings.tgNotifyCpu" }}</template>
<template #description>{{ i18n "pages.settings.tgNotifyCpuDesc" }}</template>
<template #control>
<a-input-number :min="0" :min="100" v-model="allSetting.tgCpu" :style="{ width: '100%' }"></a-switch>
<a-input-number :min="0" :max="100" v-model="allSetting.tgCpu" :style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
</a-collapse-panel>