mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-04 23:30:03 +08:00
更新国际化支持:在多个组件中引入 vue-i18n,优化文本翻译和结构
This commit is contained in:
@@ -140,7 +140,9 @@ onMounted(() => {
|
||||
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||
<dt class="block text-sm font-bold">{{ t('setting.about.dataDir') }}</dt>
|
||||
<dd class="flex text-sm sm:col-span-2 sm:mt-0">
|
||||
<span class="flex-grow undefined"><code>/moviepilot</code></span>
|
||||
<span class="flex-grow undefined"
|
||||
><code>{{ t('setting.about.dataDirectory') }}</code></span
|
||||
>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,9 @@ import { TransferDirectoryConf, StorageConf } from '@/api/types'
|
||||
import DirectoryCard from '@/components/cards/DirectoryCard.vue'
|
||||
import StorageCard from '@/components/cards/StorageCard.vue'
|
||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// 所有下载目录
|
||||
const directories = ref<TransferDirectoryConf[]>([])
|
||||
@@ -195,8 +198,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>存储</VCardTitle>
|
||||
<VCardSubtitle>设置本地或网盘存储。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.directory.storage') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.directory.storageDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<draggable
|
||||
@@ -214,7 +217,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" class="me-2" @click="saveStorages"> 保存 </VBtn>
|
||||
<VBtn type="submit" class="me-2" @click="saveStorages"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
@@ -225,8 +228,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>目录</VCardTitle>
|
||||
<VCardSubtitle>设置媒体文件整理目录结构,按先后顺序依次匹配。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.directory.directory') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.directory.directoryDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<draggable
|
||||
@@ -250,7 +253,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveDirectories"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveDirectories"> {{ t('common.save') }} </VBtn>
|
||||
<VBtn color="success" variant="tonal" @click="addDirectory">
|
||||
<VIcon icon="mdi-plus" />
|
||||
</VBtn>
|
||||
@@ -264,8 +267,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>整理 & 刮削</VCardTitle>
|
||||
<VCardSubtitle>设置重命名格式、刮削选项等。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.directory.organizeAndScrap') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.directory.organizeAndScrapDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VRow>
|
||||
@@ -273,16 +276,16 @@ onMounted(() => {
|
||||
<VSelect
|
||||
v-model="SystemSettings.Basic.SCRAP_SOURCE"
|
||||
:items="sourceItems"
|
||||
label="刮削数据源"
|
||||
hint="刮削时的元数据来源"
|
||||
:label="t('setting.directory.scrapSource')"
|
||||
:hint="t('setting.directory.scrapSourceHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VTextarea
|
||||
v-model="SystemSettings.Basic.MOVIE_RENAME_FORMAT"
|
||||
label="电影重命名格式"
|
||||
hint="使用Jinja2语法,格式参考:https://jinja.palletsprojects.com/en/3.0.x/templates"
|
||||
:label="t('setting.directory.movieRenameFormat')"
|
||||
:hint="t('setting.directory.movieRenameFormatHint')"
|
||||
persistent-hint
|
||||
clearable
|
||||
active
|
||||
@@ -291,8 +294,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VTextarea
|
||||
v-model="SystemSettings.Basic.TV_RENAME_FORMAT"
|
||||
label="电视剧重命名格式"
|
||||
hint="使用Jinja2语法,格式参考:https://jinja.palletsprojects.com/en/3.0.x/templates"
|
||||
:label="t('setting.directory.tvRenameFormat')"
|
||||
:hint="t('setting.directory.tvRenameFormatHint')"
|
||||
persistent-hint
|
||||
clearable
|
||||
active
|
||||
@@ -303,7 +306,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveSystemSettings(SystemSettings.Basic)"> 保存</VBtn>
|
||||
<VBtn type="submit" @click="saveSystemSettings(SystemSettings.Basic)"> {{ t('common.save') }}</VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
@@ -311,5 +314,5 @@ onMounted(() => {
|
||||
</VCol>
|
||||
</VRow>
|
||||
<!-- 进度框 -->
|
||||
<ProgressDialog v-if="progressDialog" v-model="progressDialog" text="正在应用配置..." />
|
||||
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="t('setting.system.reloading')" />
|
||||
</template>
|
||||
|
||||
@@ -216,19 +216,19 @@ onMounted(() => {
|
||||
<VListItemTitle>{{ t('setting.notification.wechat') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('telegram')">
|
||||
<VListItemTitle>Telegram</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.notification.telegram') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('slack')">
|
||||
<VListItemTitle>Slack</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.notification.slack') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('synologychat')">
|
||||
<VListItemTitle>SynologyChat</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.notification.synologyChat') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('vocechat')">
|
||||
<VListItemTitle>VoceChat</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.notification.voceChat') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('webpush')">
|
||||
<VListItemTitle>WebPush</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.notification.webPush') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
|
||||
@@ -8,6 +8,10 @@ import { CustomRule, FilterRuleGroup } from '@/api/types'
|
||||
import CustomerRuleCard from '@/components/cards/CustomRuleCard.vue'
|
||||
import FilterRuleGroupCard from '@/components/cards/FilterRuleGroupCard.vue'
|
||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
// 自定义规则列表
|
||||
const customRules = ref<CustomRule[]>([])
|
||||
@@ -32,10 +36,10 @@ const $toast = useToast()
|
||||
|
||||
// 种子优先规则下拉框
|
||||
const TorrentPriorityItems = [
|
||||
{ title: '资源优先级', value: 'torrent' },
|
||||
{ title: '站点优先级', value: 'site' },
|
||||
{ title: '站点上传量', value: 'upload' },
|
||||
{ title: '资源做种数', value: 'seeder' },
|
||||
{ title: t('setting.rule.resourcePriority'), value: 'torrent' },
|
||||
{ title: t('setting.rule.sitePriority'), value: 'site' },
|
||||
{ title: t('setting.rule.siteUpload'), value: 'upload' },
|
||||
{ title: t('setting.rule.resourceSeeder'), value: 'seeder' },
|
||||
]
|
||||
|
||||
// 调用API查询自动分类配置
|
||||
@@ -51,12 +55,12 @@ async function loadMediaCategories() {
|
||||
async function saveCustomRules() {
|
||||
// 检查是否存在空id规则
|
||||
if (customRules.value.some(item => !item.id)) {
|
||||
$toast.error('存在空ID的规则,无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.emptyIdError'))
|
||||
return
|
||||
}
|
||||
// 检查是否存在空的规则名称
|
||||
if (customRules.value.some(item => !item.name)) {
|
||||
$toast.error('存在空名字的规则,无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.emptyNameError'))
|
||||
return
|
||||
}
|
||||
// 获取所有规则ID和名称
|
||||
@@ -64,18 +68,18 @@ async function saveCustomRules() {
|
||||
const names = customRules.value.map(item => item.name)
|
||||
// 检查是否存在重名的规则ID
|
||||
if (new Set(ids).size !== ids.length) {
|
||||
$toast.error('存在重复规则ID!无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.duplicateIdError'))
|
||||
return
|
||||
}
|
||||
// 检查是否存在重名规则名称
|
||||
if (new Set(names).size !== names.length) {
|
||||
$toast.error('存在重复规则名称!无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.duplicateNameError'))
|
||||
return
|
||||
}
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.post('system/setting/CustomFilterRules', customRules.value)
|
||||
if (result.success) $toast.success('自定义规则保存成功')
|
||||
else $toast.error('自定义规则保存失败!')
|
||||
if (result.success) $toast.success(t('setting.rule.customRuleSaveSuccess'))
|
||||
else $toast.error(t('setting.rule.customRuleSaveFailed'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -117,19 +121,19 @@ async function queryFilterRuleGroups() {
|
||||
async function saveFilterRuleGroups() {
|
||||
// 检查是否存在空的规则组名称
|
||||
if (filterRuleGroups.value.some(item => !item.name)) {
|
||||
$toast.error('存在空名字的规则组!无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.emptyGroupNameError'))
|
||||
return
|
||||
}
|
||||
// 检查是否存在重名规则组
|
||||
const names = filterRuleGroups.value.map(item => item.name)
|
||||
if (new Set(names).size !== names.length) {
|
||||
$toast.error('存在重复规则组名称!无法保存,请修改!')
|
||||
$toast.error(t('setting.rule.duplicateGroupNameError'))
|
||||
return
|
||||
}
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.post('system/setting/UserFilterRuleGroups', filterRuleGroups.value)
|
||||
if (result.success) $toast.success('优先级规则组保存成功')
|
||||
else $toast.error('优先级规则组保存失败!')
|
||||
if (result.success) $toast.success(t('setting.rule.ruleGroupSaveSuccess'))
|
||||
else $toast.error(t('setting.rule.ruleGroupSaveFailed'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -157,10 +161,14 @@ async function shareRules(rules: CustomRule[] | FilterRuleGroup[], type: string)
|
||||
try {
|
||||
let success
|
||||
success = copyToClipboard(value)
|
||||
if (await success) $toast.success(`${type === 'custom' ? '自定义规则' : '优先级规则组'}已复制到剪贴板!`)
|
||||
else $toast.error(`${type === 'custom' ? '自定义规则' : '优先级规则组'}复制失败:可能是浏览器不支持或被用户阻止!`)
|
||||
if (await success)
|
||||
$toast.success(
|
||||
type === 'custom' ? t('setting.rule.customRuleCopySuccess') : t('setting.rule.ruleGroupCopySuccess'),
|
||||
)
|
||||
else
|
||||
$toast.error(type === 'custom' ? t('setting.rule.customRuleCopyFailed') : t('setting.rule.ruleGroupCopyFailed'))
|
||||
} catch (e) {
|
||||
$toast.error(`${type === 'custom' ? '自定义规则' : '优先级规则组'}复制失败!`)
|
||||
$toast.error(type === 'custom' ? t('setting.rule.customRuleCopyError') : t('setting.rule.ruleGroupCopyError'))
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@@ -178,7 +186,7 @@ function saveCodeString(type: string, codeString: any) {
|
||||
try {
|
||||
parsedCode = JSON.parse(codeString.value)
|
||||
} catch (e) {
|
||||
$toast.error('导入规则失败!无法解析输入的数据!')
|
||||
$toast.error(t('setting.rule.importFailed'))
|
||||
console.error(e)
|
||||
return
|
||||
}
|
||||
@@ -194,10 +202,10 @@ function saveCodeString(type: string, codeString: any) {
|
||||
const newFilterRuleGroups = extractFilterRuleGroups(parsedCode) || []
|
||||
filterRuleGroups.value = [...filterRuleGroups.value, ...newFilterRuleGroups]
|
||||
} else {
|
||||
$toast.error('导入规则失败!未知的数据类型!')
|
||||
$toast.error(t('setting.rule.importUnknownType'))
|
||||
}
|
||||
} catch (e) {
|
||||
$toast.error('导入规则失败!')
|
||||
$toast.error(t('setting.rule.importFailed'))
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@@ -272,8 +280,8 @@ function isValidValue(value: any, type: string): boolean {
|
||||
|
||||
function validateCustomRule(hasName: boolean, hasId: boolean, noDuplicates: boolean): boolean {
|
||||
if (!hasName || !hasId || !noDuplicates) {
|
||||
if (!noDuplicates) $toast.warning(`存在重名值`)
|
||||
if (!hasId) $toast.error(`导入失败!发现有规则不存在ID,可能属于优先级规则组!`)
|
||||
if (!noDuplicates) $toast.warning(t('setting.rule.duplicateValue'))
|
||||
if (!hasId) $toast.error(t('setting.rule.importNoId'))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -281,8 +289,8 @@ function validateCustomRule(hasName: boolean, hasId: boolean, noDuplicates: bool
|
||||
|
||||
function validateGroupRule(hasName: boolean, hasId: boolean, noDuplicates: boolean): boolean {
|
||||
if (!hasName || hasId || !noDuplicates) {
|
||||
if (!noDuplicates) $toast.warning(`存在重名值`)
|
||||
if (hasId) $toast.error(`导入失败!发现有规则存在相同ID,可能属于自定义规则!`)
|
||||
if (!noDuplicates) $toast.warning(t('setting.rule.duplicateValue'))
|
||||
if (hasId) $toast.error(t('setting.rule.importHasId'))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -367,8 +375,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>自定义规则</VCardTitle>
|
||||
<VCardSubtitle>自定义优先级规则项</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.rule.customRules') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.rule.customRulesDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<draggable
|
||||
@@ -391,7 +399,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" class="me-2" @click="saveCustomRules"> 保存 </VBtn>
|
||||
<VBtn type="submit" class="me-2" @click="saveCustomRules"> {{ t('common.save') }} </VBtn>
|
||||
<VBtnGroup density="comfortable">
|
||||
<VBtn color="success" variant="tonal" @click="addCustomRule">
|
||||
<VIcon icon="mdi-plus" />
|
||||
@@ -416,8 +424,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>优先级规则组</VCardTitle>
|
||||
<VCardSubtitle>预设优先级规则组,以便在搜索和订阅中使用。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.rule.priorityRuleGroups') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.rule.priorityRuleGroupsDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<draggable
|
||||
@@ -442,7 +450,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" class="me-2" @click="saveFilterRuleGroups"> 保存 </VBtn>
|
||||
<VBtn type="submit" class="me-2" @click="saveFilterRuleGroups"> {{ t('common.save') }} </VBtn>
|
||||
<VBtnGroup density="comfortable">
|
||||
<VBtn color="success" variant="tonal" @click="addFilterRuleGroup">
|
||||
<VIcon icon="mdi-plus" />
|
||||
@@ -466,7 +474,7 @@ onMounted(() => {
|
||||
<ImportCodeDialog
|
||||
v-if="importCodeDialog"
|
||||
v-model="importCodeDialog"
|
||||
:title="`导入${importCodeType === 'custom' ? '自定义规则' : '优先级规则组'}`"
|
||||
:title="importCodeType === 'custom' ? t('setting.rule.importCustomRules') : t('setting.rule.importRuleGroups')"
|
||||
:dataType="importCodeType"
|
||||
@close="importCodeDialog = false"
|
||||
@save="saveCodeString"
|
||||
@@ -475,8 +483,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>下载规则</VCardTitle>
|
||||
<VCardSubtitle>同时命中多个资源时择优下载。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.rule.downloadRules') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.rule.downloadRulesDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VForm>
|
||||
@@ -488,8 +496,8 @@ onMounted(() => {
|
||||
multiple
|
||||
clearable
|
||||
chips
|
||||
label="当前使用下载优先规则"
|
||||
hint="排在前面的优先级越高,未选择的项不纳入排序"
|
||||
:label="t('setting.rule.currentPriorityRules')"
|
||||
:hint="t('setting.rule.currentPriorityRulesHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -499,7 +507,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveTorrentPriority"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveTorrentPriority"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import type { ScheduleInfo } from '@/api/types'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -26,11 +30,11 @@ async function loadSchedulerList() {
|
||||
// 任务状态颜色
|
||||
function getSchedulerColor(status: string) {
|
||||
switch (status) {
|
||||
case '正在运行':
|
||||
case t('setting.scheduler.running'):
|
||||
return 'success'
|
||||
case '已停止':
|
||||
case t('setting.scheduler.stopped'):
|
||||
return 'error'
|
||||
case '等待':
|
||||
case t('setting.scheduler.waiting'):
|
||||
return ''
|
||||
default:
|
||||
return ''
|
||||
@@ -46,7 +50,7 @@ function runCommand(id: string) {
|
||||
jobid: id,
|
||||
},
|
||||
})
|
||||
$toast.success('定时作业执行请求提交成功!')
|
||||
$toast.success(t('setting.scheduler.executeSuccess'))
|
||||
// 1秒后刷新数据
|
||||
setTimeout(() => {
|
||||
loadSchedulerList()
|
||||
@@ -77,16 +81,16 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>定时作业</VCardTitle>
|
||||
<VCardSubtitle>包含系统内置服务以及插件提供的服务,手动执行不会影响作业正常的时间表。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.scheduler.title') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.scheduler.subtitle') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VTable class="text-no-wrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">提供者</th>
|
||||
<th scope="col">任务名称</th>
|
||||
<th scope="col">任务状态</th>
|
||||
<th scope="col">下一次执行时间</th>
|
||||
<th scope="col">{{ t('setting.scheduler.provider') }}</th>
|
||||
<th scope="col">{{ t('setting.scheduler.taskName') }}</th>
|
||||
<th scope="col">{{ t('setting.scheduler.taskStatus') }}</th>
|
||||
<th scope="col">{{ t('setting.scheduler.nextRunTime') }}</th>
|
||||
<th scope="col" />
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -107,16 +111,20 @@ onUnmounted(() => {
|
||||
{{ scheduler.next_run }}
|
||||
</td>
|
||||
<td>
|
||||
<VBtn size="small" :disabled="scheduler.status === '正在运行'" @click="runCommand(scheduler.id)">
|
||||
<VBtn
|
||||
size="small"
|
||||
:disabled="scheduler.status === t('setting.scheduler.running')"
|
||||
@click="runCommand(scheduler.id)"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon>mdi-play</VIcon>
|
||||
</template>
|
||||
执行
|
||||
{{ t('setting.scheduler.execute') }}
|
||||
</VBtn>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="schedulerList.length === 0">
|
||||
<td colspan="4" class="text-center">没有后台服务</td>
|
||||
<td colspan="4" class="text-center">{{ t('setting.scheduler.noService') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import type { FilterRuleGroup, Site } from '@/api/types'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -172,6 +173,8 @@ async function loadSystemSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
querySites()
|
||||
queryFilterRuleGroups()
|
||||
@@ -186,8 +189,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>基础设置</VCardTitle>
|
||||
<VCardSubtitle>设定数据源、规则组等基础信息。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.search.basicSettings') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.search.basicSettingsDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VRow>
|
||||
@@ -198,8 +201,8 @@ onMounted(() => {
|
||||
clearable
|
||||
chips
|
||||
:items="mediaSourcesDict"
|
||||
label="媒体搜索数据源"
|
||||
hint="搜索媒体信息时使用的数据源以及排序"
|
||||
:label="t('setting.search.mediaSource')"
|
||||
:hint="t('setting.search.mediaSourceHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -210,8 +213,8 @@ onMounted(() => {
|
||||
clearable
|
||||
chips
|
||||
:items="filterRuleGroupOptions"
|
||||
label="优先级规则组"
|
||||
hint="搜索媒体信息时按选定的过滤规则组对结果进行过滤"
|
||||
:label="t('setting.search.filterRuleGroup')"
|
||||
:hint="t('setting.search.filterRuleGroupHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -220,34 +223,34 @@ onMounted(() => {
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="SystemSettings.Basic.TORRENT_TAG"
|
||||
label="下载任务标签"
|
||||
:label="t('setting.search.downloadLabel')"
|
||||
placeholder="MOVIEPILOT"
|
||||
hint="MoviePilot添加的下载任务标签"
|
||||
:hint="t('setting.search.downloadLabelHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VCombobox
|
||||
v-model="SystemSettings.Basic.AUTO_DOWNLOAD_USER"
|
||||
label="远程搜索自动下载用户名单"
|
||||
placeholder="用户ID1,用户ID2"
|
||||
hint="使用Telegram、微信等搜索时是否自动下载,使用逗号分割,设置为 all 代表所有用户自动择优下载"
|
||||
:label="t('setting.search.downloadUser')"
|
||||
:placeholder="t('setting.search.downloadUserPlaceholder')"
|
||||
:hint="t('setting.search.downloadUserHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="SystemSettings.Basic.SEARCH_MULTIPLE_NAME"
|
||||
label="多名称资源搜索"
|
||||
hint="使用中英文等多个名称搜索站点资源并合并搜索结果,将会增加站点访问频率"
|
||||
:label="t('setting.search.multipleNameSearch')"
|
||||
:hint="t('setting.search.multipleNameSearchHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="SystemSettings.Basic.DOWNLOAD_SUBTITLE"
|
||||
label="下载站点字幕"
|
||||
hint="检查站点资源是否有独立的字幕文件,有则自动下载"
|
||||
:label="t('setting.search.downloadSubtitle')"
|
||||
:hint="t('setting.search.downloadSubtitleHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -256,7 +259,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveSearchSetting"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveSearchSetting"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
@@ -267,8 +270,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>搜索站点</VCardTitle>
|
||||
<VCardSubtitle> 只有选中的站点才会在搜索中使用。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.search.downloadSite') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.search.downloadSiteDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VChipGroup v-model="selectedSites" column multiple>
|
||||
@@ -287,7 +290,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveSelectedSites"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveSelectedSites"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import type { FilterRuleGroup, Site } from '@/api/types'
|
||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -24,8 +25,8 @@ const selectedBestVersionRuleGroup = ref([])
|
||||
|
||||
// 订阅模式选择项
|
||||
const subscribeModeItems = [
|
||||
{ title: '自动', value: 'spider' },
|
||||
{ title: '站点RSS', value: 'rss' },
|
||||
{ title: t('setting.subscribe.modes.auto'), value: 'spider' },
|
||||
{ title: t('setting.subscribe.modes.rss'), value: 'rss' },
|
||||
]
|
||||
|
||||
// 所有规则组列表
|
||||
@@ -41,13 +42,13 @@ const filterRuleGroupOptions = computed(() => {
|
||||
|
||||
// RSS运行周期选择项
|
||||
const rssIntervalItems = [
|
||||
{ title: '5分钟', value: 5 },
|
||||
{ title: '10分钟', value: 10 },
|
||||
{ title: '20分钟', value: 20 },
|
||||
{ title: '半小时', value: 30 },
|
||||
{ title: '1小时', value: 60 },
|
||||
{ title: '12小时', value: 720 },
|
||||
{ title: '1天', value: 1440 },
|
||||
{ title: t('setting.subscribe.intervals.min5'), value: 5 },
|
||||
{ title: t('setting.subscribe.intervals.min10'), value: 10 },
|
||||
{ title: t('setting.subscribe.intervals.min20'), value: 20 },
|
||||
{ title: t('setting.subscribe.intervals.min30'), value: 30 },
|
||||
{ title: t('setting.subscribe.intervals.hour1'), value: 60 },
|
||||
{ title: t('setting.subscribe.intervals.hour12'), value: 720 },
|
||||
{ title: t('setting.subscribe.intervals.day1'), value: 1440 },
|
||||
]
|
||||
|
||||
// 系统设置项
|
||||
@@ -99,8 +100,8 @@ async function saveSelectedRssSites() {
|
||||
try {
|
||||
const result1: { [key: string]: any } = await api.post('system/setting/RssSites', selectedRssSites.value)
|
||||
|
||||
if (result1.success) $toast.success('订阅站点保存成功')
|
||||
else $toast.error('订阅站点保存失败!')
|
||||
if (result1.success) $toast.success(t('setting.subscribe.saveSuccess'))
|
||||
else $toast.error(t('setting.subscribe.saveFailed'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -154,8 +155,8 @@ async function reloadSystem() {
|
||||
progressDialog.value = true
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.get('system/reload')
|
||||
if (result.success) $toast.success('系统配置已生效')
|
||||
else $toast.error('重载系统失败!')
|
||||
if (result.success) $toast.success(t('setting.system.reloadSuccess'))
|
||||
else $toast.error(t('setting.system.reloadFailed'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@@ -178,14 +179,16 @@ async function saveSubscribeSetting() {
|
||||
const result3 = await saveSystemSetting(SystemSettings.value.Basic)
|
||||
|
||||
if (result1.success && result2.success && result3) {
|
||||
$toast.success('订阅基础设置保存成功')
|
||||
$toast.success(t('setting.subscribe.settingsSaveSuccess'))
|
||||
await reloadSystem()
|
||||
} else $toast.error('订阅基础设置保存失败!')
|
||||
} else $toast.error(t('setting.subscribe.settingsSaveFailed'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
querySites()
|
||||
queryFilterRuleGroups()
|
||||
@@ -200,8 +203,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>基础设置</VCardTitle>
|
||||
<VCardSubtitle>设定订阅模式、周期等基础设置</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.subscribe.basicSettings') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.subscribe.basicSettingsDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VForm>
|
||||
@@ -210,8 +213,8 @@ onMounted(() => {
|
||||
<VSelect
|
||||
v-model="SystemSettings.Basic.SUBSCRIBE_MODE"
|
||||
:items="subscribeModeItems"
|
||||
label="订阅模式"
|
||||
hint="自动:自动爬取站点首页,站点RSS:通过站点RSS链接订阅"
|
||||
:label="t('setting.subscribe.mode')"
|
||||
:hint="t('setting.subscribe.modeHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -219,8 +222,8 @@ onMounted(() => {
|
||||
<VSelect
|
||||
v-model="SystemSettings.Basic.SUBSCRIBE_RSS_INTERVAL"
|
||||
:items="rssIntervalItems"
|
||||
label="站点RSS周期"
|
||||
hint="设置站点RSS运行周期,在订阅模式为`站点RSS`时生效"
|
||||
:label="t('setting.subscribe.rssInterval')"
|
||||
:hint="t('setting.subscribe.rssIntervalHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -231,8 +234,8 @@ onMounted(() => {
|
||||
chips
|
||||
multiple
|
||||
clearable
|
||||
label="订阅优先级规则组"
|
||||
hint="按选定的过滤规则组对订阅进行过滤"
|
||||
:label="t('setting.subscribe.filterRuleGroup')"
|
||||
:hint="t('setting.subscribe.filterRuleGroupHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -243,8 +246,8 @@ onMounted(() => {
|
||||
chips
|
||||
multiple
|
||||
clearable
|
||||
label="洗版优先级规则组"
|
||||
hint="按选定的过滤规则组对洗版订阅进行过滤"
|
||||
:label="t('setting.subscribe.bestVersionRuleGroup')"
|
||||
:hint="t('setting.subscribe.bestVersionRuleGroupHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -253,16 +256,16 @@ onMounted(() => {
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="SystemSettings.Basic.SUBSCRIBE_SEARCH"
|
||||
label="订阅定时搜索"
|
||||
hint="每隔24小时全站搜索,以补全订阅可能漏掉的资源"
|
||||
:label="t('setting.subscribe.timedSearch')"
|
||||
:hint="t('setting.subscribe.timedSearchHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="SystemSettings.Basic.LOCAL_EXISTS_SEARCH"
|
||||
label="检查本地媒体库资源"
|
||||
hint="检查存储盘是否存在资源,以避免重复下载"
|
||||
:label="t('setting.subscribe.checkLocalMedia')"
|
||||
:hint="t('setting.subscribe.checkLocalMediaHint')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -272,7 +275,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveSubscribeSetting"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveSubscribeSetting"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
@@ -283,8 +286,8 @@ onMounted(() => {
|
||||
<VCol cols="12">
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>订阅站点</VCardTitle>
|
||||
<VCardSubtitle>只有选中的站点才会在订阅中使用。</VCardSubtitle>
|
||||
<VCardTitle>{{ t('setting.subscribe.subscribeSites') }}</VCardTitle>
|
||||
<VCardSubtitle>{{ t('setting.subscribe.subscribeSitesDesc') }}</VCardSubtitle>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VChipGroup v-model="selectedRssSites" column multiple>
|
||||
@@ -303,7 +306,7 @@ onMounted(() => {
|
||||
<VCardText>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<div class="d-flex flex-wrap gap-4 mt-4">
|
||||
<VBtn type="submit" @click="saveSelectedRssSites"> 保存 </VBtn>
|
||||
<VBtn type="submit" @click="saveSelectedRssSites"> {{ t('common.save') }} </VBtn>
|
||||
</div>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
@@ -311,5 +314,5 @@ onMounted(() => {
|
||||
</VCol>
|
||||
</VRow>
|
||||
<!-- 进度框 -->
|
||||
<ProgressDialog v-if="progressDialog" v-model="progressDialog" text="正在应用配置..." />
|
||||
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="t('setting.system.reloading')" />
|
||||
</template>
|
||||
|
||||
@@ -532,10 +532,10 @@ onDeactivated(() => {
|
||||
<VMenu activator="parent" close-on-content-click>
|
||||
<VList>
|
||||
<VListItem @click="addDownloader('qbittorrent')">
|
||||
<VListItemTitle>Qbittorrent</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.system.qbittorrent') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addDownloader('transmission')">
|
||||
<VListItemTitle>Transmission</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.system.transmission') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
@@ -580,13 +580,13 @@ onDeactivated(() => {
|
||||
<VMenu activator="parent" close-on-content-click>
|
||||
<VList>
|
||||
<VListItem @click="addMediaServer('emby')">
|
||||
<VListItemTitle>Emby</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.system.emby') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addMediaServer('jellyfin')">
|
||||
<VListItemTitle>Jellyfin</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.system.jellyfin') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addMediaServer('plex')">
|
||||
<VListItemTitle>Plex</VListItemTitle>
|
||||
<VListItemTitle>{{ t('setting.system.plex') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addMediaServer('trimemedia')">
|
||||
<VListItemTitle>{{ t('setting.system.trimeMedia') }}</VListItemTitle>
|
||||
|
||||
Reference in New Issue
Block a user