feat: localize quality labels and add quality template token

This commit is contained in:
2026-05-01 07:16:03 +08:00
parent 0b8f2c9775
commit f0f9ed3456
9 changed files with 147 additions and 31 deletions
+78 -15
View File
@@ -6,9 +6,11 @@ import { useViewport } from "@/composables/useViewport";
import type { BatchLiveRoomsResult, ImportLiveRoomsRequest, ImportLiveRoomsResult, LiveRoom, RecordTask } from "@/types";
import {
autoStartDecisionLabelMap,
formatQualityLabel,
availabilityLabelMap,
currentRecordingStateLabelMap,
outputFormatLabelMap,
qualityOptionList,
recordingTemplateLabelMap,
saveModeLabelMap
} from "@/types";
@@ -89,7 +91,8 @@ const platformOptions = [
{ label: "虎牙", value: 3 }
];
const qualityOptions = ["origin", "FULL_HD", "HD", "SD"];
const qualityOptions = qualityOptionList;
const qualitySupportHint = "抖音和 Bilibili 支持按画质选流;虎牙暂未实现。若目标档位不可用,平台会自动回退到最接近的可用画质。";
const booleanOverrideOptions = [
{ label: "跟随全局", value: inheritValue },
{ label: "开启", value: "true" },
@@ -143,6 +146,35 @@ function getRoomsTableScrollWrap() {
shell.querySelector<HTMLElement>(".el-table__body-wrapper");
}
function getRoomsTableContentWidth(wrap: HTMLElement) {
const shell = roomsTableShellRef.value;
if (!shell) {
return wrap.scrollWidth;
}
const widths = [
wrap.scrollWidth,
wrap.firstElementChild?.scrollWidth ?? 0,
shell.querySelector<HTMLElement>(".el-table__body table")?.scrollWidth ?? 0,
shell.querySelector<HTMLElement>(".el-table__header table")?.scrollWidth ?? 0
];
const wrapRect = wrap.getBoundingClientRect();
let maxRight = 0;
shell.querySelectorAll<HTMLElement>(
".el-table__header th, .el-table__body td, .room-actions-cell, .config-summary, .auto-start-cell"
).forEach((element) => {
const rect = element.getBoundingClientRect();
maxRight = Math.max(maxRight, rect.right - wrapRect.left + wrap.scrollLeft);
});
widths.push(Math.ceil(maxRight) + 24);
return Math.max(...widths);
}
function handleRoomsTableBodyScroll() {
if (syncingRoomsTableProxy) {
return;
@@ -235,11 +267,11 @@ async function syncRoomsTableProxyScroll() {
return;
}
const scrollWidth = Math.max(wrap.scrollWidth, wrap.firstElementChild?.scrollWidth ?? 0);
const scrollWidth = getRoomsTableContentWidth(wrap);
const clientWidth = wrap.clientWidth;
const canScrollHorizontally = scrollWidth > clientWidth + 1;
roomsTableProxyInnerWidth.value = scrollWidth;
roomsTableProxyInnerWidth.value = canScrollHorizontally ? scrollWidth : 0;
showRoomsTableProxyScroll.value = canScrollHorizontally;
if (canScrollHorizontally && proxy && Math.abs(proxy.scrollLeft - wrap.scrollLeft) > 1) {
@@ -653,6 +685,10 @@ function getRoomAvatarText(room: LiveRoom) {
return source.slice(0, 1).toUpperCase();
}
function getQualityLabel(quality?: string | null) {
return formatQualityLabel(quality);
}
function autoStartDecisionLabel(code?: string) {
if (!code) {
return "未记录";
@@ -862,7 +898,7 @@ onBeforeUnmount(() => {
<div style="grid-column: 1 / -1;">
<dt>房间配置</dt>
<dd>
{{ row.effectiveSettings.preferredQuality }} ·
{{ getQualityLabel(row.effectiveSettings.preferredQuality) }} ·
{{ outputFormatLabelMap[row.effectiveSettings.outputFormat] }} ·
{{ saveModeLabelMap[row.effectiveSettings.saveMode] }} ·
{{ row.effectiveSettings.enableDanmakuRecording ? "弹幕开" : "弹幕关" }}
@@ -914,7 +950,7 @@ onBeforeUnmount(() => {
v-loading="loading"
:height="tableHeight"
class="premium-table rooms-table"
table-layout="auto"
table-layout="fixed"
row-key="id"
@selection-change="handleRoomSelectionChange"
>
@@ -982,10 +1018,10 @@ onBeforeUnmount(() => {
</template>
</el-table-column>
<el-table-column label="房间配置" min-width="240">
<el-table-column label="房间配置" width="280">
<template #default="{ row }">
<div class="config-summary">
<span>画质 {{ row.effectiveSettings.preferredQuality }}</span>
<span>画质 {{ getQualityLabel(row.effectiveSettings.preferredQuality) }}</span>
<span>{{ outputFormatLabelMap[row.effectiveSettings.outputFormat] }}</span>
<span>{{ saveModeLabelMap[row.effectiveSettings.saveMode] }}</span>
<span>{{ row.effectiveSettings.enableDanmakuRecording ? "弹幕开" : "弹幕关" }}</span>
@@ -1012,7 +1048,7 @@ onBeforeUnmount(() => {
</template>
</el-table-column>
<el-table-column label="操作" width="320">
<el-table-column label="操作" width="380">
<template #default="{ row }">
<div class="room-actions-cell">
<el-button size="small" @click="refreshRoom(row)">刷新</el-button>
@@ -1172,10 +1208,17 @@ onBeforeUnmount(() => {
<el-form label-position="top">
<el-form-item label="清晰度">
<el-select v-model="recordForm.preferredQuality">
<el-option v-for="option in qualityOptions" :key="option" :label="option" :value="option" />
<el-option
v-for="option in qualityOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
<div class="field-help">{{ qualitySupportHint }}</div>
<el-form-item label="输出格式">
<el-select v-model="recordForm.outputFormat">
<el-option
@@ -1241,10 +1284,17 @@ onBeforeUnmount(() => {
<el-form-item label="默认画质">
<el-select v-model="settingsForm.preferredQualityOverride">
<el-option label="跟随全局" :value="inheritValue" />
<el-option v-for="option in qualityOptions" :key="option" :label="option" :value="option" />
<el-option
v-for="option in qualityOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
<div class="field-help field-help--full">{{ qualitySupportHint }}</div>
<el-form-item label="默认输出格式">
<el-select v-model="settingsForm.outputFormatOverride">
<el-option label="跟随全局" :value="inheritValue" />
@@ -1454,7 +1504,7 @@ onBeforeUnmount(() => {
}
.rooms-table {
min-width: 1380px;
min-width: 1920px;
}
.rooms-table :deep(.el-table__cell) {
@@ -1462,7 +1512,7 @@ onBeforeUnmount(() => {
}
.rooms-table :deep(.cell) {
overflow: visible;
overflow: hidden;
}
.room-avatar {
@@ -1557,16 +1607,29 @@ onBeforeUnmount(() => {
}
.room-actions-cell {
display: flex;
align-items: center;
display: grid;
grid-template-columns: repeat(2, minmax(0, max-content));
gap: 8px;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
}
.room-actions-cell :deep(.el-button) {
margin: 0;
}
.field-help {
margin-top: -8px;
margin-bottom: 14px;
color: var(--text-muted);
font-size: 12px;
line-height: 1.6;
}
.field-help--full {
grid-column: 1 / -1;
}
.settings-note {
display: grid;
gap: 6px;