fix-settings-i18n-garbled-encoding-and-english-text

This commit is contained in:
2026-05-17 15:58:21 +08:00
parent 850c55f5da
commit 78f02978fd
+89 -87
View File
@@ -376,7 +376,7 @@ const eventScriptEnvironmentExamples = [
const eventScriptModeOptions = [ const eventScriptModeOptions = [
{ label: "璺緞", value: "path" }, { label: "璺緞", value: "path" },
{ label: "鑴氭湰鏂囨湰", value: "inline" } { label: "脚本文本", value: "inline" }
]; ];
const uploadTargetOptions = [ const uploadTargetOptions = [
@@ -459,12 +459,12 @@ const canSendTestWebhook = computed(() => Boolean(form.webhookUrl.trim()));
const segmentedExamplePath = computed(() => { const segmentedExamplePath = computed(() => {
const extension = form.defaultOutputFormat === 1 ? "ts" : "mp4"; const extension = form.defaultOutputFormat === 1 ? "ts" : "mp4";
return `Douyin/2026/04/15/涓绘挱鍚?221530_origin_涓绘挱鍚峗鐩存挱鏍囬_123456789_00001.${extension}`; return `Douyin/2026/04/15/主播名?221530_origin_主播名峗直播标题_123456789_00001.${extension}`;
}); });
const nestedSegmentedExamplePath = computed(() => { const nestedSegmentedExamplePath = computed(() => {
const extension = form.defaultOutputFormat === 1 ? "ts" : "mp4"; const extension = form.defaultOutputFormat === 1 ? "ts" : "mp4";
return `Douyin/origin/2026/04/15/涓绘挱鍚?221530_origin_涓绘挱鍚峗鐩存挱鏍囬_123456789/221530_origin_涓绘挱鍚峗鐩存挱鏍囬_123456789_00001.${extension}`; return `Douyin/origin/2026/04/15/主播名?221530_origin_主播名峗直播标题_123456789/221530_origin_主播名峗直播标题_123456789_00001.${extension}`;
}); });
async function loadSettings() { async function loadSettings() {
@@ -492,11 +492,11 @@ const pwdForm = reactive({
const pwdRules = { const pwdRules = {
currentPassword: [{ required: true, message: "Please enter the current password", trigger: "blur" }], currentPassword: [{ required: true, message: "Please enter the current password", trigger: "blur" }],
newPassword: [ newPassword: [
{ required: true, message: "璇疯緭鍏ユ柊瀵嗙爜", trigger: "blur" }, { required: true, message: "请输入新密码", trigger: "blur" },
{ min: 6, message: "Password must be at least 6 characters", trigger: "blur" } { min: 6, message: "Password must be at least 6 characters", trigger: "blur" }
], ],
confirmPassword: [ confirmPassword: [
{ required: true, message: "璇峰啀娆¤緭鍏ユ柊瀵嗙爜", trigger: "blur" }, { required: true, message: "请再次输入新密码", trigger: "blur" },
{ {
validator: (_rule: unknown, value: string, callback: (error?: Error) => void) => { validator: (_rule: unknown, value: string, callback: (error?: Error) => void) => {
if (value !== pwdForm.newPassword) { if (value !== pwdForm.newPassword) {
@@ -587,7 +587,7 @@ async function testEventScript(eventType: ScriptEventType) {
} catch (error) { } catch (error) {
const result: EventScriptTestResult = { const result: EventScriptTestResult = {
success: false, success: false,
message: getApiErrorMessage(error, "浜嬩欢鑴氭湰娴嬭瘯澶辫触") message: getApiErrorMessage(error, "事件脚本测试失败")
}; };
scriptTestResults[eventType] = result; scriptTestResults[eventType] = result;
ElMessage.error(result.message); ElMessage.error(result.message);
@@ -611,7 +611,7 @@ async function testWebhook() {
} catch (error) { } catch (error) {
const result: WebhookTestResult = { const result: WebhookTestResult = {
success: false, success: false,
message: getApiErrorMessage(error, "Webhook 娴嬭瘯澶辫触") message: getApiErrorMessage(error, "Webhook 测试失败")
}; };
webhookTestResult.value = result; webhookTestResult.value = result;
ElMessage.error(result.message); ElMessage.error(result.message);
@@ -737,7 +737,7 @@ async function exportSettingsBackup() {
URL.revokeObjectURL(downloadUrl); URL.revokeObjectURL(downloadUrl);
ElMessage.success("Settings backup exported."); ElMessage.success("Settings backup exported.");
} catch (error) { } catch (error) {
ElMessage.error(getApiErrorMessage(error, "绯荤粺璁剧疆瀵煎嚭澶辫触")); ElMessage.error(getApiErrorMessage(error, "系统设置导出失败"));
} finally { } finally {
exportingSettings.value = false; exportingSettings.value = false;
} }
@@ -764,7 +764,7 @@ async function importSettingsBackup(event: Event) {
Object.assign(form, data); Object.assign(form, data);
ElMessage.success("Settings imported from backup."); ElMessage.success("Settings imported from backup.");
} catch (error) { } catch (error) {
ElMessage.error(getApiErrorMessage(error, "绯荤粺璁剧疆瀵煎叆澶辫触")); ElMessage.error(getApiErrorMessage(error, "系统设置导入失败"));
} finally { } finally {
importingSettings.value = false; importingSettings.value = false;
} }
@@ -963,7 +963,7 @@ watch(
<el-tab-pane label="褰曞埗" name="recording"> <el-tab-pane label="褰曞埗" name="recording">
<el-card class="surface-card settings-card" shadow="never"> <el-card class="surface-card settings-card" shadow="never">
<h3 class="section-title">褰曞埗鍩虹</h3> <h3 class="section-title">褰曞埗鍩虹</h3>
<p class="section-subtitle">Default quality, output format, segmentation, ffmpeg templates, and network tolerance settings are managed here.</p> <p class="section-subtitle">默认画质输出格式分段策略ffmpeg 模板和网络容错等录制基础参数在此集中管理</p>
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
@@ -973,12 +973,12 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Output root"> <el-form-item label="输出根目录">
<el-input v-model="form.outputRoot" /> <el-input v-model="form.outputRoot" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Default quality"> <el-form-item label="默认画质">
<el-select v-model="form.defaultQuality"> <el-select v-model="form.defaultQuality">
<el-option <el-option
v-for="option in qualityOptions" v-for="option in qualityOptions"
@@ -990,7 +990,7 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="杈撳嚭鏍煎紡"> <el-form-item label="输出格式">
<el-select v-model="form.defaultOutputFormat"> <el-select v-model="form.defaultOutputFormat">
<el-option <el-option
v-for="(label, value) in outputFormatLabelMap" v-for="(label, value) in outputFormatLabelMap"
@@ -1002,7 +1002,7 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="淇濆瓨妯″紡"> <el-form-item label="保存模式">
<el-select v-model="form.saveMode"> <el-select v-model="form.saveMode">
<el-option <el-option
v-for="(label, value) in saveModeLabelMap" v-for="(label, value) in saveModeLabelMap"
@@ -1014,7 +1014,7 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="褰曞埗妯℃澘"> <el-form-item label="录制模板">
<el-select v-model="form.recordingTemplate"> <el-select v-model="form.recordingTemplate">
<el-option <el-option
v-for="(label, value) in recordingTemplateLabelMap" v-for="(label, value) in recordingTemplateLabelMap"
@@ -1026,32 +1026,32 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="鍒嗘鏃堕暱锛堝垎閽燂級"> <el-form-item label="分段时长(分钟)">
<el-input-number v-model="form.segmentDurationMinutes" :min="1" :max="720" /> <el-input-number v-model="form.segmentDurationMinutes" :min="1" :max="720" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Max concurrent transcode tasks"> <el-form-item label="最大并发转码任务数">
<el-input-number v-model="form.maxConcurrentFfmpegTranscodeTasks" :min="1" :max="16" /> <el-input-number v-model="form.maxConcurrentFfmpegTranscodeTasks" :min="1" :max="16" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="MP4 杞爜瓒呮椂锛堝垎閽燂級"> <el-form-item label="MP4 转码超时(分钟)">
<el-input-number v-model="form.mp4FinalizeTimeoutMinutes" :min="1" :max="1440" /> <el-input-number v-model="form.mp4FinalizeTimeoutMinutes" :min="1" :max="1440" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="鏈€澶ч噸杩炲欢杩燂紙绉掞級"> <el-form-item label="最大重连延迟(秒)">
<el-input-number v-model="form.reconnectDelayMaxSeconds" :min="1" :max="300" /> <el-input-number v-model="form.reconnectDelayMaxSeconds" :min="1" :max="300" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="璇诲啓瓒呮椂锛堟绉掞級"> <el-form-item label="读写超时(毫秒)">
<el-input-number v-model="form.readWriteTimeoutMilliseconds" :min="1000" :max="60000000" /> <el-input-number v-model="form.readWriteTimeoutMilliseconds" :min="1000" :max="60000000" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="鍚敤 ffmpeg 鑷姩閲嶈繛"> <el-form-item label="启用 ffmpeg 自动重连">
<el-switch v-model="form.enableAutoReconnect" /> <el-switch v-model="form.enableAutoReconnect" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1064,18 +1064,18 @@ watch(
</el-card> </el-card>
<el-card class="surface-card settings-card" shadow="never"> <el-card class="surface-card settings-card" shadow="never">
<h3 class="section-title">瀛樺偍淇濇姢</h3> <h3 class="section-title">存储保护</h3>
<p class="section-subtitle">Pause recording and MP4 finalization below the threshold, then resume once free space recovers.</p> <p class="section-subtitle">当磁盘空闲空间低于阈值时暂停录制和 MP4 转码空间恢复后自动继续</p>
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="鍚敤瀛樺偍淇濇姢"> <el-form-item label="启用存储保护">
<el-switch v-model="form.enableStorageGuard" /> <el-switch v-model="form.enableStorageGuard" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Pause below free space (MB)"> <el-form-item label="暂停阈值:空闲空间低于 (MB)">
<el-input-number <el-input-number
v-model="form.pauseRecordingWhenFreeSpaceBelowMegabytes" v-model="form.pauseRecordingWhenFreeSpaceBelowMegabytes"
:min="0" :min="0"
@@ -1085,7 +1085,7 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Resume above free space (MB)"> <el-form-item label="恢复阈值:空闲空间高于 (MB)">
<el-input-number <el-input-number
v-model="form.resumeRecordingWhenFreeSpaceAboveMegabytes" v-model="form.resumeRecordingWhenFreeSpaceAboveMegabytes"
:min="0" :min="0"
@@ -1098,32 +1098,33 @@ watch(
</el-form> </el-form>
<div class="helper-panel"> <div class="helper-panel">
鎭㈠闃堝煎缓璁珮浜庢殏鍋滈槇鍊硷紝閬垮厤纾佺洏绌洪棿鍦ㄤ复鐣屽奸檮杩戝弽澶嶆姈鍔ㄣ侻P4 爜浼氶澶栧崰鐢ㄤ腑闂?TS 鏂囦欢绌洪棿銆? </div> 恢复阈值建议高于暂停阈值避免磁盘空间在临界值附近反复抖动MP4 转码会额外占用中间 TS 文件空间
</div>
</el-card> </el-card>
<el-card class="surface-card settings-card" shadow="never"> <el-card class="surface-card settings-card" shadow="never">
<h3 class="section-title">淇濈暀娓呯悊</h3> <h3 class="section-title">保留清理</h3>
<p class="section-subtitle">Clean up inactive sessions, tasks, results, and logs by retention age, with optional file deletion.</p> <p class="section-subtitle">按保留天数清理不活跃的会话任务结果和日志可选删除磁盘文件</p>
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="鍚敤鑷姩娓呯悊"> <el-form-item label="启用自动清理">
<el-switch v-model="form.enableRetentionCleanup" /> <el-switch v-model="form.enableRetentionCleanup" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="淇濈暀澶╂暟"> <el-form-item label="保留天数">
<el-input-number v-model="form.retentionDays" :min="1" :max="3650" /> <el-input-number v-model="form.retentionDays" :min="1" :max="3650" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="鍒犻櫎纾佺洏鏂囦欢"> <el-form-item label="删除磁盘文件">
<el-switch v-model="form.retentionDeleteFiles" /> <el-switch v-model="form.retentionDeleteFiles" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Video file condition"> <el-form-item label="视频文件条件">
<el-select v-model="form.retentionVideoFileCondition" style="width: 100%"> <el-select v-model="form.retentionVideoFileCondition" style="width: 100%">
<el-option <el-option
v-for="option in retentionVideoFileOptions" v-for="option in retentionVideoFileOptions"
@@ -1135,8 +1136,8 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Task status condition (all segments)"> <el-form-item label="任务状态条件(所有分段)">
<el-select v-model="form.retentionTaskStatuses" multiple placeholder="Any status" style="width: 100%"> <el-select v-model="form.retentionTaskStatuses" multiple placeholder="任意状态" style="width: 100%">
<el-option <el-option
v-for="option in retentionTaskStatusOptions" v-for="option in retentionTaskStatusOptions"
:key="option.value" :key="option.value"
@@ -1151,7 +1152,7 @@ watch(
<div class="action-strip"> <div class="action-strip">
<div class="helper-text">Run now and the daily retention cleanup use the same saved rules. Save this section first if you just changed the filters.</div> <div class="helper-text">Run now and the daily retention cleanup use the same saved rules. Save this section first if you just changed the filters.</div>
<el-button :loading="runningRetentionCleanup" @click="runRetentionCleanup">Run cleanup now</el-button> <el-button :loading="runningRetentionCleanup" @click="runRetentionCleanup">立即执行清理</el-button>
</div> </div>
<div <div
@@ -1244,7 +1245,7 @@ watch(
</el-form> </el-form>
<div class="example-box"> <div class="example-box">
<div class="example-box__label">绀轰緥杈撳嚭</div> <div class="example-box__label">示例输出</div>
<div class="monospace example-box__value">榛樿鍒嗘锛歿{ segmentedExamplePath }}</div> <div class="monospace example-box__value">榛樿鍒嗘锛歿{ segmentedExamplePath }}</div>
<div class="monospace example-box__value">綍妯澘鍚?{fileStem}锛歿{ nestedSegmentedExamplePath }}</div> <div class="monospace example-box__value">綍妯澘鍚?{fileStem}锛歿{ nestedSegmentedExamplePath }}</div>
</div> </div>
@@ -1267,26 +1268,26 @@ watch(
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="Polling and upload" name="polling"> <el-tab-pane label="轮询与上传" name="polling">
<el-card class="surface-card settings-card" shadow="never"> <el-card class="surface-card settings-card" shadow="never">
<h3 class="section-title">鍚庡彴宸</h3> <h3 class="section-title">后台巡检</h3>
<p class="section-subtitle">Control scheduled live-status checks and automatic recording starts when a room goes live.</p> <p class="section-subtitle">控制定时直播状态检查和直播间开播时自动开始录制</p>
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="鍚敤鍚庡彴宸℃"> <el-form-item label="启用后台巡检">
<el-switch v-model="form.enableBackgroundPolling" /> <el-switch v-model="form.enableBackgroundPolling" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="妫€娴嬪埌寮€鎾悗鑷姩褰曞埗"> <el-form-item label="检测到开播后自动录制">
<el-switch v-model="form.autoStartRecordingOnLive" /> <el-switch v-model="form.autoStartRecordingOnLive" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Polling interval (s)"> <el-form-item label="轮询间隔(秒)">
<el-input-number v-model="form.pollingIntervalSeconds" :min="10" :max="3600" /> <el-input-number v-model="form.pollingIntervalSeconds" :min="10" :max="3600" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1346,7 +1347,7 @@ watch(
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Endpoint"> <el-form-item label="端点">
<el-input v-model="form.webDavUpload.endpoint" placeholder="https://dav.example.com" /> <el-input v-model="form.webDavUpload.endpoint" placeholder="https://dav.example.com" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1356,12 +1357,12 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Username"> <el-form-item label="用户名">
<el-input v-model="form.webDavUpload.username" /> <el-input v-model="form.webDavUpload.username" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="瀵嗙爜"> <el-form-item label="密码">
<el-input v-model="form.webDavUpload.password" type="password" show-password /> <el-input v-model="form.webDavUpload.password" type="password" show-password />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1380,17 +1381,17 @@ watch(
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Endpoint"> <el-form-item label="端点">
<el-input v-model="form.s3Upload.endpoint" placeholder="https://s3.example.com" /> <el-input v-model="form.s3Upload.endpoint" placeholder="https://s3.example.com" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Bucket"> <el-form-item label="存储桶">
<el-input v-model="form.s3Upload.bucket" /> <el-input v-model="form.s3Upload.bucket" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Region"> <el-form-item label="区域">
<el-input v-model="form.s3Upload.region" placeholder="auto / us-east-1" /> <el-input v-model="form.s3Upload.region" placeholder="auto / us-east-1" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1400,17 +1401,17 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Access Key"> <el-form-item label="访问密钥">
<el-input v-model="form.s3Upload.accessKey" /> <el-input v-model="form.s3Upload.accessKey" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Secret Key"> <el-form-item label="秘密密钥">
<el-input v-model="form.s3Upload.secretKey" type="password" show-password /> <el-input v-model="form.s3Upload.secretKey" type="password" show-password />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Force Path Style"> <el-form-item label="强制路径样式">
<el-switch v-model="form.s3Upload.forcePathStyle" /> <el-switch v-model="form.s3Upload.forcePathStyle" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1423,7 +1424,7 @@ watch(
</el-card> </el-card>
<el-card v-if="false" class="surface-card settings-card settings-grid__full" shadow="never"> <el-card v-if="false" class="surface-card settings-card settings-grid__full" shadow="never">
<h3 class="section-title">骞冲彴浠g悊</h3> <h3 class="section-title">平台代理</h3>
<p class="section-subtitle">These proxies only affect platform-side status checks and stream requests, not email, webhook, or file uploads.</p> <p class="section-subtitle">These proxies only affect platform-side status checks and stream requests, not email, webhook, or file uploads.</p>
<div v-if="false" class="event-script-grid"> <div v-if="false" class="event-script-grid">
@@ -1435,7 +1436,7 @@ watch(
</div> </div>
<el-switch v-model="form.douyinProxy.enabled" /> <el-switch v-model="form.douyinProxy.enabled" />
</div> </div>
<el-form-item label="浠g悊鍦板潃"> <el-form-item label="代理地址">
<el-input v-model="form.douyinProxy.proxyUrl" placeholder="http://127.0.0.1:7890" /> <el-input v-model="form.douyinProxy.proxyUrl" placeholder="http://127.0.0.1:7890" />
</el-form-item> </el-form-item>
</div> </div>
@@ -1448,7 +1449,7 @@ watch(
</div> </div>
<el-switch v-model="form.bilibiliProxy.enabled" /> <el-switch v-model="form.bilibiliProxy.enabled" />
</div> </div>
<el-form-item label="浠g悊鍦板潃"> <el-form-item label="代理地址">
<el-input v-model="form.bilibiliProxy.proxyUrl" placeholder="http://127.0.0.1:7890" /> <el-input v-model="form.bilibiliProxy.proxyUrl" placeholder="http://127.0.0.1:7890" />
</el-form-item> </el-form-item>
</div> </div>
@@ -1461,7 +1462,7 @@ watch(
</div> </div>
<el-switch v-model="form.huyaProxy.enabled" /> <el-switch v-model="form.huyaProxy.enabled" />
</div> </div>
<el-form-item label="浠g悊鍦板潃"> <el-form-item label="代理地址">
<el-input v-model="form.huyaProxy.proxyUrl" placeholder="http://127.0.0.1:7890" /> <el-input v-model="form.huyaProxy.proxyUrl" placeholder="http://127.0.0.1:7890" />
</el-form-item> </el-form-item>
</div> </div>
@@ -1469,22 +1470,23 @@ watch(
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="浜嬩欢鑴氭湰" name="scripts"> <el-tab-pane label="事件脚本" name="scripts">
<el-card class="surface-card settings-card settings-grid__full" shadow="never"> <el-card class="surface-card settings-card settings-grid__full" shadow="never">
<h3 class="section-title">浜嬩欢鑴氭湰</h3> <h3 class="section-title">事件脚本</h3>
<p class="section-subtitle"> <p class="section-subtitle">
佷笅鎾佸垎鐗囧畬鎴愭椂閮藉彲浠ユ墽琛岃剼鏈傝剼鏈敮鎸佽矾寰勬ā寮忓拰鐩存帴濉啓鏂囨湰妯紡锛涙祴璇曟寜閽細鐩存帴鐢ㄥ綋鍓嶈鍗曞兼墽琛岋紝涓嶈姹傚厛淇濆瓨銆? </p> 开播下播分片完成时都可以执行脚本脚本支持路径模式和直接填写文本模式测试按钮会直接用当前表单值执行不要求先保存
</p>
<el-form label-position="top"> <el-form label-position="top">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="鍚敤浜嬩欢鑴氭湰"> <el-form-item label="启用事件脚本">
<el-switch v-model="form.enableEventScripts" /> <el-switch v-model="form.enableEventScripts" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="Script timeout (s)"> <el-form-item label="脚本超时(秒)">
<el-input-number v-model="form.eventScriptTimeoutSeconds" :min="1" :max="3600" /> <el-input-number v-model="form.eventScriptTimeoutSeconds" :min="1" :max="3600" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1495,8 +1497,8 @@ watch(
<div class="event-script-section"> <div class="event-script-section">
<div class="event-script-section__header"> <div class="event-script-section__header">
<div> <div>
<h4 class="event-script-section__title">Live started</h4> <h4 class="event-script-section__title">开播</h4>
<p class="event-script-section__subtitle">Triggered when the room first enters the online state.</p> <p class="event-script-section__subtitle">当直播间首次进入开播状态时触发</p>
</div> </div>
<div class="event-script-section__actions"> <div class="event-script-section__actions">
<el-switch v-model="form.enableLiveStartedScript" inline-prompt active-text="On" inactive-text="Off" /> <el-switch v-model="form.enableLiveStartedScript" inline-prompt active-text="On" inactive-text="Off" />
@@ -1516,14 +1518,14 @@ watch(
:disabled="!canTestScript('live_started')" :disabled="!canTestScript('live_started')"
@click="testEventScript('live_started')" @click="testEventScript('live_started')"
> >
娴嬭瘯鑴氭湰 测试脚本
</el-button> </el-button>
</div> </div>
</div> </div>
<el-form-item v-if="form.liveStartedScriptMode === 'path'" label="鑴氭湰璺緞"> <el-form-item v-if="form.liveStartedScriptMode === 'path'" label="鑴氭湰璺緞">
<el-input v-model="form.liveStartedScriptPath" placeholder="/app/scripts/live-started.sh" /> <el-input v-model="form.liveStartedScriptPath" placeholder="/app/scripts/live-started.sh" />
</el-form-item> </el-form-item>
<el-form-item v-else label="鑴氭湰鏂囨湰"> <el-form-item v-else label="脚本文本">
<el-input <el-input
v-model="form.liveStartedScriptContent" v-model="form.liveStartedScriptContent"
type="textarea" type="textarea"
@@ -1541,7 +1543,7 @@ watch(
{{ scriptTestResults.live_started?.detail }} {{ scriptTestResults.live_started?.detail }}
</div> </div>
<div v-if="scriptTestResults.live_started?.customLogOutput" class="test-result__detail"> <div v-if="scriptTestResults.live_started?.customLogOutput" class="test-result__detail">
畾涔夋棩蹇楄緭鍑猴細{{ scriptTestResults.live_started?.customLogOutput }} 自定义日志输出{{ scriptTestResults.live_started?.customLogOutput }}
</div> </div>
</div> </div>
</div> </div>
@@ -1549,8 +1551,8 @@ watch(
<div class="event-script-section"> <div class="event-script-section">
<div class="event-script-section__header"> <div class="event-script-section__header">
<div> <div>
<h4 class="event-script-section__title">涓嬫挱</h4> <h4 class="event-script-section__title">下播</h4>
<p class="event-script-section__subtitle">Triggered when the room changes from online back to offline.</p> <p class="event-script-section__subtitle">当直播间从开播状态回到离线状态时触发</p>
</div> </div>
<div class="event-script-section__actions"> <div class="event-script-section__actions">
<el-switch v-model="form.enableLiveEndedScript" inline-prompt active-text="On" inactive-text="Off" /> <el-switch v-model="form.enableLiveEndedScript" inline-prompt active-text="On" inactive-text="Off" />
@@ -1570,14 +1572,14 @@ watch(
:disabled="!canTestScript('live_ended')" :disabled="!canTestScript('live_ended')"
@click="testEventScript('live_ended')" @click="testEventScript('live_ended')"
> >
娴嬭瘯鑴氭湰 测试脚本
</el-button> </el-button>
</div> </div>
</div> </div>
<el-form-item v-if="form.liveEndedScriptMode === 'path'" label="鑴氭湰璺緞"> <el-form-item v-if="form.liveEndedScriptMode === 'path'" label="鑴氭湰璺緞">
<el-input v-model="form.liveEndedScriptPath" placeholder="/app/scripts/live-ended.sh" /> <el-input v-model="form.liveEndedScriptPath" placeholder="/app/scripts/live-ended.sh" />
</el-form-item> </el-form-item>
<el-form-item v-else label="鑴氭湰鏂囨湰"> <el-form-item v-else label="脚本文本">
<el-input <el-input
v-model="form.liveEndedScriptContent" v-model="form.liveEndedScriptContent"
type="textarea" type="textarea"
@@ -1603,8 +1605,8 @@ watch(
<div class="event-script-section event-script-section--full"> <div class="event-script-section event-script-section--full">
<div class="event-script-section__header"> <div class="event-script-section__header">
<div> <div>
<h4 class="event-script-section__title">鍒嗙墖瀹屾垚</h4> <h4 class="event-script-section__title">分片完成</h4>
<p class="event-script-section__subtitle">Triggered after MP4 finalization completes and the segment status becomes completed.</p> <p class="event-script-section__subtitle"> MP4 转码最终化完成且分段状态变为已完成时触发</p>
</div> </div>
<div class="event-script-section__actions"> <div class="event-script-section__actions">
<el-switch v-model="form.enableSegmentCompletedScript" inline-prompt active-text="On" inactive-text="Off" /> <el-switch v-model="form.enableSegmentCompletedScript" inline-prompt active-text="On" inactive-text="Off" />
@@ -1624,14 +1626,14 @@ watch(
:disabled="!canTestScript('segment_completed')" :disabled="!canTestScript('segment_completed')"
@click="testEventScript('segment_completed')" @click="testEventScript('segment_completed')"
> >
娴嬭瘯鑴氭湰 测试脚本
</el-button> </el-button>
</div> </div>
</div> </div>
<el-form-item v-if="form.segmentCompletedScriptMode === 'path'" label="鑴氭湰璺緞"> <el-form-item v-if="form.segmentCompletedScriptMode === 'path'" label="脚本路径">
<el-input v-model="form.segmentCompletedScriptPath" placeholder="/app/scripts/segment-completed.sh" /> <el-input v-model="form.segmentCompletedScriptPath" placeholder="/app/scripts/segment-completed.sh" />
</el-form-item> </el-form-item>
<el-form-item v-else label="鑴氭湰鏂囨湰"> <el-form-item v-else label="脚本文本">
<el-input <el-input
v-model="form.segmentCompletedScriptContent" v-model="form.segmentCompletedScriptContent"
type="textarea" type="textarea"
@@ -1712,12 +1714,12 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="寮傚父閫氱煡"> <el-form-item label="异常通知">
<el-switch v-model="form.notifyWebhookOnException" /> <el-switch v-model="form.notifyWebhookOnException" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="Timeout (s)"> <el-form-item label="超时(秒)">
<el-input-number v-model="form.webhookTimeoutSeconds" :min="1" :max="300" /> <el-input-number v-model="form.webhookTimeoutSeconds" :min="1" :max="300" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1751,7 +1753,7 @@ watch(
</el-row> </el-row>
</el-form> </el-form>
<div class="template-help"> <div class="template-help">
<div class="template-help__label">Webhook 鍙橀噺</div> <div class="template-help__label">Webhook 变量</div>
<div class="token-list"> <div class="token-list">
<span v-for="token in webhookTemplateTokens" :key="token" class="token-chip">{{ token }}</span> <span v-for="token in webhookTemplateTokens" :key="token" class="token-chip">{{ token }}</span>
</div> </div>
@@ -1759,7 +1761,7 @@ watch(
<div class="action-strip"> <div class="action-strip">
<div class="helper-text">The test sends a sample live_started payload, including sample event script output, using the current URL, headers, and timeout values from this form.</div> <div class="helper-text">The test sends a sample live_started payload, including sample event script output, using the current URL, headers, and timeout values from this form.</div>
<el-button :loading="testingWebhook" :disabled="!canSendTestWebhook" @click="testWebhook">娴嬭瘯 Webhook</el-button> <el-button :loading="testingWebhook" :disabled="!canSendTestWebhook" @click="testWebhook">测试 Webhook</el-button>
</div> </div>
<div v-if="webhookTestResult" class="test-result" :class="webhookTestResult.success ? 'test-result--success' : 'test-result--warning'"> <div v-if="webhookTestResult" class="test-result" :class="webhookTestResult.success ? 'test-result--success' : 'test-result--warning'">
@@ -1790,7 +1792,7 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="寮傚父鎻愰啋"> <el-form-item label="异常提醒">
<el-switch v-model="form.notifyOnException" /> <el-switch v-model="form.notifyOnException" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1817,12 +1819,12 @@ watch(
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="SMTP 瀵嗙爜"> <el-form-item label="SMTP 密码">
<el-input v-model="form.emailPassword" type="password" show-password /> <el-input v-model="form.emailPassword" type="password" show-password />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="鍙戜欢鍦板潃"> <el-form-item label="发件地址">
<el-input v-model="form.emailFromAddress" placeholder="noreply@example.com" /> <el-input v-model="form.emailFromAddress" placeholder="noreply@example.com" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -1861,7 +1863,7 @@ watch(
<div class="template-section"> <div class="template-section">
<div class="template-section__header"> <div class="template-section__header">
<div> <div>
<h4 class="template-section__title">寮傚父鎻愰啋</h4> <h4 class="template-section__title">异常提醒</h4>
<p class="template-section__subtitle">Exception emails inject source, summary, detail, task context values, and optional event script output into the HTML body.</p> <p class="template-section__subtitle">Exception emails inject source, summary, detail, task context values, and optional event script output into the HTML body.</p>
</div> </div>
</div> </div>
@@ -1942,7 +1944,7 @@ watch(
</div> </div>
<el-form label-position="top"> <el-form label-position="top">
<el-form-item label="Proxy URL"> <el-form-item label="代理 URL">
<el-input <el-input
v-model="form.platformRequestSettings[platform.key].proxy.proxyUrl" v-model="form.platformRequestSettings[platform.key].proxy.proxyUrl"
placeholder="http://127.0.0.1:7890" placeholder="http://127.0.0.1:7890"
@@ -2004,10 +2006,10 @@ watch(
<div class="settings-savebar" :style="savebarStyle"> <div class="settings-savebar" :style="savebarStyle">
<div class="settings-savebar__content"> <div class="settings-savebar__content">
<div class="settings-savebar__copy"> <div class="settings-savebar__copy">
<div class="settings-savebar__title">褰撳墠淇敼涓嶄細鑷姩淇濆瓨</div> <div class="settings-savebar__title">当前修改不会自动保存</div>
<div class="settings-savebar__subtitle">You can save the current settings from anywhere on this page.</div> <div class="settings-savebar__subtitle">您可以在此页面任意位置保存当前设置</div>
</div> </div>
<el-button type="primary" :loading="saving" @click="saveSettings">淇濆瓨璁剧疆</el-button> <el-button type="primary" :loading="saving" @click="saveSettings">保存设置</el-button>
</div> </div>
</div> </div>
</div> </div>