From bea752879cf78437369db1a8f6940aa55873c833 Mon Sep 17 00:00:00 2001 From: PKC278 <52959804+PKC278@users.noreply.github.com> Date: Tue, 20 Jan 2026 00:34:33 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat(passkey):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE=E9=A1=B9?= =?UTF-8?q?=EF=BC=8C=E5=85=81=E8=AE=B8=E6=B3=A8=E5=86=8Cpasskey=E6=97=B6?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E9=AA=8C=E8=AF=81=E6=98=AF=E5=90=A6=E5=B7=B2?= =?UTF-8?q?=E6=B3=A8=E5=86=8Cotp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dialog/PasskeyDialog.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/dialog/PasskeyDialog.vue b/src/components/dialog/PasskeyDialog.vue index 90c6c656..756d9bc5 100644 --- a/src/components/dialog/PasskeyDialog.vue +++ b/src/components/dialog/PasskeyDialog.vue @@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n' import { formatDateDifference } from '@core/utils/formatters' import api from '@/api' import type { ApiResponse, PassKey } from '@/api/types' +import { useGlobalSettingsStore } from '@/stores' interface Props { modelValue: boolean @@ -26,6 +27,7 @@ const emit = defineEmits(['update:modelValue', 'update:passkeyList', 'verifyPass const { t, locale } = useI18n() const display = useDisplay() const $toast = useToast() +const globalSettingsStore = useGlobalSettingsStore() // 内部状态 const show = computed({ @@ -45,6 +47,9 @@ const passkeyName = ref('') // PassKey challenge const passkeyChallenge = ref('') +const allowPasskeyWithoutOtp = computed(() => !!globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP')) +const canRegisterPasskey = computed(() => props.isOtp || allowPasskeyWithoutOtp.value) + // 格式化日期 function formatDate(dateStr: string) { return new Date(dateStr).toLocaleDateString(locale.value) @@ -230,7 +235,7 @@ watch( - +
{{ t('profile.registerNewPasskey') }}

{{ t('profile.passkeyDescription') }}

From 3a782bc69c0e47cc900c606e3d9f649228c8b99e Mon Sep 17 00:00:00 2001 From: PKC278 <52959804+PKC278@users.noreply.github.com> Date: Tue, 20 Jan 2026 18:33:08 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(locales):=20=E4=BB=A5zh-CN=E4=B8=BA?= =?UTF-8?q?=E5=9F=BA=E5=87=86=EF=BC=8C=E8=A1=A5=E5=85=85=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E7=BC=BA=E5=A4=B1=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/en-US.ts | 23 +++++++++++++++++++++- src/locales/zh-TW.ts | 45 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index d29c69e2..2bb2570a 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1670,6 +1670,7 @@ export default { storage: 'Storage', storageDesc: 'Set up local or cloud storage.', directory: 'Directory', + mediaType: 'Media Type', directoryDesc: 'Set up media file organization directory structure, matching in sequence.', organizeAndScrap: 'Organization & Scraping', organizeAndScrapDesc: 'Set rename format, scraping options, etc.', @@ -1786,7 +1787,7 @@ export default { }, cache: { title: 'Cache Management', - subtitle: 'Manage torrent cache data', + subtitle: 'Manage cached site resources', totalCount: 'Total Count', siteCount: 'Site Count', filterByTitle: 'Filter by Title', @@ -3048,6 +3049,26 @@ export default { unsupportedDownloaderType: 'Unsupported downloader type: {type}', unsupportedMediaServerType: 'Unsupported media server type: {type}', unsupportedNotificationType: 'Unsupported notification type: {type}', + storageTestFailed: 'Storage test failed', + downloaderTestFailed: 'Downloader test failed', + downloaderNotSelected: 'No downloader selected', + mediaServerTestFailed: 'Media server test failed', + mediaServerNotSelected: 'No media server selected', + notificationTestFailed: 'Notification test failed', + notificationNotSelected: 'No notification type selected', + saveStepFailed: 'Failed to save step settings', + basicSettingsSaved: 'Basic settings saved successfully', + saveBasicSettingsFailed: 'Failed to save basic settings', + storageSettingsSaved: 'Storage settings saved successfully', + saveStorageSettingsFailed: 'Failed to save storage settings', + downloaderSettingsSaved: 'Downloader settings saved successfully', + saveDownloaderSettingsFailed: 'Failed to save downloader settings', + mediaServerSettingsSaved: 'Media server settings saved successfully', + saveMediaServerSettingsFailed: 'Failed to save media server settings', + notificationSettingsSaved: 'Notification settings saved successfully', + saveNotificationSettingsFailed: 'Failed to save notification settings', + preferenceSettingsSaved: 'Preference settings saved successfully', + savePreferenceSettingsFailed: 'Failed to save preference settings', passwordUpdateSuccess: 'Password updated successfully', userCreateSuccess: 'User created successfully', passwordUpdateFailed: 'Failed to update password', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 940cd705..3bd9b959 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -159,7 +159,6 @@ export default { subscribeMovie: '電影訂閱', subscribeTv: '電視劇訂閱', settings: '設置', - language: '語言設置', selectLanguage: '選擇語言', logout: '退出登錄', restarting: '正在重啟...', @@ -435,10 +434,13 @@ export default { name: '企業微信', corpId: '企業ID', corpIdHint: '企業微信後台企業信息中的企業ID', + corpIdRequired: '企業ID不能為空', appId: '應用 AgentId', appIdHint: '企業微信自建應用的AgentId', + appIdRequired: '應用AgentId不能為空', appSecret: '應用 Secret', appSecretHint: '企業微信自建應用的Secret', + appSecretRequired: '應用Secret不能為空', proxy: '代理地址', proxyHint: '微信消息的轉發代理地址,2022年6月20日後創建的自建應用才需要,不使用代理時需要保留默認值', token: 'Token', @@ -453,23 +455,30 @@ export default { name: 'Telegram', token: 'Bot Token', tokenHint: 'Telegram機器人token,格式:123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', + tokenRequired: 'Bot Token不能為空', chatId: 'Chat ID', chatIdHint: '接受消息通知的用戶、群組或頻道Chat ID', + chatIdRequired: 'Chat ID不能為空', users: '用戶白名單', usersHint: '可使用Telegram機器人的用戶ID清單,多個用戶用,分隔,不填寫則所有用戶都能使用', admins: '管理員白名單', adminsHint: '可使用管理菜單及命令的用戶ID列表,多個ID使用,分隔', adminsPlaceholder: '用戶ID列表,多個ID使用,分隔', usersPlaceholder: '用戶ID列表,多個ID使用,分隔', + apiUrl: '代理API地址', + apiUrlHint: '自定義代理API地址,格式:https://api.telegram.org', + apiUrlPlaceholder: 'https://api.telegram.org', }, slack: { name: 'Slack', oauthToken: 'Slack Bot User OAuth Token', oauthTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`Bot User OAuth Token`', + oauthTokenRequired: 'OAuth Token不能為空', appToken: 'Slack App-Level Token', appTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`App-Level Token`', channel: '頻道名稱', channelHint: '消息發送頻道,默認`全體`', + channelRequired: '頻道名稱不能為空', }, discord: { name: 'Discord', @@ -487,6 +496,7 @@ export default { name: 'Synology Chat', webhook: '機器人傳入URL', webhookHint: 'Synology Chat機器人傳入URL', + webhookRequired: 'Webhook URL不能為空', token: '令牌', tokenHint: 'Synology Chat機器人令牌', }, @@ -494,8 +504,10 @@ export default { name: 'VoceChat', host: '地址', hostHint: 'VoceChat服務端地址,格式:http(s)://ip:port', + hostRequired: '地址不能為空', apiKey: '機器人密鑰', apiKeyHint: 'VoceChat機器人密鑰', + apiKeyRequired: 'API密鑰不能為空', channelId: '頻道ID', channelIdHint: 'VoceChat的頻道ID,不包含#號', }, @@ -503,6 +515,7 @@ export default { name: 'WebPush', username: '登錄用戶名', usernameHint: '只有對應的用戶登錄後才會推送消息', + usernameRequired: '用戶名不能為空', }, }, shortcut: { @@ -1637,6 +1650,7 @@ export default { storage: '存儲', storageDesc: '設置本地或網盤存儲', directory: '目錄', + mediaType: '媒體類型', directoryDesc: '設置媒體文件整理目錄結構,按先後順序依次匹配。', organizeAndScrap: '整理 & 刮削', organizeAndScrapDesc: '設置重命名格式、刮削選項等。', @@ -1695,8 +1709,8 @@ export default { importHasId: '導入失敗!發現有規則存在相同ID,可能屬於自定義規則!', }, scheduler: { - scheduledTasks: '定時作業', - scheduledTasksDesc: '包含系統內置服務以及插件提供的服務', + title: '定時作業', + subtitle: '包含系統內置服務以及插件提供的服務', provider: '提供者', taskName: '任務名稱', taskStatus: '任務狀態', @@ -1748,9 +1762,10 @@ export default { settingsSaveFailed: '訂閱基礎設置保存失敗!', }, cache: { - title: '緩存', - description: '種子緩存、圖片文件緩存管理', + title: '緩存管理', subtitle: '管理緩存的站點資源', + totalCount: '總條數', + siteCount: '站點數', filterByTitle: '按標題篩選', filterBySite: '按站點篩選', selectSite: '選擇站點', @@ -3001,6 +3016,26 @@ export default { unsupportedDownloaderType: '不支援的下載器類型: {type}', unsupportedMediaServerType: '不支援的媒體服務器類型: {type}', unsupportedNotificationType: '不支援的通知類型: {type}', + storageTestFailed: '存儲目錄測試失敗', + downloaderTestFailed: '下載器測試失敗', + downloaderNotSelected: '未選擇下載器', + mediaServerTestFailed: '媒體服務器測試失敗', + mediaServerNotSelected: '未選擇媒體服務器', + notificationTestFailed: '消息通知測試失敗', + notificationNotSelected: '未選擇通知類型', + saveStepFailed: '保存步驟設置失敗', + basicSettingsSaved: '基礎設置保存成功', + saveBasicSettingsFailed: '保存基礎設置失敗', + storageSettingsSaved: '存儲設置保存成功', + saveStorageSettingsFailed: '保存存儲設置失敗', + downloaderSettingsSaved: '下載器設置保存成功', + saveDownloaderSettingsFailed: '保存下載器設置失敗', + mediaServerSettingsSaved: '媒體服務器設置保存成功', + saveMediaServerSettingsFailed: '保存媒體服務器設置失敗', + notificationSettingsSaved: '通知設置保存成功', + saveNotificationSettingsFailed: '保存通知設置失敗', + preferenceSettingsSaved: '偏好設置保存成功', + savePreferenceSettingsFailed: '保存偏好設置失敗', passwordUpdateSuccess: '密碼更新成功', userCreateSuccess: '使用者建立成功', passwordUpdateFailed: '密碼更新失敗', From c1d759f3f379c2320a92fec9c991aa448565752c Mon Sep 17 00:00:00 2001 From: PKC278 <52959804+PKC278@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:37:58 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(passkey):=20=E5=8A=A0=E5=BC=BA=E6=97=A0?= =?UTF-8?q?OTP=E6=B3=A8=E5=86=8CPassKey=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dialog/PasskeyDialog.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dialog/PasskeyDialog.vue b/src/components/dialog/PasskeyDialog.vue index 756d9bc5..f087313e 100644 --- a/src/components/dialog/PasskeyDialog.vue +++ b/src/components/dialog/PasskeyDialog.vue @@ -47,7 +47,7 @@ const passkeyName = ref('') // PassKey challenge const passkeyChallenge = ref('') -const allowPasskeyWithoutOtp = computed(() => !!globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP')) +const allowPasskeyWithoutOtp = computed(() => globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP') === true) const canRegisterPasskey = computed(() => props.isOtp || allowPasskeyWithoutOtp.value) // 格式化日期 From 63d629016698894ee600d2fb219393df9772f032 Mon Sep 17 00:00:00 2001 From: PKC278 <52959804+PKC278@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:54:27 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix(otp):=20=E4=BF=AE=E6=AD=A3=20OTP=20?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dialog/OTPAuthDialog.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/dialog/OTPAuthDialog.vue b/src/components/dialog/OTPAuthDialog.vue index 3d873111..68905319 100644 --- a/src/components/dialog/OTPAuthDialog.vue +++ b/src/components/dialog/OTPAuthDialog.vue @@ -5,6 +5,7 @@ import { useDisplay } from 'vuetify' import { useI18n } from 'vue-i18n' import api from '@/api' import type { ApiResponse, PassKey } from '@/api/types' +import { useGlobalSettingsStore } from '@/stores' interface Props { modelValue: boolean @@ -21,6 +22,7 @@ const emit = defineEmits(['update:modelValue', 'update:isOtp', 'verifyPassword'] const { t } = useI18n() const display = useDisplay() const $toast = useToast() +const globalSettingsStore = useGlobalSettingsStore() // 内部状态 const show = computed({ @@ -37,6 +39,8 @@ const secret = ref('') // 确认双重验证密码 const otpPassword = ref('') +const allowPasskeyWithoutOtp = computed(() => globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP') === true) + // 二维码图片 base64 const qrCodeImage = ref('') @@ -104,7 +108,7 @@ async function judgeOtpPassword() { // 关闭当前用户的双重验证 function disableOtp() { // 如果已绑定PassKey,不允许关闭OTP - if (props.passkeyList && props.passkeyList.length > 0) { + if (props.passkeyList && props.passkeyList.length > 0 && !allowPasskeyWithoutOtp.value) { $toast.error(t('profile.disableOtpWithPasskeyError')) return }