351 lines
9.4 KiB
Vue
351 lines
9.4 KiB
Vue
<!-- Author: fruit.com.cn -->
|
|
<!-- 后台转码档位与缩略图雪碧图配置 -->
|
|
|
|
<script setup lang="ts">
|
|
import { AppIcons } from '@/constants/icons'
|
|
import { useI18n } from '@/hooks/web/useI18n'
|
|
import PageHeading from '@/views/components/PageHeading.vue'
|
|
import { useTranscodeSettings } from './composables/useTranscodeSettings'
|
|
|
|
const { t } = useI18n()
|
|
const {
|
|
form,
|
|
formRef,
|
|
rules,
|
|
loading,
|
|
saving,
|
|
loadError,
|
|
canManage,
|
|
qualityRules,
|
|
positiveEvenRule,
|
|
positiveIntegerRule,
|
|
enabledRules,
|
|
loadProfile,
|
|
addRung,
|
|
deleteRung,
|
|
saveProfile
|
|
} = useTranscodeSettings()
|
|
</script>
|
|
|
|
<template>
|
|
<PageHeading
|
|
:eyebrow="t('transcodeSettings.eyebrow')"
|
|
:title="t('transcodeSettings.title')"
|
|
:description="t('transcodeSettings.description')"
|
|
>
|
|
<el-button :disabled="loading" @click="loadProfile">
|
|
<AppIcon :icon="AppIcons.refresh" />
|
|
{{ t('transcodeSettings.reload') }}
|
|
</el-button>
|
|
<el-button
|
|
type="primary"
|
|
class="primary-button"
|
|
:loading="saving"
|
|
:disabled="!canManage || loading"
|
|
@click="saveProfile"
|
|
>
|
|
<AppIcon :icon="AppIcons.check" />
|
|
{{ t('transcodeSettings.save') }}
|
|
</el-button>
|
|
</PageHeading>
|
|
|
|
<el-alert
|
|
v-if="loadError"
|
|
class="transcode-alert"
|
|
:title="loadError"
|
|
type="error"
|
|
show-icon
|
|
:closable="false"
|
|
/>
|
|
<el-alert
|
|
v-if="!canManage"
|
|
class="transcode-alert"
|
|
:title="t('transcodeSettings.noPermission')"
|
|
type="warning"
|
|
show-icon
|
|
:closable="false"
|
|
/>
|
|
|
|
<el-form
|
|
ref="formRef"
|
|
v-loading="loading"
|
|
:model="form"
|
|
:rules="rules"
|
|
label-position="top"
|
|
class="transcode-form"
|
|
>
|
|
<section class="panel transcode-panel">
|
|
<div class="transcode-section-heading">
|
|
<div>
|
|
<h2>{{ t('transcodeSettings.enabled') }}</h2>
|
|
<p>{{ t('transcodeSettings.enabledDescription') }}</p>
|
|
</div>
|
|
<el-switch v-model="form.enabled" size="large" />
|
|
</div>
|
|
<div class="transcode-grid transcode-grid--compact">
|
|
<el-form-item :label="t('transcodeSettings.segmentSeconds')" prop="segmentSeconds">
|
|
<el-input-number
|
|
v-model="form.segmentSeconds"
|
|
controls-position="right"
|
|
:min="2"
|
|
:max="10"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel transcode-panel">
|
|
<div class="transcode-section-heading">
|
|
<div>
|
|
<h2>{{ t('transcodeSettings.ladderTitle') }}</h2>
|
|
<p>{{ t('transcodeSettings.ladderDescription') }}</p>
|
|
</div>
|
|
<el-button type="primary" plain @click="addRung">
|
|
<AppIcon :icon="AppIcons.add" />
|
|
{{ t('transcodeSettings.addRung') }}
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table
|
|
:data="form.ladder"
|
|
border
|
|
class="transcode-table"
|
|
:empty-text="t('transcodeSettings.emptyLadder')"
|
|
>
|
|
<el-table-column type="index" width="60" label="#" />
|
|
<el-table-column :label="t('transcodeSettings.quality')" min-width="150">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.quality`"
|
|
:rules="qualityRules($index)"
|
|
class="table-form-item"
|
|
>
|
|
<el-input v-model="row.quality" maxlength="16" />
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column :label="t('transcodeSettings.width')" min-width="120">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.width`"
|
|
:rules="positiveEvenRule()"
|
|
class="table-form-item"
|
|
>
|
|
<el-input-number
|
|
v-model="row.width"
|
|
controls-position="right"
|
|
:min="2"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column :label="t('transcodeSettings.height')" min-width="120">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.height`"
|
|
:rules="positiveEvenRule()"
|
|
class="table-form-item"
|
|
>
|
|
<el-input-number
|
|
v-model="row.height"
|
|
controls-position="right"
|
|
:min="2"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column :label="t('transcodeSettings.videoBitrateKbps')" min-width="150">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.videoBitrateKbps`"
|
|
:rules="positiveIntegerRule()"
|
|
class="table-form-item"
|
|
>
|
|
<el-input-number
|
|
v-model="row.videoBitrateKbps"
|
|
controls-position="right"
|
|
:min="1"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column :label="t('transcodeSettings.audioBitrateKbps')" min-width="150">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.audioBitrateKbps`"
|
|
:rules="positiveIntegerRule()"
|
|
class="table-form-item"
|
|
>
|
|
<el-input-number
|
|
v-model="row.audioBitrateKbps"
|
|
controls-position="right"
|
|
:min="1"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column :label="t('transcodeSettings.rowEnabled')" width="100" align="center">
|
|
<template #default="{ row, $index }">
|
|
<el-form-item
|
|
:prop="`ladder.${$index}.enabled`"
|
|
:rules="enabledRules"
|
|
class="table-form-item table-form-item--center"
|
|
>
|
|
<el-switch v-model="row.enabled" />
|
|
</el-form-item>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="" width="72" align="center" fixed="right">
|
|
<template #default="{ $index }">
|
|
<el-tooltip :content="t('transcodeSettings.deleteRung')" placement="top">
|
|
<el-button circle type="danger" plain @click="deleteRung($index)">
|
|
<AppIcon :icon="AppIcons.delete" />
|
|
</el-button>
|
|
</el-tooltip>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</section>
|
|
|
|
<section class="panel transcode-panel">
|
|
<div class="transcode-section-heading">
|
|
<div>
|
|
<h2>{{ t('transcodeSettings.spriteTitle') }}</h2>
|
|
<p>{{ t('transcodeSettings.spriteDescription') }}</p>
|
|
</div>
|
|
<el-switch v-model="form.sprite.enabled" size="large" />
|
|
</div>
|
|
<div class="transcode-grid">
|
|
<el-form-item :label="t('transcodeSettings.intervalSeconds')" prop="sprite.intervalSeconds">
|
|
<el-input-number
|
|
v-model="form.sprite.intervalSeconds"
|
|
controls-position="right"
|
|
:min="1"
|
|
:max="10"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item :label="t('transcodeSettings.columns')" prop="sprite.columns">
|
|
<el-input-number
|
|
v-model="form.sprite.columns"
|
|
controls-position="right"
|
|
:min="5"
|
|
:max="20"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item :label="t('transcodeSettings.thumbWidth')" prop="sprite.thumbWidth">
|
|
<el-input-number
|
|
v-model="form.sprite.thumbWidth"
|
|
controls-position="right"
|
|
:min="120"
|
|
:max="240"
|
|
:precision="0"
|
|
/>
|
|
</el-form-item>
|
|
</div>
|
|
<div class="transcode-footer">
|
|
<el-button
|
|
type="primary"
|
|
class="primary-button"
|
|
:loading="saving"
|
|
:disabled="!canManage || loading"
|
|
@click="saveProfile"
|
|
>
|
|
<AppIcon :icon="AppIcons.check" />
|
|
{{ t('transcodeSettings.save') }}
|
|
</el-button>
|
|
</div>
|
|
</section>
|
|
</el-form>
|
|
</template>
|
|
|
|
<style scoped lang="less">
|
|
.transcode-alert {
|
|
margin-bottom: 14px;
|
|
}
|
|
|
|
.transcode-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
.transcode-panel {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.transcode-section-heading {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-bottom: 18px;
|
|
|
|
h2 {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
p {
|
|
margin: 6px 0 0;
|
|
line-height: 1.5;
|
|
color: var(--el-text-color-secondary);
|
|
}
|
|
}
|
|
|
|
.transcode-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(180px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.transcode-grid--compact {
|
|
grid-template-columns: minmax(180px, 320px);
|
|
}
|
|
|
|
.transcode-table {
|
|
width: 100%;
|
|
}
|
|
|
|
.table-form-item {
|
|
margin-bottom: 0;
|
|
|
|
:deep(.el-input-number) {
|
|
width: 100%;
|
|
}
|
|
|
|
:deep(.el-form-item__error) {
|
|
position: static;
|
|
margin-top: 4px;
|
|
}
|
|
}
|
|
|
|
.table-form-item--center {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.transcode-footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
margin-top: 18px;
|
|
}
|
|
|
|
@media (width <= 900px) {
|
|
.transcode-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.transcode-section-heading {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
</style>
|