|
|
|
@ -1,6 +1,11 @@
|
|
|
|
<template>
|
|
|
|
<template>
|
|
|
|
<main class="config-root config-page">
|
|
|
|
<main class="config-root config-page">
|
|
|
|
<el-page-header content="配置同步屏窗口" />
|
|
|
|
<div class="config-top-status">
|
|
|
|
|
|
|
|
<span class="socket-status" :class="socketRunning ? 'running' : 'stopped'">
|
|
|
|
|
|
|
|
<i class="socket-dot" />
|
|
|
|
|
|
|
|
Socket {{ socketRunning ? "运行中" : "未启动" }} (9501)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-collapse v-model="activePanels" class="config-collapse">
|
|
|
|
<el-collapse v-model="activePanels" class="config-collapse">
|
|
|
|
<el-collapse-item name="base">
|
|
|
|
<el-collapse-item name="base">
|
|
|
|
@ -96,6 +101,11 @@
|
|
|
|
<el-input-number v-model="area.windowId" :min="1" />
|
|
|
|
<el-input-number v-model="area.windowId" :min="1" />
|
|
|
|
</el-form-item>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
|
|
<el-form-item label="时钟窗口">
|
|
|
|
|
|
|
|
<el-switch v-model="area.isClockWindow" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
<el-col :span="6">
|
|
|
|
<el-col :span="6">
|
|
|
|
<el-form-item label="宽度">
|
|
|
|
<el-form-item label="宽度">
|
|
|
|
<el-input-number v-model="area.width" :min="1" />
|
|
|
|
<el-input-number v-model="area.width" :min="1" />
|
|
|
|
@ -145,6 +155,21 @@
|
|
|
|
<el-input-number v-model="area.windowNumberStyle.fontWeight" :min="100" :step="100" />
|
|
|
|
<el-input-number v-model="area.windowNumberStyle.fontWeight" :min="100" :step="100" />
|
|
|
|
</el-form-item>
|
|
|
|
</el-form-item>
|
|
|
|
</el-col>
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="圆圈大小">
|
|
|
|
|
|
|
|
<el-input-number v-model="area.windowNumberCircleStyle.size" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="边框粗细">
|
|
|
|
|
|
|
|
<el-input-number v-model="area.windowNumberCircleStyle.borderWidth" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="圆角半径">
|
|
|
|
|
|
|
|
<el-input-number v-model="area.windowNumberCircleStyle.borderRadius" :min="0" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
</el-row>
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-divider content-position="left">文本区域(占比 2.5,静态/动态=1:1)</el-divider>
|
|
|
|
<el-divider content-position="left">文本区域(占比 2.5,静态/动态=1:1)</el-divider>
|
|
|
|
@ -196,6 +221,83 @@
|
|
|
|
</el-card>
|
|
|
|
</el-card>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</el-collapse-item>
|
|
|
|
</el-collapse-item>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-collapse-item name="subtitles">
|
|
|
|
|
|
|
|
<template #title>
|
|
|
|
|
|
|
|
<div class="card-header row-between">
|
|
|
|
|
|
|
|
<span>滚动字幕区域</span>
|
|
|
|
|
|
|
|
<el-button type="primary" plain size="small" @click.stop="addSubtitleArea">
|
|
|
|
|
|
|
|
添加滚动字幕
|
|
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<div class="panel-scroll area-list">
|
|
|
|
|
|
|
|
<el-card
|
|
|
|
|
|
|
|
v-for="(subtitle, index) in draft.subtitleAreas"
|
|
|
|
|
|
|
|
:key="subtitle.id"
|
|
|
|
|
|
|
|
class="area-item"
|
|
|
|
|
|
|
|
shadow="never"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
|
|
<div class="row-between">
|
|
|
|
|
|
|
|
<strong>字幕区域 {{ index + 1 }}</strong>
|
|
|
|
|
|
|
|
<el-button type="danger" link @click="removeSubtitleArea(index)">删除</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<el-form label-width="120px" size="small">
|
|
|
|
|
|
|
|
<el-row :gutter="12">
|
|
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
|
|
<el-form-item label="宽度">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.width" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
|
|
<el-form-item label="高度">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.height" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
|
|
<el-form-item label="X">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.x" :min="0" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
|
|
|
<el-form-item label="Y">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.y" :min="0" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
<el-row :gutter="12">
|
|
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
|
|
<el-form-item label="字幕文本">
|
|
|
|
|
|
|
|
<el-input v-model="subtitle.text" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="字号">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.textStyle.fontSize" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="颜色">
|
|
|
|
|
|
|
|
<el-input v-model="subtitle.textStyle.color" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="粗细">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.textStyle.fontWeight" :min="100" :step="100" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="4">
|
|
|
|
|
|
|
|
<el-form-item label="滚动速度">
|
|
|
|
|
|
|
|
<el-input-number v-model="subtitle.speed" :min="1" />
|
|
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-collapse-item>
|
|
|
|
</el-collapse>
|
|
|
|
</el-collapse>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="actions-row">
|
|
|
|
<div class="actions-row">
|
|
|
|
@ -206,10 +308,6 @@
|
|
|
|
<el-button type="danger" plain :disabled="!socketRunning" @click="stopSocketService">
|
|
|
|
<el-button type="danger" plain :disabled="!socketRunning" @click="stopSocketService">
|
|
|
|
停止 Socket 服务
|
|
|
|
停止 Socket 服务
|
|
|
|
</el-button>
|
|
|
|
</el-button>
|
|
|
|
<span class="socket-status" :class="socketRunning ? 'running' : 'stopped'">
|
|
|
|
|
|
|
|
<i class="socket-dot" />
|
|
|
|
|
|
|
|
Socket {{ socketRunning ? "运行中" : "未启动" }} (9501)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="save-hint">{{ saveMessage }}</span>
|
|
|
|
<span class="save-hint">{{ saveMessage }}</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
</main>
|
|
|
|
@ -220,7 +318,12 @@ import { computed, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
|
|
|
import { currentMonitor } from "@tauri-apps/api/window";
|
|
|
|
import { currentMonitor } from "@tauri-apps/api/window";
|
|
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
|
|
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
|
|
|
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
|
|
|
import type { BroadcastConfig, ChildWindowAreaConfig, SegmentConfigItem } from "../models/config";
|
|
|
|
import type {
|
|
|
|
|
|
|
|
BroadcastConfig,
|
|
|
|
|
|
|
|
ChildWindowAreaConfig,
|
|
|
|
|
|
|
|
SegmentConfigItem,
|
|
|
|
|
|
|
|
SubtitleAreaConfig,
|
|
|
|
|
|
|
|
} from "../models/config";
|
|
|
|
import { DEFAULT_BROADCAST_CONFIG } from "../models/config";
|
|
|
|
import { DEFAULT_BROADCAST_CONFIG } from "../models/config";
|
|
|
|
import { useBroadcastConfig } from "../composables/useBroadcastConfig";
|
|
|
|
import { useBroadcastConfig } from "../composables/useBroadcastConfig";
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
@ -239,7 +342,7 @@ interface SocketStatusPayload {
|
|
|
|
const screenWidth = ref(normalizeScreenWidth(window.screen.width || 1920));
|
|
|
|
const screenWidth = ref(normalizeScreenWidth(window.screen.width || 1920));
|
|
|
|
const { config, patchConfig } = useBroadcastConfig();
|
|
|
|
const { config, patchConfig } = useBroadcastConfig();
|
|
|
|
const saveMessage = ref("修改后请点击“保存配置”。");
|
|
|
|
const saveMessage = ref("修改后请点击“保存配置”。");
|
|
|
|
const activePanels = ref(["base", "segments", "areas"]);
|
|
|
|
const activePanels = ref(["base", "segments", "areas", "subtitles"]);
|
|
|
|
const socketRunning = ref(false);
|
|
|
|
const socketRunning = ref(false);
|
|
|
|
// 避免 store -> draft 回填触发“未保存”提示。
|
|
|
|
// 避免 store -> draft 回填触发“未保存”提示。
|
|
|
|
const syncingFromStore = ref(false);
|
|
|
|
const syncingFromStore = ref(false);
|
|
|
|
@ -267,12 +370,20 @@ function cloneSegments(segments: SegmentConfigItem[]) {
|
|
|
|
function cloneWindowAreas(areas: ChildWindowAreaConfig[]) {
|
|
|
|
function cloneWindowAreas(areas: ChildWindowAreaConfig[]) {
|
|
|
|
return areas.map((item) => ({
|
|
|
|
return areas.map((item) => ({
|
|
|
|
...item,
|
|
|
|
...item,
|
|
|
|
|
|
|
|
windowNumberCircleStyle: { ...item.windowNumberCircleStyle },
|
|
|
|
windowNumberStyle: { ...item.windowNumberStyle },
|
|
|
|
windowNumberStyle: { ...item.windowNumberStyle },
|
|
|
|
staticTextStyle: { ...item.staticTextStyle },
|
|
|
|
staticTextStyle: { ...item.staticTextStyle },
|
|
|
|
dynamicTextStyle: { ...item.dynamicTextStyle },
|
|
|
|
dynamicTextStyle: { ...item.dynamicTextStyle },
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function cloneSubtitleAreas(areas: SubtitleAreaConfig[]) {
|
|
|
|
|
|
|
|
return areas.map((item) => ({
|
|
|
|
|
|
|
|
...item,
|
|
|
|
|
|
|
|
textStyle: { ...item.textStyle },
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeStyle(style: { fontSize: number; color: string; fontWeight: number }) {
|
|
|
|
function normalizeStyle(style: { fontSize: number; color: string; fontWeight: number }) {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
fontSize: Number.isFinite(style.fontSize) && style.fontSize > 0 ? Math.floor(style.fontSize) : 14,
|
|
|
|
fontSize: Number.isFinite(style.fontSize) && style.fontSize > 0 ? Math.floor(style.fontSize) : 14,
|
|
|
|
@ -286,12 +397,18 @@ function createDefaultWindowArea(index: number): ChildWindowAreaConfig {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
id: `area-${Date.now()}-${index}`,
|
|
|
|
id: `area-${Date.now()}-${index}`,
|
|
|
|
windowId: index + 1,
|
|
|
|
windowId: index + 1,
|
|
|
|
|
|
|
|
isClockWindow: false,
|
|
|
|
width: 220,
|
|
|
|
width: 220,
|
|
|
|
height: 48,
|
|
|
|
height: 48,
|
|
|
|
x: 0,
|
|
|
|
x: 0,
|
|
|
|
y: index * 50,
|
|
|
|
y: index * 50,
|
|
|
|
windowNumber: String(index + 1),
|
|
|
|
windowNumber: String(index + 1),
|
|
|
|
windowNumberCircle: false,
|
|
|
|
windowNumberCircle: false,
|
|
|
|
|
|
|
|
windowNumberCircleStyle: {
|
|
|
|
|
|
|
|
size: 36,
|
|
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
|
|
borderRadius: 18,
|
|
|
|
|
|
|
|
},
|
|
|
|
windowNumberStyle: {
|
|
|
|
windowNumberStyle: {
|
|
|
|
fontSize: 16,
|
|
|
|
fontSize: 16,
|
|
|
|
color: "#ffffff",
|
|
|
|
color: "#ffffff",
|
|
|
|
@ -312,6 +429,23 @@ function createDefaultWindowArea(index: number): ChildWindowAreaConfig {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function createDefaultSubtitleArea(index: number): SubtitleAreaConfig {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
id: `subtitle-${Date.now()}-${index}`,
|
|
|
|
|
|
|
|
width: 420,
|
|
|
|
|
|
|
|
height: 28,
|
|
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
|
|
text: "欢迎使用同步屏系统",
|
|
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
|
|
|
color: "#ffffff",
|
|
|
|
|
|
|
|
fontWeight: 500,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
speed: 80,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 添加一个新分段,默认放在当前末段之后。
|
|
|
|
* 添加一个新分段,默认放在当前末段之后。
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@ -350,6 +484,16 @@ function removeWindowArea(index: number) {
|
|
|
|
saveMessage.value = "已修改,点击“保存配置”后生效。";
|
|
|
|
saveMessage.value = "已修改,点击“保存配置”后生效。";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function addSubtitleArea() {
|
|
|
|
|
|
|
|
draft.subtitleAreas.push(createDefaultSubtitleArea(draft.subtitleAreas.length));
|
|
|
|
|
|
|
|
saveMessage.value = "已修改,点击“保存配置”后生效。";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function removeSubtitleArea(index: number) {
|
|
|
|
|
|
|
|
draft.subtitleAreas.splice(index, 1);
|
|
|
|
|
|
|
|
saveMessage.value = "已修改,点击“保存配置”后生效。";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function startSocketService() {
|
|
|
|
async function startSocketService() {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const result = await invoke<SocketStatusPayload>("start_socket_service");
|
|
|
|
const result = await invoke<SocketStatusPayload>("start_socket_service");
|
|
|
|
@ -379,8 +523,10 @@ async function saveConfig() {
|
|
|
|
const segments = draft.segments.map((item, index) =>
|
|
|
|
const segments = draft.segments.map((item, index) =>
|
|
|
|
normalizeSegmentConfigItem(item, index, screenWidth.value, segmentHeight),
|
|
|
|
normalizeSegmentConfigItem(item, index, screenWidth.value, segmentHeight),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
const windowAreas = draft.windowAreas.map((area, index) => ({
|
|
|
|
const windowAreas = draft.windowAreas.map((area, index) => {
|
|
|
|
id: area.id || `area-${index + 1}`,
|
|
|
|
const circleStyle = area.windowNumberCircleStyle ?? { size: 36, borderWidth: 1, borderRadius: 18 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
id: area.id || `area-${index + 1}`,
|
|
|
|
windowId:
|
|
|
|
windowId:
|
|
|
|
Number.isFinite(area.windowId) && area.windowId > 0 ? Math.floor(area.windowId) : index + 1,
|
|
|
|
Number.isFinite(area.windowId) && area.windowId > 0 ? Math.floor(area.windowId) : index + 1,
|
|
|
|
width: Number.isFinite(area.width) && area.width > 0 ? Math.floor(area.width) : 220,
|
|
|
|
width: Number.isFinite(area.width) && area.width > 0 ? Math.floor(area.width) : 220,
|
|
|
|
@ -388,12 +534,35 @@ async function saveConfig() {
|
|
|
|
x: Number.isFinite(area.x) ? Math.max(0, Math.floor(area.x)) : 0,
|
|
|
|
x: Number.isFinite(area.x) ? Math.max(0, Math.floor(area.x)) : 0,
|
|
|
|
y: Number.isFinite(area.y) ? Math.max(0, Math.floor(area.y)) : 0,
|
|
|
|
y: Number.isFinite(area.y) ? Math.max(0, Math.floor(area.y)) : 0,
|
|
|
|
windowNumber: area.windowNumber || String(index + 1),
|
|
|
|
windowNumber: area.windowNumber || String(index + 1),
|
|
|
|
|
|
|
|
isClockWindow: area.isClockWindow === true,
|
|
|
|
windowNumberCircle: area.windowNumberCircle === true,
|
|
|
|
windowNumberCircle: area.windowNumberCircle === true,
|
|
|
|
|
|
|
|
windowNumberCircleStyle: {
|
|
|
|
|
|
|
|
size: Number.isFinite(circleStyle.size) && circleStyle.size > 0 ? Math.floor(circleStyle.size) : 36,
|
|
|
|
|
|
|
|
borderWidth:
|
|
|
|
|
|
|
|
Number.isFinite(circleStyle.borderWidth) && circleStyle.borderWidth > 0
|
|
|
|
|
|
|
|
? Math.floor(circleStyle.borderWidth)
|
|
|
|
|
|
|
|
: 1,
|
|
|
|
|
|
|
|
borderRadius:
|
|
|
|
|
|
|
|
Number.isFinite(circleStyle.borderRadius) && circleStyle.borderRadius >= 0
|
|
|
|
|
|
|
|
? Math.floor(circleStyle.borderRadius)
|
|
|
|
|
|
|
|
: 18,
|
|
|
|
|
|
|
|
},
|
|
|
|
windowNumberStyle: normalizeStyle(area.windowNumberStyle),
|
|
|
|
windowNumberStyle: normalizeStyle(area.windowNumberStyle),
|
|
|
|
staticText: area.staticText || "静态文本",
|
|
|
|
staticText: area.staticText || "静态文本",
|
|
|
|
staticTextStyle: normalizeStyle(area.staticTextStyle),
|
|
|
|
staticTextStyle: normalizeStyle(area.staticTextStyle),
|
|
|
|
dynamicText: area.dynamicText || "动态文本",
|
|
|
|
dynamicText: area.dynamicText || "动态文本",
|
|
|
|
dynamicTextStyle: normalizeStyle(area.dynamicTextStyle),
|
|
|
|
dynamicTextStyle: normalizeStyle(area.dynamicTextStyle),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
const subtitleAreas = draft.subtitleAreas.map((area, index) => ({
|
|
|
|
|
|
|
|
id: area.id || `subtitle-${index + 1}`,
|
|
|
|
|
|
|
|
width: Number.isFinite(area.width) && area.width > 0 ? Math.floor(area.width) : 420,
|
|
|
|
|
|
|
|
height: Number.isFinite(area.height) && area.height > 0 ? Math.floor(area.height) : 28,
|
|
|
|
|
|
|
|
x: Number.isFinite(area.x) ? Math.max(0, Math.floor(area.x)) : 0,
|
|
|
|
|
|
|
|
y: Number.isFinite(area.y) ? Math.max(0, Math.floor(area.y)) : 0,
|
|
|
|
|
|
|
|
text: area.text || "欢迎使用同步屏系统",
|
|
|
|
|
|
|
|
textStyle: normalizeStyle(area.textStyle),
|
|
|
|
|
|
|
|
speed: Number.isFinite(area.speed) && area.speed > 0 ? area.speed : 80,
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
await patchConfig({
|
|
|
|
await patchConfig({
|
|
|
|
totalWidth,
|
|
|
|
totalWidth,
|
|
|
|
@ -401,6 +570,7 @@ async function saveConfig() {
|
|
|
|
showRuler: draft.showRuler,
|
|
|
|
showRuler: draft.showRuler,
|
|
|
|
segments,
|
|
|
|
segments,
|
|
|
|
windowAreas,
|
|
|
|
windowAreas,
|
|
|
|
|
|
|
|
subtitleAreas,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
saveMessage.value = "保存成功,已写入配置文件并实时应用。";
|
|
|
|
saveMessage.value = "保存成功,已写入配置文件并实时应用。";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -414,6 +584,7 @@ watch(
|
|
|
|
draft.showRuler = next.showRuler;
|
|
|
|
draft.showRuler = next.showRuler;
|
|
|
|
draft.segments = cloneSegments(next.segments);
|
|
|
|
draft.segments = cloneSegments(next.segments);
|
|
|
|
draft.windowAreas = cloneWindowAreas(next.windowAreas);
|
|
|
|
draft.windowAreas = cloneWindowAreas(next.windowAreas);
|
|
|
|
|
|
|
|
draft.subtitleAreas = cloneSubtitleAreas(next.subtitleAreas);
|
|
|
|
syncingFromStore.value = false;
|
|
|
|
syncingFromStore.value = false;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ immediate: true, deep: true },
|
|
|
|
{ immediate: true, deep: true },
|
|
|
|
@ -427,10 +598,15 @@ watch(
|
|
|
|
segments: draft.segments.map((item) => ({ ...item })),
|
|
|
|
segments: draft.segments.map((item) => ({ ...item })),
|
|
|
|
windowAreas: draft.windowAreas.map((item) => ({
|
|
|
|
windowAreas: draft.windowAreas.map((item) => ({
|
|
|
|
...item,
|
|
|
|
...item,
|
|
|
|
|
|
|
|
windowNumberCircleStyle: { ...item.windowNumberCircleStyle },
|
|
|
|
windowNumberStyle: { ...item.windowNumberStyle },
|
|
|
|
windowNumberStyle: { ...item.windowNumberStyle },
|
|
|
|
staticTextStyle: { ...item.staticTextStyle },
|
|
|
|
staticTextStyle: { ...item.staticTextStyle },
|
|
|
|
dynamicTextStyle: { ...item.dynamicTextStyle },
|
|
|
|
dynamicTextStyle: { ...item.dynamicTextStyle },
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
|
|
|
|
subtitleAreas: draft.subtitleAreas.map((item) => ({
|
|
|
|
|
|
|
|
...item,
|
|
|
|
|
|
|
|
textStyle: { ...item.textStyle },
|
|
|
|
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
() => {
|
|
|
|
() => {
|
|
|
|
if (!syncingFromStore.value) {
|
|
|
|
if (!syncingFromStore.value) {
|
|
|
|
|