pkc-ys/PKCYsManage/templates/index.html
2024-11-02 02:00:46 +08:00

708 lines
26 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ titleName }}{{ PKC_VERSION }}</title>
<style>
/* CSS 代码 */
body {
font-family: 'Roboto', sans-serif; /* 使用现代字体 Roboto */
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #e0eafc, #cfdef3); /* 更柔和的渐变背景 */
/*background: linear-gradient(120deg, #00ccff, #ff00ff);*/
color: #333;
overflow: hidden;
display: flex; /* 使用 flexbox 布局 */
flex-direction: column;
align-items: center; /* 居中内容 */
}
h2 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
font-size: 2.5rem; /* 更大的标题 */
font-weight: 600; /* 更粗的标题 */
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 添加阴影 */
}
.form-group {
margin-bottom: 20px;
width: 100%;
max-width: 500px; /* 限制表单宽度 */
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
input, select {
width: 100%;
padding: 12px 15px;
border: 2px solid #ccc;
border-radius: 6px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
transition: border-color 0.3s, box-shadow 0.3s;
font-size: 16px;
background-color: #f9f9f9; /* 添加更浅的背景色 */
}
input:focus, select:focus {
border-color: #3498db;
box-shadow: 0 0 8px rgba(52, 152, 219, 0.5);
outline: none;
}
button {
padding: 12px 20px;
background-color: #2ecc71;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s, transform 0.3s;
font-size: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 添加阴影 */
}
button:hover {
background-color: #27ae60;
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2); /* 悬停时阴影更明显 */
}
button:focus {
outline: none;
}
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
border-radius: 8px;
width: 100%;
max-width: 100%; /* 限制 Tab 宽度 */
margin-bottom: 20px; /* 添加 Tab 与内容之间的间隔 */
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
color: #2c3e50;
border-right: 1px solid #ccc;
font-weight: bold; /* 加粗 Tab 标题 */
}
.tab button:last-child {
border-right: none;
}
.tab button:hover {
background-color: #e0e0e0;
}
.tab button.active {
background-color: #2c3e50; /* 使用深蓝色作为激活状态 */
color: #fff;
}
.tabcontent {
display: block; /* 确保内容可见 */
padding: 20px;
border: 1px solid #ccc;
border-top: none;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
/*background-color: #fff;*/
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-height: 500px; /* 设置最大高度 */
overflow-y: auto; /* 允许垂直滚动 */
width: 100%; /* 使宽度适应父容器 */
box-sizing: border-box; /* 包括内边距和边框在宽度计算内 */
}
.search-input {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 5px;
}
.custom-dropdown {
position: relative;
}
#search_input_edit, #search_input_delete {
width: 100%;
padding: 12px 15px;
border: 2px solid #ccc;
border-radius: 6px;
box-sizing: border-box;
font-size: 16px;
background-color: #f9f9f9; /* 添加更浅的背景色 */
}
.dropdown-options {
position: absolute;
width: 100%;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ccc;
border-top: none;
background-color: white;
display: none;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 999;
}
.dropdown-item {
padding: 10px;
cursor: pointer;
transition: background-color 0.3s;
}
.dropdown-item:hover {
background-color: #f0f0f0;
}
/* 显示下拉框 */
#search_input_edit:focus + .dropdown-options,
#search_input_delete:focus + .dropdown-options {
display: block;
}
#urlModal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
text-align: center;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
</style>
</head>
<body>
<h2>{{ titleName }} {{ PKC_VERSION }}</h2>
<div class="tab">
<button class="tablinks active" onclick="openTab(event, 'addCategory')">添加分类</button>
<button class="tablinks" onclick="openTab(event, 'editCategory')">修改分类</button>
<button class="tablinks" onclick="openTab(event, 'deleteCategory')">删除分类</button>
<button class="tablinks" onclick="openTab(event, 'addToList')">添加音色</button>
<button class="tablinks" onclick="openTab(event, 'editListItem')">修改音色</button>
<button class="tablinks" onclick="openTab(event, 'deleteFromList')">删除音色</button>
<button class="tablinks" onclick="openTab(event, 'backup')">备份</button>
<button class="tablinks" onclick="openTab(event, 'export')">导出</button>
<button class="tablinks" onclick="openTab(event, 'import')">导入</button>
<button class="tablinks" onclick="getYsList()">音色接口</button>
<button class="tablinks" onclick="loginout()">退出</button>
</div>
<div id="addCategory" class="tabcontent" style="display: block;">
<h3>添加分类</h3>
<form method="POST" onsubmit="return validateForm('add_category','addCategory')">
<input type="hidden" name="action" value="add_category">
<div class="form-group">
<label for="type">音色接口:</label>
<select id="type" name="type">
<option value="fish.audio" selected>fish.audio</option>
<option value="FineVoice">FineVoice</option>
<option value="琅琅">琅琅</option>
<option value="讯飞">讯飞</option>
<option value="acgn.ttson.cn">二次元(原神)</option>
</select>
</div>
<div class="form-group">
<label for="name">*分类名称:</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="token">是否需要Token:</label>
<select id="token" name="token">
<option value="yes" selected>Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="form-group">
<label for="sort">*排序:</label>
<input type="number" id="sort" name="sort" required>
</div>
<div class="form-group">
<label for="url">URL:</label>
<input type="text" id="url" name="url">
</div>
<div class="form-group">
<label for="alias">别名:</label>
<input type="text" id="alias" name="alias">
</div>
<div class="form-group">
<label for="desc">描述:</label>
<input type="text" id="desc" name="desc">
</div>
<button type="submit">添加分类</button>
</form>
</div>
<div id="editCategory" class="tabcontent">
<h3>修改分类</h3>
<form method="POST" onsubmit="return validateForm('edit_category','editCategory')">
<input type="hidden" name="action" value="edit_category">
<div class="form-group">
<label for="old_name">选择分类:</label>
<select id="old_name" name="old_name" required onchange="fillCategoryDetails()" onkeyup="filterSelectOptions('old_name')">
{% for category_name in audio_colors.keys() %}
<option value="{{ category_name }}">{{ category_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="type">音色接口:</label>
<select id="type" name="type">
<option value="fish.audio">fish.audio</option>
<option value="FineVoice">FineVoice</option>
<option value="琅琅" selected>琅琅</option>
<option value="讯飞">讯飞</option>
<option value="acgn.ttson.cn">二次元(原神)</option>
</select>
</div>
<div class="form-group">
<label for="new_name">*新分类名称:</label>
<input type="text" id="new_name" name="new_name" required>
</div>
<div class="form-group">
<label for="token">是否需要Token:</label>
<select id="token" name="token">
<option value="yes" selected>Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="form-group">
<label for="sort">*排序:</label>
<input type="number" id="sort" name="sort" required>
</div>
<div class="form-group">
<label for="url">URL:</label>
<input type="text" id="url" name="url">
</div>
<div class="form-group">
<label for="alias">别名:</label>
<input type="text" id="alias" name="alias">
</div>
<div class="form-group">
<label for="desc">描述:</label>
<input type="text" id="desc" name="desc">
</div>
<button type="submit">修改分类</button>
</form>
</div>
<div id="deleteCategory" class="tabcontent">
<h3>删除分类</h3>
<form method="POST" onsubmit="return validateForm('delete_category','deleteCategory')">
<input type="hidden" name="action" value="delete_category">
<div class="form-group">
<label for="name">选择分类:</label>
<select id="name" name="name" required>
{% for category_name in audio_colors.keys() %}
<option value="{{ category_name }}">{{ category_name }}</option>
{% endfor %}
</select>
</div>
<button type="submit">删除分类</button>
</form>
</div>
<div id="addToList" class="tabcontent">
<h3>添加音色到分类</h3>
<form method="POST" onsubmit="return validateForm('add_to_list','addToList')">
<input type="hidden" name="action" value="add_to_list">
<div class="form-group">
<label for="category_name_add">选择分类:</label>
<select id="category_name_add" name="category_name" required>
{% for category_name in audio_colors.keys() %}
<option value="{{ category_name }}">{{ category_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="name">*音色名称:</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="desc">*描述:</label>
<input type="text" id="desc" name="desc" required>
</div>
<div class="form-group">
<label for="vid">*音色 ID:</label>
<input type="text" id="vid" name="vid" required>
</div>
<div class="form-group">
<label for="img">图片链接:</label>
<input type="text" id="img" name="img">
</div>
<button type="submit">添加音色</button>
</form>
</div>
<div id="editListItem" class="tabcontent">
<h3>修改音色</h3>
<form method="POST" onsubmit="return validateForm('edit_list_item','editListItem')">
<input type="hidden" name="action" value="edit_list_item">
<div class="form-group">
<label for="category_name_edit">选择分类:</label>
<select id="category_name_edit" name="category_name" required onchange="updateAudioColorsList('edit')">
{% for category_name in audio_colors.keys() %}
<option value="{{ category_name }}" {% if category_name == first_category_name %}selected{% endif %}>{{ category_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="old_name_edit">选择音色:</label>
<div class="custom-dropdown">
<input type="text" id="search_input_edit" placeholder="搜索音色(输入要搜索的内容然后点下面的下拉菜单)..." onkeyup="filterSelectOptions('edit')" autocomplete="off" />
<select id="old_name_edit" name="old_name" onchange="fillAudioColorDetails('edit')">
<!-- 音色选项将在这里动态生成 -->
</select>
<div id="dropdown_options_edit" class="dropdown-options">
<!-- 音色选项将在这里动态生成 -->
</div>
</div>
</div>
<div class="form-group">
<label for="new_name">新音色名称:</label>
<input type="text" id="new_name" name="new_name" required>
</div>
<div class="form-group">
<label for="desc">*描述:</label>
<input type="text" id="desc" name="desc" required>
</div>
<div class="form-group">
<label for="vid">*音色 ID:</label>
<input type="text" id="vid" name="vid" required>
</div>
<div class="form-group">
<label for="img">图片链接:</label>
<input type="text" id="img" name="img">
</div>
<button type="submit">修改音色</button>
</form>
</div>
<div id="deleteFromList" class="tabcontent">
<h3>删除音色</h3>
<form method="POST" onsubmit="return validateForm('old_name_delete','deleteFromList')">
<input type="hidden" name="action" value="delete_from_list">
<div class="form-group">
<label for="category_name_delete">选择分类:</label>
<select id="category_name_delete" name="category_name" required onchange="updateAudioColorsList('delete')">
{% for category_name in audio_colors.keys() %}
<option value="{{ category_name }}" {% if category_name == first_category_name %}selected{% endif %}>{{ category_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="old_name_delete">选择音色:</label>
<div class="custom-dropdown">
<input type="text" id="search_input_delete" placeholder="搜索音色(输入要搜索的内容然后点下面的下拉菜单)..." onkeyup="filterSelectOptions('delete')" autocomplete="off" />
<select id="old_name_delete" name="name" onchange="fillAudioColorDetailsForDelete('delete')">
<!-- 音色选项将在这里动态生成 -->
</select>
<div id="dropdown_options_delete" class="dropdown-options">
<!-- 音色选项将在这里动态生成 -->
</div>
</div>
</div>
<button type="submit">删除音色</button>
</form>
</div>
<div id="backup" class="tabcontent">
<h3>备份</h3>
<form method="POST" onsubmit="return validateForm('backup','backup')">
<input type="hidden" name="action" value="backup">
<button type="submit">备份</button>
</form>
</div>
<div id="export" class="tabcontent">
<h3>导出</h3>
<form method="POST" onsubmit="return validateForm('export','export')">
<input type="hidden" name="action" value="export">
<button type="submit">导出</button>
</form>
</div>
<div id="import" class="tabcontent">
<h3>导入</h3>
<form method="POST" enctype="multipart/form-data" onsubmit="return validateForm('import','import')">
<input type="hidden" name="action" value="import">
<div class="form-group">
<label for="import_file">选择 PKC音色JSON文件:</label>
<input type="file" id="import_file" name="import_file" accept=".json" required>
</div>
<button type="submit">导入</button>
</form>
</div>
<div id="urlModal" style="display:none;">
<div class="modal-content">
<p id="urlText"></p>
<button id="copyButton">复制</button>
<button id="openButton">访问</button>
<button id="cancelButton">取消</button>
</div>
</div>
<script>
function showResponseMessage(message) {
// 导航到新URL
alert(message); // 使用 alert() 函数显示弹窗提示
var currentUrl = window.location.href;
window.location.href = currentUrl;
}
function openTab(evt, tabName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " active";
}
function updateAudioColorsList(action) {
var categorySelect = document.getElementById("category_name_" + action);
var selectedCategory = categorySelect.value;
// 获取对应分类的音色列表
var audioColors = {{ audio_colors | tojson | safe }}; // 使用 JSON.stringify 转换
var categoryData = audioColors[selectedCategory];
var dropdownOptions = document.getElementById('dropdown_options_' + action);
dropdownOptions.innerHTML = ''; // 清空下拉选项
var oldNameSelect = document.getElementById('old_name_' + action);
oldNameSelect.innerHTML = ''; // 清空下拉选项
if (categoryData && categoryData['list']) {
categoryData['list'].forEach(function(item) {
var dropdownItem = document.createElement('div');
dropdownItem.classList.add('dropdown-item');
dropdownItem.textContent = item['name'] + ' | ' + item['desc'];
dropdownItem.dataset.desc = item['desc'] + '|' + item['img'] + '|' + item['vid'];
dropdownItem.addEventListener('click', function() {
document.getElementById('search_input_' + action).value = this.textContent;
if (action === 'edit') {
fillAudioColorDetails(action);
} else if (action === 'delete') {
fillAudioColorDetailsForDelete('delete');
}
});
dropdownOptions.appendChild(dropdownItem);
var option = document.createElement('option');
option.value = item['name'];
option.textContent = item['name'] + ' | ' + item['desc'];
option.dataset.desc = item['desc'] + '|' + item['img'] + '|' + item['vid'];
oldNameSelect.appendChild(option);
});
}
}
function fillCategoryDetails() {
var selectedCategory = document.getElementById('old_name').value;
var categoryData = {{ audio_colors | tojson | safe }};
document.getElementById('editCategory').querySelector('#new_name').value = selectedCategory;
document.getElementById('editCategory').querySelector('#desc').value = categoryData[selectedCategory]['desc'];
document.getElementById('editCategory').querySelector('#token').value = categoryData[selectedCategory]['token'];
document.getElementById('editCategory').querySelector('#sort').value = categoryData[selectedCategory]['sort']; // 填充 sort 值
document.getElementById('editCategory').querySelector('#url').value = categoryData[selectedCategory]['url']; // 填充 sort 值
document.getElementById('editCategory').querySelector('#type').value = categoryData[selectedCategory]['type']; // 填充 sort 值
document.getElementById('editCategory').querySelector('#alias').value = categoryData[selectedCategory]['alias']; // 填充 sort 值
}
function fillCategoryAdd() {
document.getElementById('addCategory').querySelector('#sort').value = {{ ysCount }};
}
function fillAudioColorDetails(action) {
var selectedItemText = document.getElementById('old_name_edit').value;
var descAndImgAndVid = document.getElementById('old_name_edit').querySelector('option[value="' + selectedItemText + '"]').dataset.desc.split('|');
document.getElementById('editListItem').querySelector('#new_name').value = selectedItemText;
document.getElementById('editListItem').querySelector('#desc').value = descAndImgAndVid[0];
document.getElementById('editListItem').querySelector('#img').value = descAndImgAndVid[1];
document.getElementById('editListItem').querySelector('#vid').value = descAndImgAndVid[2];
}
function fillAudioColorDetailsForDelete(action) {
var selectedItemText = document.getElementById('old_name_delete').value;
var descAndImgAndVid = document.getElementById('old_name_delete').querySelector('option[value="' + selectedItemText + '"]').dataset.desc.split('|');
document.getElementById('deleteFromList').querySelector('#old_name_delete').value = selectedItemText;
// document.getElementById('deleteFromList').querySelector('#desc').value = descAndImgAndVid[0]; // 填充描述
// document.getElementById('deleteFromList').querySelector('#img').value = descAndImgAndVid[1]; // 填充图片链接
// document.getElementById('deleteFromList').querySelector('#vid').value = descAndImgAndVid[2]; // 填充音色 ID
}
// 页面加载时,初始化修改和删除音色的音色列表
document.addEventListener('DOMContentLoaded', function() {
updateAudioColorsList('edit');
updateAudioColorsList('delete');
fillCategoryAdd();
var response = '{{ response }}'; // 获取 response 变量的值
if (response && response !== 'None') {
showResponseMessage(response);
}
let cacheValue = localStorage.getItem('curtabName');
if (cacheValue && cacheValue.length >1){
openTab(event, cacheValue)
}
});
function filterSelectOptions(action) {
var input = document.getElementById('search_input_' + action);
const select = document.getElementById('old_name_' + action);
var filter = input.value.toLocaleUpperCase('en-US');
var options = document.getElementById('old_name_' + action).getElementsByTagName('option');
var isINList = 0;
for (var i = 0; i < options.length; i++) {
var optionText = options[i].textContent;
if (optionText.toLocaleUpperCase('en-US').indexOf(filter) > -1) {
options[i].style.display = "";
isINList++;
} else {
options[i].style.display = "none";
}
}
// 设置下拉框大小
select.size = isINList > 0 ? Math.min(optionText.length, 5) : 1;
// 如果没有匹配项,清空选择
if (isINList === 0 && filter.length > 0) {
select.selectedIndex = -1; // 清空选择
}
}
// 为搜索框添加 onkeyup 事件
document.getElementById('search_input_edit').addEventListener('keyup', function() {
filterSelectOptions('edit');
});
document.getElementById('search_input_delete').addEventListener('keyup', function() {
filterSelectOptions('delete');
});
// 选择项点击事件
document.getElementById('dropdown_options_edit').addEventListener('click', function(event) {
var selectedItem = event.target;
if (selectedItem.classList.contains('dropdown-item')) {
document.getElementById('search_input_edit').value = selectedItem.textContent; // 设置输入框的值为选中的项
fillAudioColorDetails('edit');
}
});
document.getElementById('dropdown_options_delete').addEventListener('click', function(event) {
var selectedItem = event.target;
if (selectedItem.classList.contains('dropdown-item')) {
document.getElementById('search_input_delete').value = selectedItem.textContent; // 设置输入框的值为选中的项
fillAudioColorDetailsForDelete('delete');
}
});
function loginout() {
var currentUrl = window.location.origin + '/logout';
// 提示用户确认登出
var confirmation = confirm("您确定要登出吗?");
// 如果用户确认登出,则跳转到登出页面
if (confirmation) {
window.location.href = currentUrl;
}
// else {
// // 用户选择取消,可以选择在此处添加其他逻辑
// console.log("用户取消了登出操作");
// }
}
function getYsList() {
{#var domainName = '{{ domainName }}';#}
{#var mainUrl = domainName.length > 0 ? window.location.protocol+'//'+domainName+':'+window.location.port:window.location.origin;#}
var currentUrl = window.location.origin + '/ysList';
document.getElementById('urlText').textContent = currentUrl;
document.getElementById('urlModal').style.display = 'flex';
document.getElementById('copyButton').onclick = function() {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(currentUrl).then(() => {
alert('链接已复制到剪贴板!');
}).catch(err => {
alert('复制链接失败:' + err);
});
} else {
// 备选方案
const textArea = document.createElement('textarea');
textArea.value = currentUrl;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
alert('链接已复制到剪贴板!');
} catch (err) {
alert('复制链接失败:' + err);
}
document.body.removeChild(textArea);
}
};
document.getElementById('openButton').onclick = function() {
window.open(currentUrl, '_blank');
};
document.getElementById('cancelButton').onclick = function() {
document.getElementById('urlModal').style.display = 'none';
};
}
function validateForm(a,b) {
localStorage.setItem('curtabName', b);
if (a === 'old_name_delete'){
var select = document.getElementById(a);
if (select.selectedIndex === -1 || select.value === "") {
alert("未选中");
return false; // 阻止表单提交
}
return true; // 允许表单提交
}
}
</script>
</body>
</html>