mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
feat: Provider 异步删除、可配置密码策略、Hub 超时优化及多项改进
- 新增 Provider 异步删除任务系统,后台分阶段删除子资源并清理残留引用 - 新增可配置密码策略等级(weak/medium/strong),支持系统设置面板调整 - aether-hub 升级至 0.1.4,idle timeout 支持禁用(设为 0),worker 默认超时调整为 120s - OAuth 手动续期增加 Redis 分布式锁,防止并发刷新冲突 - ProxyNode 心跳检测改为 asyncio.to_thread,避免阻塞事件循环 - 删除 ModelMultiSelect 和 useInvalidModels,MultiSelect 组件通用化 - 明确 allowed_providers/allowed_api_formats 的 NULL 与空数组语义 - 前端 StandaloneKeyFormDialog、UserFormDialog 等多处 UI 优化 - 新增 Alembic 迁移脚本清理 Provider 删除后的残留引用 - 补充相关测试用例
This commit is contained in:
@@ -119,6 +119,18 @@
|
||||
type="password"
|
||||
class="mt-1"
|
||||
/>
|
||||
<p
|
||||
v-if="passwordError"
|
||||
class="mt-1 text-xs text-destructive"
|
||||
>
|
||||
{{ passwordError }}
|
||||
</p>
|
||||
<p
|
||||
v-else
|
||||
class="mt-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{{ passwordPolicyHint }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label for="confirm-password">确认{{ profile?.has_password ? '新' : '' }}密码</Label>
|
||||
@@ -465,6 +477,12 @@ import { authApi } from '@/api/auth'
|
||||
import { oauthApi, type OAuthLinkInfo, type OAuthProviderInfo } from '@/api/oauth'
|
||||
import { getOAuthIcon } from '@/utils/oauth-icons'
|
||||
import { useDarkMode, type ThemeMode } from '@/composables/useDarkMode'
|
||||
import {
|
||||
getPasswordPolicyHint,
|
||||
normalizePasswordPolicyLevel,
|
||||
validatePasswordByPolicy,
|
||||
type PasswordPolicyLevel,
|
||||
} from '@/utils/passwordPolicy'
|
||||
import Card from '@/components/ui/card.vue'
|
||||
import Button from '@/components/ui/button.vue'
|
||||
import Badge from '@/components/ui/badge.vue'
|
||||
@@ -516,6 +534,7 @@ const preferencesForm = ref({
|
||||
|
||||
const savingProfile = ref(false)
|
||||
const changingPassword = ref(false)
|
||||
const passwordPolicyLevel = ref<PasswordPolicyLevel>('weak')
|
||||
const themeSelectOpen = ref(false)
|
||||
const languageSelectOpen = ref(false)
|
||||
|
||||
@@ -539,6 +558,11 @@ const hasProfileChanges = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const passwordPolicyHint = computed(() => getPasswordPolicyHint(passwordPolicyLevel.value))
|
||||
const passwordError = computed(() =>
|
||||
validatePasswordByPolicy(passwordForm.value.new_password, passwordPolicyLevel.value)
|
||||
)
|
||||
|
||||
// 检测密码表单是否有内容
|
||||
const hasPasswordChanges = computed(() => {
|
||||
const hasPassword = profile.value?.has_password
|
||||
@@ -577,8 +601,10 @@ async function loadEmailConfigured() {
|
||||
try {
|
||||
const settings = await authApi.getRegistrationSettings()
|
||||
emailConfigured.value = !!settings.email_configured
|
||||
passwordPolicyLevel.value = normalizePasswordPolicyLevel(settings.password_policy_level)
|
||||
} catch {
|
||||
emailConfigured.value = false
|
||||
passwordPolicyLevel.value = 'weak'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,8 +792,8 @@ async function changePassword() {
|
||||
return
|
||||
}
|
||||
|
||||
if (passwordForm.value.new_password.length < 6) {
|
||||
showError('密码长度至少6位', '密码错误')
|
||||
if (passwordError.value) {
|
||||
showError(passwordError.value, '密码错误')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user