mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-08 09:16:58 +08:00
feat(plugin): support responsive federated config controls (#521)
This commit is contained in:
@@ -46,6 +46,14 @@ const isRefreshed = ref(false)
|
|||||||
// 渲染模式: 'vuetify' 或 'vue'
|
// 渲染模式: 'vuetify' 或 'vue'
|
||||||
const renderMode = ref('vuetify')
|
const renderMode = ref('vuetify')
|
||||||
|
|
||||||
|
// 插件未声明布局偏好时沿用标准配置弹窗宽度。
|
||||||
|
const dialogMaxWidth = ref('60rem')
|
||||||
|
|
||||||
|
interface PluginConfigLayout {
|
||||||
|
/** 插件配置界面期望的最大宽度,使用合法 CSS 尺寸。 */
|
||||||
|
maxWidth?: string
|
||||||
|
}
|
||||||
|
|
||||||
// Vue 模式:动态加载的组件
|
// Vue 模式:动态加载的组件
|
||||||
const dynamicComponent = defineAsyncComponent({
|
const dynamicComponent = defineAsyncComponent({
|
||||||
// 工厂函数
|
// 工厂函数
|
||||||
@@ -89,6 +97,7 @@ async function loadPluginUIData() {
|
|||||||
pluginFormItems = []
|
pluginFormItems = []
|
||||||
pluginConfigForm.value = {}
|
pluginConfigForm.value = {}
|
||||||
renderMode.value = 'vuetify'
|
renderMode.value = 'vuetify'
|
||||||
|
dialogMaxWidth.value = '60rem'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取UI定义
|
// 获取UI定义
|
||||||
@@ -123,6 +132,12 @@ function handleVueComponentSave(newConfig: Record<string, any>) {
|
|||||||
savePluginConf()
|
savePluginConf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 联邦配置组件可按自身布局密度覆盖宿主弹窗宽度。
|
||||||
|
function handleVueComponentLayout(layout?: PluginConfigLayout | null) {
|
||||||
|
const maxWidth = typeof layout?.maxWidth === 'string' ? layout.maxWidth.trim() : ''
|
||||||
|
dialogMaxWidth.value = maxWidth || '60rem'
|
||||||
|
}
|
||||||
|
|
||||||
// 调用API保存配置数据
|
// 调用API保存配置数据
|
||||||
async function savePluginConf() {
|
async function savePluginConf() {
|
||||||
// 显示等待提示框
|
// 显示等待提示框
|
||||||
@@ -148,7 +163,7 @@ onBeforeMount(async () => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VDialog scrollable max-width="60rem" :fullscreen="!display.mdAndUp.value">
|
<VDialog scrollable :max-width="dialogMaxWidth" :fullscreen="!display.mdAndUp.value">
|
||||||
<!-- Vuetify 渲染模式 -->
|
<!-- Vuetify 渲染模式 -->
|
||||||
<VCard v-if="renderMode === 'vuetify'" :title="`${props.plugin?.plugin_name} - ${t('dialog.pluginConfig.title')}`">
|
<VCard v-if="renderMode === 'vuetify'" :title="`${props.plugin?.plugin_name} - ${t('dialog.pluginConfig.title')}`">
|
||||||
<VDialogCloseBtn @click="emit('close')" />
|
<VDialogCloseBtn @click="emit('close')" />
|
||||||
@@ -192,6 +207,7 @@ onBeforeMount(async () => {
|
|||||||
:initial-config="pluginConfigForm"
|
:initial-config="pluginConfigForm"
|
||||||
:api="api"
|
:api="api"
|
||||||
@save="handleVueComponentSave"
|
@save="handleVueComponentSave"
|
||||||
|
@layout="handleVueComponentLayout"
|
||||||
@switch="emit('switch')"
|
@switch="emit('switch')"
|
||||||
@close="emit('close')"
|
@close="emit('close')"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '* * * * *',
|
default: '* * * * *',
|
||||||
},
|
},
|
||||||
|
/** 是否允许直接清空 CRON。 */
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
@@ -39,7 +44,6 @@ function updateModelValue(value: string) {
|
|||||||
:modelValue="innerValue"
|
:modelValue="innerValue"
|
||||||
@update:modelValue="updateModelValue"
|
@update:modelValue="updateModelValue"
|
||||||
v-bind="{ ...menuprops, ...propsWithoutModelValue }"
|
v-bind="{ ...menuprops, ...propsWithoutModelValue }"
|
||||||
clearable
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</CronInput>
|
</CronInput>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { locale } = useI18n()
|
||||||
|
|
||||||
const menu = ref(false)
|
const menu = ref(false)
|
||||||
const currentCron = ref(props.modelValue)
|
const currentCron = ref(props.modelValue)
|
||||||
@@ -14,6 +15,27 @@ const menuRoot = ref<HTMLElement>()
|
|||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
const menuContentClass = `cron-input-menu-${instance?.uid ?? 'default'}`
|
const menuContentClass = `cron-input-menu-${instance?.uid ?? 'default'}`
|
||||||
const menuContentSelector = `.${menuContentClass}`
|
const menuContentSelector = `.${menuContentClass}`
|
||||||
|
const normalizedLocale = computed(() => locale.value.toLowerCase().replace(/_/g, '-'))
|
||||||
|
const cronLocale = computed(() => normalizedLocale.value.startsWith('zh') ? 'zh-cn' : 'en')
|
||||||
|
// vue-js-cron 没有内置繁体中文,只需覆盖简体词典中会显示的 Cron 专有字词。
|
||||||
|
const cronCustomLocale = computed(() => normalizedLocale.value === 'zh-tw' ? {
|
||||||
|
'*': {
|
||||||
|
day: {
|
||||||
|
value: { text: '{{value.alt}}號' },
|
||||||
|
range: { text: '{{start.alt}}號-{{end.alt}}號' },
|
||||||
|
},
|
||||||
|
dayOfWeek: { empty: { text: '一週的每一天' } },
|
||||||
|
hour: { empty: { text: '每小時' } },
|
||||||
|
minute: { empty: { text: '每分鐘' } },
|
||||||
|
},
|
||||||
|
hour: {
|
||||||
|
text: '小時',
|
||||||
|
minute: { '*': { suffix: '分鐘' } },
|
||||||
|
},
|
||||||
|
week: { text: '週' },
|
||||||
|
'q-minute': { text: '分鐘' },
|
||||||
|
'q-hour': { text: '小時' },
|
||||||
|
} : undefined)
|
||||||
|
|
||||||
function isCronMenuTarget(target: EventTarget | null) {
|
function isCronMenuTarget(target: EventTarget | null) {
|
||||||
if (!(target instanceof Element)) return false
|
if (!(target instanceof Element)) return false
|
||||||
@@ -72,7 +94,14 @@ watch(
|
|||||||
</template>
|
</template>
|
||||||
<VList>
|
<VList>
|
||||||
<VListItem>
|
<VListItem>
|
||||||
<VCronVuetify v-model="currentCron" locale="zh-CN" :chip-props="{ color: 'success' }" class="mt-1" />
|
<VCronVuetify
|
||||||
|
:key="locale"
|
||||||
|
v-model="currentCron"
|
||||||
|
:chip-props="{ color: 'success' }"
|
||||||
|
class="mt-1"
|
||||||
|
:custom-locale="cronCustomLocale"
|
||||||
|
:locale="cronLocale"
|
||||||
|
/>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
|
|||||||
Reference in New Issue
Block a user