This commit is contained in:
zpc 2025-03-28 02:39:13 +08:00
parent b00924a691
commit 7cf247a873
7 changed files with 839 additions and 214 deletions

View File

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShengShengBuXi.ConsoleApp", "ShengShengBuXi.ConsoleApp.csproj", "{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9BAF9C30-5594-4165-981C-6FACBF081E8D}
EndGlobalSection
EndGlobal

View File

@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text.Json;
using Newtonsoft.Json;
@ -91,7 +92,99 @@ namespace ShengShengBuXi.Hubs
/// </summary>
private static readonly int _sentenceHistoryLimit = 20;
// 客户端注册信息
private static Dictionary<string, ClientInfo> _clientsDict = new Dictionary<string, ClientInfo>();
// 用于线程安全访问
private static object _clientsLock = new object();
// 文本显示队列
private static List<DisplayText> _displayTextList = new List<DisplayText>();
private static object _displayTextListLock = new object();
// 监控文本列表
private static List<MonitorText> _monitorTextList = new List<MonitorText>();
private static object _monitorTextListLock = new object();
// 配置信息
private static string _displayConfig = "{}";
private static object _displayConfigLock = new object();
// 管理员配置保存路径
private static readonly string ConfigDirectory = Path.Combine(Directory.GetCurrentDirectory(), "config");
private static readonly string DisplayConfigPath = Path.Combine(ConfigDirectory, "display.json");
// 用于初始化配置
static AudioHub()
{
// 确保配置目录存在
if (!Directory.Exists(ConfigDirectory))
{
Directory.CreateDirectory(ConfigDirectory);
}
// 加载显示配置
LoadDisplayConfig();
}
// 加载显示配置
private static void LoadDisplayConfig()
{
try
{
if (File.Exists(DisplayConfigPath))
{
string configJson = File.ReadAllText(DisplayConfigPath);
lock (_displayConfigLock)
{
_displayConfig = configJson;
}
Console.WriteLine("加载显示配置成功");
}
else
{
// 创建默认配置
string defaultConfig = @"{
""leftContainer"": {
""turnPageHeight"": 0.8,
""fontSize"": ""16px"",
""typewriterSpeed"": 50
},
""rightContainer"": {
""fontSize"": ""24px"",
""fontWeight"": ""normal"",
""fontStyle"": ""normal"",
""typewriterSpeed"": 50
},
""waterEffect"": {
""enabled"": true,
""minInterval"": 800,
""maxInterval"": 2000,
""simultaneousDrops"": 3,
""fadeOutSpeed"": 0.1,
""centerBias"": 0.5,
""largeDrop"": {
""probability"": 0.2,
""size"": 9
}
}
}";
lock (_displayConfigLock)
{
_displayConfig = defaultConfig;
}
// 保存默认配置
File.WriteAllText(DisplayConfigPath, defaultConfig);
Console.WriteLine("创建默认显示配置成功");
}
}
catch (Exception ex)
{
Console.WriteLine($"加载显示配置出错: {ex.Message}");
}
}
/// <summary>
/// 初始化音频Hub
/// </summary>
@ -1328,5 +1421,76 @@ namespace ShengShengBuXi.Hubs
_logger.LogInformation($"客户端获取当前显示模式: {Context.ConnectionId}, 类型: {clientInfo.ClientType}");
return _configurationService.CurrentConfig.DisplayType;
}
/// <summary>
/// 获取显示配置
/// </summary>
/// <returns>显示配置的JSON字符串</returns>
public string GetDisplayConfig()
{
lock (_displayConfigLock)
{
return _displayConfig;
}
}
/// <summary>
/// 保存显示配置
/// </summary>
/// <param name="configJson">配置的JSON字符串</param>
/// <returns>是否保存成功</returns>
public async Task<bool> SaveDisplayConfig(string configJson)
{
try
{
// 尝试解析JSON以验证格式
JsonDocument.Parse(configJson);
// 保存到文件
await File.WriteAllTextAsync(DisplayConfigPath, configJson);
// 更新内存中的配置
lock (_displayConfigLock)
{
_displayConfig = configJson;
}
// 通知所有显示客户端
await NotifyDisplayConfig();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"保存显示配置出错: {ex.Message}");
return false;
}
}
/// <summary>
/// 通知所有显示客户端更新配置
/// </summary>
private async Task NotifyDisplayConfig()
{
string configJson;
lock (_displayConfigLock)
{
configJson = _displayConfig;
}
List<string> displayClientIds = new List<string>();
lock (_clients)
{
displayClientIds = _clients
.Where(c => c.Value.ClientType.ToString() == "Display")
.Select(c => c.Key)
.ToList();
}
foreach (var clientId in displayClientIds)
{
await Clients.Client(clientId).SendAsync("ReceiveDisplayConfig", configJson);
}
}
}
}

View File

@ -0,0 +1,60 @@
using System;
namespace ShengShengBuXi.Models
{
/// <summary>
/// 监控文本模型
/// </summary>
public class MonitorText
{
/// <summary>
/// 唯一标识符
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 显示文本内容
/// </summary>
public string Text { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// 是否来自真实用户(否则为系统预设文本)
/// </summary>
public bool IsRealUser { get; set; }
/// <summary>
/// 原始语音识别结果ID如果有
/// </summary>
public string RecognitionId { get; set; }
/// <summary>
/// 文本优先级(真实用户优先显示)
/// </summary>
public int Priority => IsRealUser ? 10 : 1;
/// <summary>
/// 是否处理过
/// </summary>
public bool IsProcessed { get; set; } = false;
/// <summary>
/// 处理后的文字
/// </summary>
public string CompletedText { get; set; }
/// <summary>
/// 录音文件路径
/// </summary>
public string RecordingPath { get; set; }
/// <summary>
/// 识别文字的文件的路径
/// </summary>
public string TextFilePath { get; set; }
}
}

View File

@ -40,6 +40,9 @@
<li class="nav-item" role="presentation">
<button class="nav-link" id="recognition-tab" data-bs-toggle="tab" data-bs-target="#recognition" type="button" role="tab" aria-controls="recognition" aria-selected="false">识别结果</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="display-config-tab" data-bs-toggle="tab" data-bs-target="#display-config" type="button" role="tab" aria-controls="display-config" aria-selected="false">显示配置</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<!-- 系统配置 -->
@ -294,6 +297,128 @@
</div>
</div>
</div>
<!-- 显示配置 -->
<div class="tab-pane fade" id="display-config" role="tabpanel" aria-labelledby="display-config-tab">
<div class="mt-3">
<div class="d-flex justify-content-end mb-3">
<button type="button" class="btn btn-success me-2" onclick="saveDisplayConfig()">保存配置</button>
<button type="button" class="btn btn-primary me-2" onclick="getDisplayConfig()">刷新配置</button>
<button type="button" class="btn btn-secondary" onclick="resetDisplayConfig()">重置默认值</button>
</div>
<form id="display-config-form" class="mt-3">
<div class="row">
<!-- 左侧容器配置 -->
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5>左侧容器配置</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="leftTurnPageHeight" class="form-label">翻页高度比例</label>
<input type="number" class="form-control" id="leftTurnPageHeight" step="0.1" min="0.1" max="1.0" value="0.8">
<div class="form-text">页面高度比例值范围0.1-1.0</div>
</div>
<div class="mb-3">
<label for="leftFontSize" class="form-label">字体大小</label>
<input type="text" class="form-control" id="leftFontSize" value="16px">
<div class="form-text">左侧历史记录字体大小例如16px</div>
</div>
<div class="mb-3">
<label for="leftTypewriterSpeed" class="form-label">打字效果速度</label>
<input type="number" class="form-control" id="leftTypewriterSpeed" min="10" max="500" value="50">
<div class="form-text">数值越小,打字效果速度越快</div>
</div>
</div>
</div>
</div>
<!-- 右侧容器配置 -->
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5>右侧容器配置</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="rightFontSize" class="form-label">字体大小</label>
<input type="text" class="form-control" id="rightFontSize" value="24px">
<div class="form-text">右侧主要显示文本的字体大小</div>
</div>
<div class="mb-3">
<label for="rightFontWeight" class="form-label">字体粗细</label>
<select class="form-select" id="rightFontWeight">
<option value="normal">正常</option>
<option value="bold">粗体</option>
<option value="bolder">很粗</option>
<option value="lighter">细体</option>
</select>
</div>
<div class="mb-3">
<label for="rightFontStyle" class="form-label">字体风格</label>
<select class="form-select" id="rightFontStyle">
<option value="normal">正常</option>
<option value="italic">斜体</option>
</select>
</div>
<div class="mb-3">
<label for="rightTypewriterSpeed" class="form-label">打字效果速度</label>
<input type="number" class="form-control" id="rightTypewriterSpeed" min="10" max="500" value="50">
<div class="form-text">数值越小,打字效果速度越快</div>
</div>
</div>
</div>
</div>
<!-- 水波纹效果配置 -->
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5>水波纹效果配置</h5>
</div>
<div class="card-body">
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="waterEffectEnabled" checked>
<label class="form-check-label" for="waterEffectEnabled">启用水波纹效果</label>
</div>
<div class="mb-3">
<label for="waterMinInterval" class="form-label">最小间隔(毫秒)</label>
<input type="number" class="form-control" id="waterMinInterval" min="100" max="5000" value="800">
</div>
<div class="mb-3">
<label for="waterMaxInterval" class="form-label">最大间隔(毫秒)</label>
<input type="number" class="form-control" id="waterMaxInterval" min="100" max="10000" value="2000">
</div>
<div class="mb-3">
<label for="waterSimultaneousDrops" class="form-label">同时涟漪数量</label>
<input type="number" class="form-control" id="waterSimultaneousDrops" min="1" max="10" value="3">
</div>
<div class="mb-3">
<label for="waterFadeOutSpeed" class="form-label">淡出速度</label>
<input type="number" class="form-control" id="waterFadeOutSpeed" min="0.01" max="1" step="0.01" value="0.1">
</div>
<div class="mb-3">
<label for="waterCenterBias" class="form-label">中心倾向</label>
<input type="number" class="form-control" id="waterCenterBias" min="0" max="1" step="0.1" value="0.5">
<div class="form-text">0表示随机1表示集中在中心</div>
</div>
<div class="mb-3">
<label for="waterLargeDropProbability" class="form-label">大水滴概率</label>
<input type="number" class="form-control" id="waterLargeDropProbability" min="0" max="1" step="0.1" value="0.2">
</div>
<div class="mb-3">
<label for="waterLargeDropSize" class="form-label">大水滴大小</label>
<input type="number" class="form-control" id="waterLargeDropSize" min="3" max="20" value="9">
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@ -302,7 +427,7 @@
</div>
@section Scripts {
@* <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.6/signalr.min.js"></script> *@
@* <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.6/signalr.min.js"></script> *@
<script src="~/lib/microsoft-signalr/signalr.min.js"></script>
<script>
@ -363,77 +488,54 @@
// 初始化SignalR连接
function initSignalR() {
log("初始化SignalR连接...");
updateConnectionStatus("连接中...", "warning");
// 创建连接
connection = new signalR.HubConnectionBuilder()
.withUrl("/audiohub")
.configureLogging(signalR.LogLevel.Debug) // 使用Debug级别以获取更多日志
.withUrl("/audioHub")
.withAutomaticReconnect()
.build();
// 注册连接事件处理程序
// 注册连接事件处理程序
connection.onreconnecting(error => {
log("重新连接中: " + (error ? error.message : "未知错误"));
updateConnectionStatus("重连中...", "warning");
});
connection.onreconnected(connectionId => {
log("已重新连接ID: " + connectionId);
updateConnectionStatus("已连接", "success");
// 重新注册
registerAsAdmin();
// 设置连接状态变化的处理
// setConnectionStatusHandlers();
// 设置消息处理
connection.on("ReceiveServerMessage", function(message) {
log("服务器消息: " + message);
showMessage(message);
});
connection.onclose(error => {
log("连接已关闭: " + (error ? error.message : ""));
updateConnectionStatus("已断开", "danger");
// 5秒后重连
setTimeout(() => startConnection(), 5000);
});
// 注册服务器消息处理程序
setupSignalRHandlers();
// 建立连接
startConnection();
}
// 开始连接
function startConnection() {
log("正在连接到服务器...");
// 启动连接
connection.start()
.then(() => {
log("已连接到服务器连接ID: " + connection.connectionId);
.then(function() {
log("SignalR连接成功");
updateConnectionStatus("已连接", "success");
registerAsAdmin();
// 注册为管理员客户端
connection.invoke("RegisterClient", 1, "WebAdmin")
.then(function() {
log("注册为管理员客户端成功");
// 获取最新配置
getLatestConfig();
// 获取显示配置
getDisplayConfig();
// 获取客户端列表
//getClientList();
setTimeout(getRecentRecordings, 1000);
})
.catch(function(err) {
log("注册为管理员客户端失败: " + err);
showMessage("注册为管理员客户端失败,请刷新页面重试", "danger");
});
})
.catch(err => {
log("连接失败: " + err);
.catch(function(err) {
log("SignalR连接失败: " + err);
updateConnectionStatus("连接失败", "danger");
setTimeout(() => startConnection(), 5000);
});
}
// 注册为管理员
function registerAsAdmin() {
if (!connection || connection.state !== signalR.HubConnectionState.Connected) {
log("无法注册:未连接");
return;
}
log("正在注册为管理员客户端...");
.then(() => {
log("已注册为管理员客户端");
// 注册成功后立即获取配置和录音列表
getLatestConfig();
setTimeout(getRecentRecordings, 1000);
})
.catch(err => {
log("注册失败: " + err);
showMessage("注册失败: " + err, "danger");
setTimeout(initSignalR, 5000); // 5秒后重试
});
}
@ -1012,6 +1114,25 @@
log("错误: " + message);
showMessage("错误: " + message, "danger");
});
// 显示配置更新结果
connection.on("DisplayConfigUpdated", (success, message) => {
log("显示配置更新结果: " + message);
showMessage(message, success ? "success" : "danger");
});
// 接收显示配置
connection.on("ReceiveDisplayConfig", (configJson) => {
log("接收到显示配置");
try {
const config = JSON.parse(configJson);
loadDisplayConfigToForm(config);
log("显示配置已成功加载");
} catch (error) {
log("解析显示配置失败: " + error);
showMessage("解析显示配置失败: " + error, "danger");
}
});
}
// 更新客户端列表
@ -1294,6 +1415,139 @@
}
}
// 获取显示配置
function getDisplayConfig() {
if (!connection || connection.state !== signalR.HubConnectionState.Connected) {
showMessage("未连接到服务器", "danger");
return;
}
log("正在获取显示配置...");
connection.invoke("GetDisplayConfig")
.then(function (configJson) {
log("获取显示配置成功");
try {
const config = JSON.parse(configJson);
// 填充表单
if (config.leftContainer) {
document.getElementById('leftTurnPageHeight').value = config.leftContainer.turnPageHeight || 0.8;
document.getElementById('leftFontSize').value = config.leftContainer.fontSize || '16px';
document.getElementById('leftTypewriterSpeed').value = config.leftContainer.typewriterSpeed || 50;
}
if (config.rightContainer) {
document.getElementById('rightFontSize').value = config.rightContainer.fontSize || '24px';
document.getElementById('rightFontWeight').value = config.rightContainer.fontWeight || 'normal';
document.getElementById('rightFontStyle').value = config.rightContainer.fontStyle || 'normal';
document.getElementById('rightTypewriterSpeed').value = config.rightContainer.typewriterSpeed || 50;
}
if (config.waterEffect) {
document.getElementById('waterEffectEnabled').checked = config.waterEffect.enabled !== undefined ? config.waterEffect.enabled : true;
document.getElementById('waterMinInterval').value = config.waterEffect.minInterval || 800;
document.getElementById('waterMaxInterval').value = config.waterEffect.maxInterval || 2000;
document.getElementById('waterSimultaneousDrops').value = config.waterEffect.simultaneousDrops || 3;
document.getElementById('waterFadeOutSpeed').value = config.waterEffect.fadeOutSpeed || 0.1;
document.getElementById('waterCenterBias').value = config.waterEffect.centerBias || 0.5;
if (config.waterEffect.largeDrop) {
document.getElementById('waterLargeDropProbability').value = config.waterEffect.largeDrop.probability || 0.2;
document.getElementById('waterLargeDropSize').value = config.waterEffect.largeDrop.size || 9;
}
}
showMessage("显示配置加载成功", "success");
} catch (error) {
log("解析显示配置失败: " + error);
showMessage("解析显示配置失败: " + error, "danger");
}
})
.catch(function (err) {
log("获取显示配置出错: " + err);
showMessage("获取显示配置出错: " + err, "danger");
});
}
// 保存显示配置
function saveDisplayConfig() {
if (!connection || connection.state !== signalR.HubConnectionState.Connected) {
showMessage("未连接到服务器", "danger");
return;
}
// 收集表单数据
const config = {
leftContainer: {
turnPageHeight: parseFloat(document.getElementById('leftTurnPageHeight').value),
fontSize: document.getElementById('leftFontSize').value,
typewriterSpeed: parseInt(document.getElementById('leftTypewriterSpeed').value)
},
rightContainer: {
fontSize: document.getElementById('rightFontSize').value,
fontWeight: document.getElementById('rightFontWeight').value,
fontStyle: document.getElementById('rightFontStyle').value,
typewriterSpeed: parseInt(document.getElementById('rightTypewriterSpeed').value)
},
waterEffect: {
enabled: document.getElementById('waterEffectEnabled').checked,
minInterval: parseInt(document.getElementById('waterMinInterval').value),
maxInterval: parseInt(document.getElementById('waterMaxInterval').value),
simultaneousDrops: parseInt(document.getElementById('waterSimultaneousDrops').value),
fadeOutSpeed: parseFloat(document.getElementById('waterFadeOutSpeed').value),
centerBias: parseFloat(document.getElementById('waterCenterBias').value),
largeDrop: {
probability: parseFloat(document.getElementById('waterLargeDropProbability').value),
size: parseInt(document.getElementById('waterLargeDropSize').value)
}
}
};
const configJson = JSON.stringify(config);
log("正在保存显示配置: " + configJson);
connection.invoke("SaveDisplayConfig", configJson)
.then(function (success) {
if (success) {
log("显示配置保存成功");
showMessage("显示配置保存成功", "success");
// 重载配置
getDisplayConfig();
} else {
log("显示配置保存失败");
showMessage("显示配置保存失败", "danger");
}
})
.catch(function (err) {
log("保存显示配置出错: " + err);
showMessage("保存显示配置出错: " + err, "danger");
});
}
// 重置显示配置为默认值
function resetDisplayConfig() {
document.getElementById('leftTurnPageHeight').value = 0.8;
document.getElementById('leftFontSize').value = '16px';
document.getElementById('leftTypewriterSpeed').value = 50;
document.getElementById('rightFontSize').value = '24px';
document.getElementById('rightFontWeight').value = 'normal';
document.getElementById('rightFontStyle').value = 'normal';
document.getElementById('rightTypewriterSpeed').value = 50;
document.getElementById('waterEffectEnabled').checked = true;
document.getElementById('waterMinInterval').value = 800;
document.getElementById('waterMaxInterval').value = 2000;
document.getElementById('waterSimultaneousDrops').value = 3;
document.getElementById('waterFadeOutSpeed').value = 0.1;
document.getElementById('waterCenterBias').value = 0.5;
document.getElementById('waterLargeDropProbability').value = 0.2;
document.getElementById('waterLargeDropSize').value = 9;
showMessage("已重置为默认配置,请点击保存按钮保存", "info");
}
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", function() {
log("页面已加载");
@ -1307,6 +1561,17 @@
setTimeout(getRecentRecordings, 500);
}
});
// 切换到显示配置标签页时自动加载显示配置
document.getElementById('display-config-tab').addEventListener('click', function() {
if (connection && connection.state === signalR.HubConnectionState.Connected) {
log("切换到显示配置标签页,自动加载显示配置");
setTimeout(getDisplayConfig, 500);
}
});
// 初始化显示配置默认值
resetDisplayConfig();
});
</script>
}

View File

@ -155,10 +155,7 @@
size: 80 // 大涟漪的大小
}
},
// 预设的中文句子数组
sentences: [
]
};
let currentSentenceIndex = 0; // 当前句子索引
@ -354,6 +351,19 @@
displayText(text);
});
// 接收显示配置的处理函数
hubConnection.on("ReceiveDisplayConfig", function (configJson) {
console.log("收到显示配置");
try {
const newConfig = JSON.parse(configJson);
// 更新全局配置
updateConfig(newConfig);
console.log("已更新显示配置");
} catch (error) {
console.error("解析显示配置失败:", error);
}
});
// 启动连接
hubConnection.start()
.then(function () {
@ -362,6 +372,19 @@
hubConnection.invoke("RegisterClient", 3, "Display")
.then(function() {
console.log("注册为显示客户端成功");
// 获取显示配置
return hubConnection.invoke("GetDisplayConfig");
})
.then(function(configJson) {
if(configJson) {
console.log("已获取显示配置");
try {
const config = JSON.parse(configJson);
updateConfig(config);
} catch (error) {
console.error("解析显示配置失败:", error);
}
}
// 开始接收显示文本
return hubConnection.invoke("StartReceivingDisplayText");
})
@ -369,7 +392,7 @@
console.log("开始接收显示文本");
})
.catch(function(err) {
console.error("注册客户端失败:", err);
console.error("客户端操作失败:", err);
});
})
.catch(function (err) {
@ -385,6 +408,67 @@
});
}
// 更新配置
function updateConfig(newConfig) {
// 更新左侧容器配置
if (newConfig.leftContainer) {
CONFIG.leftContainer.turnPageHeight = newConfig.leftContainer.turnPageHeight || CONFIG.leftContainer.turnPageHeight;
CONFIG.leftContainer.fontSize = newConfig.leftContainer.fontSize || CONFIG.leftContainer.fontSize;
CONFIG.leftContainer.typewriterSpeed = newConfig.leftContainer.typewriterSpeed || CONFIG.leftContainer.typewriterSpeed;
// 应用字体大小到CSS
document.documentElement.style.setProperty('--left-font-size', CONFIG.leftContainer.fontSize);
}
// 更新右侧容器配置
if (newConfig.rightContainer) {
CONFIG.rightContainer.fontSize = newConfig.rightContainer.fontSize || CONFIG.rightContainer.fontSize;
CONFIG.rightContainer.fontWeight = newConfig.rightContainer.fontWeight || CONFIG.rightContainer.fontWeight;
CONFIG.rightContainer.fontStyle = newConfig.rightContainer.fontStyle || CONFIG.rightContainer.fontStyle;
CONFIG.rightContainer.typewriterSpeed = newConfig.rightContainer.typewriterSpeed || CONFIG.rightContainer.typewriterSpeed;
// 应用到CSS
document.documentElement.style.setProperty('--right-font-size', CONFIG.rightContainer.fontSize);
document.documentElement.style.setProperty('--right-font-weight', CONFIG.rightContainer.fontWeight);
document.documentElement.style.setProperty('--right-font-style', CONFIG.rightContainer.fontStyle);
}
// 更新水波纹效果配置
if (newConfig.waterEffect) {
CONFIG.waterEffect.enabled = newConfig.waterEffect.enabled !== undefined ? newConfig.waterEffect.enabled : CONFIG.waterEffect.enabled;
CONFIG.waterEffect.minInterval = newConfig.waterEffect.minInterval || CONFIG.waterEffect.minInterval;
CONFIG.waterEffect.maxInterval = newConfig.waterEffect.maxInterval || CONFIG.waterEffect.maxInterval;
CONFIG.waterEffect.simultaneousDrops = newConfig.waterEffect.simultaneousDrops || CONFIG.waterEffect.simultaneousDrops;
CONFIG.waterEffect.fadeOutSpeed = newConfig.waterEffect.fadeOutSpeed || CONFIG.waterEffect.fadeOutSpeed;
CONFIG.waterEffect.centerBias = newConfig.waterEffect.centerBias !== undefined ? newConfig.waterEffect.centerBias : CONFIG.waterEffect.centerBias;
if (newConfig.waterEffect.largeDrop) {
CONFIG.waterEffect.largeDrop.probability = newConfig.waterEffect.largeDrop.probability !== undefined ?
newConfig.waterEffect.largeDrop.probability : CONFIG.waterEffect.largeDrop.probability;
CONFIG.waterEffect.largeDrop.size = newConfig.waterEffect.largeDrop.size || CONFIG.waterEffect.largeDrop.size;
}
// 应用水波纹效果配置
if ($('.water-effect').data('ripples')) {
// 如果ripples已初始化先销毁
$('.water-effect').ripples('destroy');
}
if (CONFIG.waterEffect.enabled) {
$('.water-effect').show();
$('.water-effect').ripples({
resolution: 1024,
dropRadius: 1.5,
perturbance: 0
});
} else {
$('.water-effect').hide();
}
}
console.log("配置已更新:", CONFIG);
}
// 页面加载完成后初始化
$(window).ready(function () {
$('#magazine').turn({

View File

@ -10,6 +10,9 @@
</PropertyGroup>
<ItemGroup>
<Content Update="config.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\js\jquery.ripples.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View File

@ -0,0 +1,25 @@
{
"leftContainer": {
"turnPageHeight": 0.55,
"fontSize": "16px",
"typewriterSpeed": 50
},
"rightContainer": {
"fontSize": "40px",
"fontWeight": "700",
"fontStyle": "italic",
"typewriterSpeed": 330
},
"waterEffect": {
"enabled": true,
"minInterval": 1600,
"maxInterval": 8000,
"simultaneousDrops": 2,
"fadeOutSpeed": 2000,
"centerBias": 0.6,
"largeDrop": {
"probability": 0.2,
"size": 80
}
}
}