Merge pull request #434 from PKC278/v2

This commit is contained in:
jxxghp
2026-01-20 21:21:24 +08:00
committed by GitHub
4 changed files with 73 additions and 8 deletions
+5 -1
View File
@@ -5,6 +5,7 @@ import { useDisplay } from 'vuetify'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import api from '@/api' import api from '@/api'
import type { ApiResponse, PassKey } from '@/api/types' import type { ApiResponse, PassKey } from '@/api/types'
import { useGlobalSettingsStore } from '@/stores'
interface Props { interface Props {
modelValue: boolean modelValue: boolean
@@ -21,6 +22,7 @@ const emit = defineEmits(['update:modelValue', 'update:isOtp', 'verifyPassword']
const { t } = useI18n() const { t } = useI18n()
const display = useDisplay() const display = useDisplay()
const $toast = useToast() const $toast = useToast()
const globalSettingsStore = useGlobalSettingsStore()
// 内部状态 // 内部状态
const show = computed({ const show = computed({
@@ -37,6 +39,8 @@ const secret = ref('')
// 确认双重验证密码 // 确认双重验证密码
const otpPassword = ref('') const otpPassword = ref('')
const allowPasskeyWithoutOtp = computed(() => globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP') === true)
// 二维码图片 base64 // 二维码图片 base64
const qrCodeImage = ref('') const qrCodeImage = ref('')
@@ -104,7 +108,7 @@ async function judgeOtpPassword() {
// 关闭当前用户的双重验证 // 关闭当前用户的双重验证
function disableOtp() { function disableOtp() {
// 如果已绑定PassKey,不允许关闭OTP // 如果已绑定PassKey,不允许关闭OTP
if (props.passkeyList && props.passkeyList.length > 0) { if (props.passkeyList && props.passkeyList.length > 0 && !allowPasskeyWithoutOtp.value) {
$toast.error(t('profile.disableOtpWithPasskeyError')) $toast.error(t('profile.disableOtpWithPasskeyError'))
return return
} }
+6 -1
View File
@@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n'
import { formatDateDifference } from '@core/utils/formatters' import { formatDateDifference } from '@core/utils/formatters'
import api from '@/api' import api from '@/api'
import type { ApiResponse, PassKey } from '@/api/types' import type { ApiResponse, PassKey } from '@/api/types'
import { useGlobalSettingsStore } from '@/stores'
interface Props { interface Props {
modelValue: boolean modelValue: boolean
@@ -26,6 +27,7 @@ const emit = defineEmits(['update:modelValue', 'update:passkeyList', 'verifyPass
const { t, locale } = useI18n() const { t, locale } = useI18n()
const display = useDisplay() const display = useDisplay()
const $toast = useToast() const $toast = useToast()
const globalSettingsStore = useGlobalSettingsStore()
// 内部状态 // 内部状态
const show = computed({ const show = computed({
@@ -45,6 +47,9 @@ const passkeyName = ref('')
// PassKey challenge // PassKey challenge
const passkeyChallenge = ref('') const passkeyChallenge = ref('')
const allowPasskeyWithoutOtp = computed(() => globalSettingsStore.get('PASSKEY_ALLOW_REGISTER_WITHOUT_OTP') === true)
const canRegisterPasskey = computed(() => props.isOtp || allowPasskeyWithoutOtp.value)
// 格式化日期 // 格式化日期
function formatDate(dateStr: string) { function formatDate(dateStr: string) {
return new Date(dateStr).toLocaleDateString(locale.value) return new Date(dateStr).toLocaleDateString(locale.value)
@@ -230,7 +235,7 @@ watch(
</VAlert> </VAlert>
<!-- 注册新通行密钥 --> <!-- 注册新通行密钥 -->
<VCard v-if="props.isOtp" variant="tonal" class="mb-6"> <VCard v-if="canRegisterPasskey" variant="tonal" class="mb-6">
<VCardText> <VCardText>
<h5 class="text-h5 font-weight-medium mb-2">{{ t('profile.registerNewPasskey') }}</h5> <h5 class="text-h5 font-weight-medium mb-2">{{ t('profile.registerNewPasskey') }}</h5>
<p class="mb-4">{{ t('profile.passkeyDescription') }}</p> <p class="mb-4">{{ t('profile.passkeyDescription') }}</p>
+22 -1
View File
@@ -1670,6 +1670,7 @@ export default {
storage: 'Storage', storage: 'Storage',
storageDesc: 'Set up local or cloud storage.', storageDesc: 'Set up local or cloud storage.',
directory: 'Directory', directory: 'Directory',
mediaType: 'Media Type',
directoryDesc: 'Set up media file organization directory structure, matching in sequence.', directoryDesc: 'Set up media file organization directory structure, matching in sequence.',
organizeAndScrap: 'Organization & Scraping', organizeAndScrap: 'Organization & Scraping',
organizeAndScrapDesc: 'Set rename format, scraping options, etc.', organizeAndScrapDesc: 'Set rename format, scraping options, etc.',
@@ -1786,7 +1787,7 @@ export default {
}, },
cache: { cache: {
title: 'Cache Management', title: 'Cache Management',
subtitle: 'Manage torrent cache data', subtitle: 'Manage cached site resources',
totalCount: 'Total Count', totalCount: 'Total Count',
siteCount: 'Site Count', siteCount: 'Site Count',
filterByTitle: 'Filter by Title', filterByTitle: 'Filter by Title',
@@ -3048,6 +3049,26 @@ export default {
unsupportedDownloaderType: 'Unsupported downloader type: {type}', unsupportedDownloaderType: 'Unsupported downloader type: {type}',
unsupportedMediaServerType: 'Unsupported media server type: {type}', unsupportedMediaServerType: 'Unsupported media server type: {type}',
unsupportedNotificationType: 'Unsupported notification 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', passwordUpdateSuccess: 'Password updated successfully',
userCreateSuccess: 'User created successfully', userCreateSuccess: 'User created successfully',
passwordUpdateFailed: 'Failed to update password', passwordUpdateFailed: 'Failed to update password',
+40 -5
View File
@@ -159,7 +159,6 @@ export default {
subscribeMovie: '電影訂閱', subscribeMovie: '電影訂閱',
subscribeTv: '電視劇訂閱', subscribeTv: '電視劇訂閱',
settings: '設置', settings: '設置',
language: '語言設置',
selectLanguage: '選擇語言', selectLanguage: '選擇語言',
logout: '退出登錄', logout: '退出登錄',
restarting: '正在重啟...', restarting: '正在重啟...',
@@ -435,10 +434,13 @@ export default {
name: '企業微信', name: '企業微信',
corpId: '企業ID', corpId: '企業ID',
corpIdHint: '企業微信後台企業信息中的企業ID', corpIdHint: '企業微信後台企業信息中的企業ID',
corpIdRequired: '企業ID不能為空',
appId: '應用 AgentId', appId: '應用 AgentId',
appIdHint: '企業微信自建應用的AgentId', appIdHint: '企業微信自建應用的AgentId',
appIdRequired: '應用AgentId不能為空',
appSecret: '應用 Secret', appSecret: '應用 Secret',
appSecretHint: '企業微信自建應用的Secret', appSecretHint: '企業微信自建應用的Secret',
appSecretRequired: '應用Secret不能為空',
proxy: '代理地址', proxy: '代理地址',
proxyHint: '微信消息的轉發代理地址,2022年6月20日後創建的自建應用才需要,不使用代理時需要保留默認值', proxyHint: '微信消息的轉發代理地址,2022年6月20日後創建的自建應用才需要,不使用代理時需要保留默認值',
token: 'Token', token: 'Token',
@@ -453,23 +455,30 @@ export default {
name: 'Telegram', name: 'Telegram',
token: 'Bot Token', token: 'Bot Token',
tokenHint: 'Telegram機器人token,格式:123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', tokenHint: 'Telegram機器人token,格式:123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
tokenRequired: 'Bot Token不能為空',
chatId: 'Chat ID', chatId: 'Chat ID',
chatIdHint: '接受消息通知的用戶、群組或頻道Chat ID', chatIdHint: '接受消息通知的用戶、群組或頻道Chat ID',
chatIdRequired: 'Chat ID不能為空',
users: '用戶白名單', users: '用戶白名單',
usersHint: '可使用Telegram機器人的用戶ID清單,多個用戶用,分隔,不填寫則所有用戶都能使用', usersHint: '可使用Telegram機器人的用戶ID清單,多個用戶用,分隔,不填寫則所有用戶都能使用',
admins: '管理員白名單', admins: '管理員白名單',
adminsHint: '可使用管理菜單及命令的用戶ID列表,多個ID使用,分隔', adminsHint: '可使用管理菜單及命令的用戶ID列表,多個ID使用,分隔',
adminsPlaceholder: '用戶ID列表,多個ID使用,分隔', adminsPlaceholder: '用戶ID列表,多個ID使用,分隔',
usersPlaceholder: '用戶ID列表,多個ID使用,分隔', usersPlaceholder: '用戶ID列表,多個ID使用,分隔',
apiUrl: '代理API地址',
apiUrlHint: '自定義代理API地址,格式:https://api.telegram.org',
apiUrlPlaceholder: 'https://api.telegram.org',
}, },
slack: { slack: {
name: 'Slack', name: 'Slack',
oauthToken: 'Slack Bot User OAuth Token', oauthToken: 'Slack Bot User OAuth Token',
oauthTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`Bot User OAuth Token`', oauthTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`Bot User OAuth Token`',
oauthTokenRequired: 'OAuth Token不能為空',
appToken: 'Slack App-Level Token', appToken: 'Slack App-Level Token',
appTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`App-Level Token`', appTokenHint: 'Slack應用`OAuth & Permissions`頁面中的`App-Level Token`',
channel: '頻道名稱', channel: '頻道名稱',
channelHint: '消息發送頻道,默認`全體`', channelHint: '消息發送頻道,默認`全體`',
channelRequired: '頻道名稱不能為空',
}, },
discord: { discord: {
name: 'Discord', name: 'Discord',
@@ -487,6 +496,7 @@ export default {
name: 'Synology Chat', name: 'Synology Chat',
webhook: '機器人傳入URL', webhook: '機器人傳入URL',
webhookHint: 'Synology Chat機器人傳入URL', webhookHint: 'Synology Chat機器人傳入URL',
webhookRequired: 'Webhook URL不能為空',
token: '令牌', token: '令牌',
tokenHint: 'Synology Chat機器人令牌', tokenHint: 'Synology Chat機器人令牌',
}, },
@@ -494,8 +504,10 @@ export default {
name: 'VoceChat', name: 'VoceChat',
host: '地址', host: '地址',
hostHint: 'VoceChat服務端地址,格式:http(s)://ip:port', hostHint: 'VoceChat服務端地址,格式:http(s)://ip:port',
hostRequired: '地址不能為空',
apiKey: '機器人密鑰', apiKey: '機器人密鑰',
apiKeyHint: 'VoceChat機器人密鑰', apiKeyHint: 'VoceChat機器人密鑰',
apiKeyRequired: 'API密鑰不能為空',
channelId: '頻道ID', channelId: '頻道ID',
channelIdHint: 'VoceChat的頻道ID,不包含#號', channelIdHint: 'VoceChat的頻道ID,不包含#號',
}, },
@@ -503,6 +515,7 @@ export default {
name: 'WebPush', name: 'WebPush',
username: '登錄用戶名', username: '登錄用戶名',
usernameHint: '只有對應的用戶登錄後才會推送消息', usernameHint: '只有對應的用戶登錄後才會推送消息',
usernameRequired: '用戶名不能為空',
}, },
}, },
shortcut: { shortcut: {
@@ -1637,6 +1650,7 @@ export default {
storage: '存儲', storage: '存儲',
storageDesc: '設置本地或網盤存儲', storageDesc: '設置本地或網盤存儲',
directory: '目錄', directory: '目錄',
mediaType: '媒體類型',
directoryDesc: '設置媒體文件整理目錄結構,按先後順序依次匹配。', directoryDesc: '設置媒體文件整理目錄結構,按先後順序依次匹配。',
organizeAndScrap: '整理 & 刮削', organizeAndScrap: '整理 & 刮削',
organizeAndScrapDesc: '設置重命名格式、刮削選項等。', organizeAndScrapDesc: '設置重命名格式、刮削選項等。',
@@ -1695,8 +1709,8 @@ export default {
importHasId: '導入失敗!發現有規則存在相同ID,可能屬於自定義規則!', importHasId: '導入失敗!發現有規則存在相同ID,可能屬於自定義規則!',
}, },
scheduler: { scheduler: {
scheduledTasks: '定時作業', title: '定時作業',
scheduledTasksDesc: '包含系統內置服務以及插件提供的服務', subtitle: '包含系統內置服務以及插件提供的服務',
provider: '提供者', provider: '提供者',
taskName: '任務名稱', taskName: '任務名稱',
taskStatus: '任務狀態', taskStatus: '任務狀態',
@@ -1748,9 +1762,10 @@ export default {
settingsSaveFailed: '訂閱基礎設置保存失敗!', settingsSaveFailed: '訂閱基礎設置保存失敗!',
}, },
cache: { cache: {
title: '緩存', title: '緩存管理',
description: '種子緩存、圖片文件緩存管理',
subtitle: '管理緩存的站點資源', subtitle: '管理緩存的站點資源',
totalCount: '總條數',
siteCount: '站點數',
filterByTitle: '按標題篩選', filterByTitle: '按標題篩選',
filterBySite: '按站點篩選', filterBySite: '按站點篩選',
selectSite: '選擇站點', selectSite: '選擇站點',
@@ -3001,6 +3016,26 @@ export default {
unsupportedDownloaderType: '不支援的下載器類型: {type}', unsupportedDownloaderType: '不支援的下載器類型: {type}',
unsupportedMediaServerType: '不支援的媒體服務器類型: {type}', unsupportedMediaServerType: '不支援的媒體服務器類型: {type}',
unsupportedNotificationType: '不支援的通知類型: {type}', unsupportedNotificationType: '不支援的通知類型: {type}',
storageTestFailed: '存儲目錄測試失敗',
downloaderTestFailed: '下載器測試失敗',
downloaderNotSelected: '未選擇下載器',
mediaServerTestFailed: '媒體服務器測試失敗',
mediaServerNotSelected: '未選擇媒體服務器',
notificationTestFailed: '消息通知測試失敗',
notificationNotSelected: '未選擇通知類型',
saveStepFailed: '保存步驟設置失敗',
basicSettingsSaved: '基礎設置保存成功',
saveBasicSettingsFailed: '保存基礎設置失敗',
storageSettingsSaved: '存儲設置保存成功',
saveStorageSettingsFailed: '保存存儲設置失敗',
downloaderSettingsSaved: '下載器設置保存成功',
saveDownloaderSettingsFailed: '保存下載器設置失敗',
mediaServerSettingsSaved: '媒體服務器設置保存成功',
saveMediaServerSettingsFailed: '保存媒體服務器設置失敗',
notificationSettingsSaved: '通知設置保存成功',
saveNotificationSettingsFailed: '保存通知設置失敗',
preferenceSettingsSaved: '偏好設置保存成功',
savePreferenceSettingsFailed: '保存偏好設置失敗',
passwordUpdateSuccess: '密碼更新成功', passwordUpdateSuccess: '密碼更新成功',
userCreateSuccess: '使用者建立成功', userCreateSuccess: '使用者建立成功',
passwordUpdateFailed: '密碼更新失敗', passwordUpdateFailed: '密碼更新失敗',