xk/backend/public/index.html
2026-02-02 20:51:52 +08:00

571 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel - 虚境起源</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="css/admin.css">
</head>
<body>
<!-- Login Page -->
<div id="loginPage" class="login-page">
<div class="login-container">
<div class="login-header">
<i class="fas fa-shield-alt"></i>
<h1>管理后台</h1>
<p>虚境起源管理系统</p>
</div>
<form id="loginForm" class="login-form">
<div class="form-group">
<label for="username">
<i class="fas fa-user"></i>
用户名
</label>
<input type="text" id="username" name="username" required autocomplete="username">
</div>
<div class="form-group">
<label for="password">
<i class="fas fa-lock"></i>
密码
</label>
<input type="password" id="password" name="password" required autocomplete="current-password">
</div>
<div id="loginError" class="error-message" style="display: none;"></div>
<button type="submit" class="btn btn-primary btn-block">
<i class="fas fa-sign-in-alt"></i>
登录
</button>
</form>
</div>
</div>
<!-- Admin Dashboard -->
<div id="adminDashboard" class="admin-dashboard" style="display: none;">
<!-- Sidebar -->
<aside class="sidebar">
<div class="sidebar-header">
<i class="fas fa-cube"></i>
<h2>虚境起源</h2>
</div>
<nav class="sidebar-nav">
<div class="nav-section">
<div class="nav-section-title">
<i class="fas fa-handshake"></i>
<span>合作伙伴管理</span>
</div>
<a href="#storage-config" class="nav-link" data-page="storage-config">
<i class="fas fa-folder-open"></i>
存储配置
</a>
<a href="#add-partner" class="nav-link" data-page="add-partner">
<i class="fas fa-plus-circle"></i>
新增合作伙伴
</a>
<a href="#partner-list" class="nav-link active" data-page="partner-list">
<i class="fas fa-list"></i>
合作伙伴列表
</a>
</div>
<div class="nav-section">
<div class="nav-section-title">
<i class="fas fa-video"></i>
<span>宣传视频</span>
</div>
<a href="#video-list" class="nav-link" data-page="video-list">
<i class="fas fa-list"></i>
媒体列表
</a>
<a href="#video-config" class="nav-link" data-page="video-config">
<i class="fas fa-cog"></i>
媒体配置
</a>
<a href="#add-video" class="nav-link" data-page="add-video">
<i class="fas fa-plus-circle"></i>
新增媒体
</a>
</div>
<div class="nav-section">
<div class="nav-section-title">
<i class="fas fa-cog"></i>
<span>系统设置</span>
</div>
<a href="#system-settings" class="nav-link" data-page="system-settings">
<i class="fas fa-sliders-h"></i>
系统设置
</a>
<a href="#change-password" class="nav-link" data-page="change-password">
<i class="fas fa-key"></i>
修改密码
</a>
</div>
</nav>
<div class="sidebar-footer">
<button id="logoutBtn" class="btn btn-secondary btn-block">
<i class="fas fa-sign-out-alt"></i>
退出登录
</button>
</div>
</aside>
<!-- Main Content -->
<main class="main-content">
<header class="content-header">
<h1 id="pageTitle">Partner List</h1>
<div class="user-info">
<i class="fas fa-user-circle"></i>
<span id="currentUser">Admin</span>
</div>
</header>
<div class="content-body">
<!-- Storage Configuration Page -->
<div id="storageConfigPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>存储配置</h3>
</div>
<div class="card-body">
<form id="storageConfigForm">
<div class="form-group">
<label>上传目录</label>
<div class="input-with-status">
<input type="text" id="uploadDir" name="logo_upload_dir" value="img/logo" required>
<div id="dirStatus" class="status-indicators">
<span class="status-indicator" id="dirExists">
<i class="fas fa-circle"></i>
<span>已存在</span>
</span>
<span class="status-indicator" id="dirWritable">
<i class="fas fa-circle"></i>
<span>可写入</span>
</span>
</div>
</div>
<small>相对于项目根目录的路径</small>
</div>
<div class="form-group">
<label>最大文件大小(字节)</label>
<input type="number" id="maxSize" name="logo_max_size" value="5242880" required>
<small>5242880 字节 = 5MB</small>
</div>
<div class="form-group">
<label>允许的扩展名</label>
<input type="text" id="allowedExt" name="allowed_extensions" value="jpg,jpeg,png,gif,svg" required>
<small>逗号分隔的扩展名列表</small>
</div>
<div class="form-actions">
<button type="button" id="createDirBtn" class="btn btn-secondary">
<i class="fas fa-folder-plus"></i>
创建目录
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
保存配置
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Partner List Page -->
<div id="partnerListPage" class="page-content">
<div class="card">
<div class="card-header">
<h3>合作伙伴列表</h3>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Logo</th>
<th>名称</th>
<th>URL</th>
<th>排序</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="partnersTableBody">
<tr>
<td colspan="7" class="text-center">加载中...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- System Settings Page -->
<div id="systemSettingsPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>系统设置</h3>
</div>
<div class="card-body">
<div id="settingsTableContainer">
<p class="text-muted">加载设置中...</p>
</div>
</div>
</div>
</div>
<!-- Change Password Page -->
<div id="changePasswordPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>修改管理员密码</h3>
</div>
<div class="card-body">
<form id="changePasswordForm" style="max-width: 500px;">
<div class="form-group">
<label for="currentPassword">当前密码 *</label>
<input type="password" id="currentPassword" name="current_password" required autocomplete="current-password">
</div>
<div class="form-group">
<label for="newPassword">新密码 *</label>
<input type="password" id="newPassword" name="new_password" required minlength="6" autocomplete="new-password">
<small>密码长度至少6位</small>
</div>
<div class="form-group">
<label for="confirmPassword">确认新密码 *</label>
<input type="password" id="confirmPassword" name="confirm_password" required minlength="6" autocomplete="new-password">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
修改密码
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Video List Page -->
<div id="videoListPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>媒体列表</h3>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>封面</th>
<th>中文标题</th>
<th>英文标题</th>
<th>时长</th>
<th>上传状态</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="videosTableBody">
<tr>
<td colspan="8" class="text-center">Loading...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Video Config Page -->
<div id="videoConfigPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>腾讯云VOD配置</h3>
</div>
<div class="card-body">
<form id="vodConfigForm">
<div class="form-group">
<label for="secretId">SecretId *</label>
<input type="text" id="secretId" name="secret_id" required placeholder="腾讯云SecretId">
<small>在腾讯云访问管理控制台获取</small>
</div>
<div class="form-group">
<label for="secretKey">SecretKey *</label>
<input type="password" id="secretKey" name="secret_key" required placeholder="腾讯云SecretKey">
<small>请妥善保管密钥信息</small>
</div>
<div class="form-group">
<label for="vodRegion">地域</label>
<select id="vodRegion" name="region">
<option value="ap-guangzhou">华南地区(广州)</option>
<option value="ap-shanghai">华东地区(上海)</option>
<option value="ap-beijing">华北地区(北京)</option>
<option value="ap-chengdu">西南地区(成都)</option>
<option value="ap-chongqing">西南地区(重庆)</option>
<option value="ap-hongkong">港澳台地区(中国香港)</option>
<option value="ap-singapore">亚太东南(新加坡)</option>
<option value="ap-mumbai">亚太南部(孟买)</option>
<option value="ap-seoul">亚太东北(首尔)</option>
<option value="ap-bangkok">亚太东南(曼谷)</option>
<option value="ap-tokyo">亚太东北(东京)</option>
<option value="na-siliconvalley">美国西部(硅谷)</option>
<option value="na-ashburn">美国东部(弗吉尼亚)</option>
<option value="na-toronto">北美地区(多伦多)</option>
<option value="eu-frankfurt">欧洲地区(法兰克福)</option>
<option value="eu-moscow">欧洲地区(莫斯科)</option>
</select>
<small>选择离您最近的地域</small>
</div>
<div class="form-group">
<label for="subAppId">子应用ID</label>
<input type="text" id="subAppId" name="sub_app_id" placeholder="可选,留空使用主应用">
</div>
<div class="form-group">
<label for="vodProcedure">任务流</label>
<input type="text" id="vodProcedure" name="procedure" placeholder="可选,视频处理任务流">
<small>配置转码、截图等处理任务</small>
</div>
<div class="form-group">
<label for="storageRegion">存储地域</label>
<input type="text" id="storageRegion" name="storage_region" placeholder="可选,留空使用默认">
</div>
<hr style="margin: 30px 0; border: none; border-top: 2px solid #e5e7eb;">
<h4 style="margin-bottom: 20px; color: #374151;">COS 对象存储配置(用于封面图)</h4>
<div class="form-group">
<label for="cosBucket">COS存储桶 *</label>
<input type="text" id="cosBucket" name="cos_bucket" required placeholder="例如my-bucket-1234567890">
<small>在腾讯云COS控制台创建存储桶后获取格式bucket-appid</small>
</div>
<div class="form-group">
<label for="cosRegion">COS地域</label>
<select id="cosRegion" name="cos_region">
<option value="ap-guangzhou">华南地区(广州)</option>
<option value="ap-shanghai">华东地区(上海)</option>
<option value="ap-beijing">华北地区(北京)</option>
<option value="ap-chengdu">西南地区(成都)</option>
<option value="ap-chongqing">西南地区(重庆)</option>
<option value="ap-hongkong">港澳台地区(中国香港)</option>
<option value="ap-singapore">亚太东南(新加坡)</option>
<option value="ap-mumbai">亚太南部(孟买)</option>
<option value="ap-seoul">亚太东北(首尔)</option>
<option value="ap-bangkok">亚太东南(曼谷)</option>
<option value="ap-tokyo">亚太东北(东京)</option>
<option value="na-siliconvalley">美国西部(硅谷)</option>
<option value="na-ashburn">美国东部(弗吉尼亚)</option>
<option value="na-toronto">北美地区(多伦多)</option>
<option value="eu-frankfurt">欧洲地区(法兰克福)</option>
<option value="eu-moscow">欧洲地区(莫斯科)</option>
</select>
<small>存储桶所在地域建议与VOD地域相同</small>
</div>
<div class="form-group">
<label for="cosPath">COS存储路径前缀</label>
<input type="text" id="cosPath" name="cos_path" value="video-covers/" placeholder="video-covers/">
<small>封面图在存储桶中的路径前缀,末尾需要斜杠</small>
</div>
<hr>
<h4>VOD防盗链配置</h4>
<div class="form-group">
<label for="signKey">防盗链签名密钥(可选)</label>
<input type="text" id="signKey" name="sign_key" placeholder="请输入防盗链Key">
<small>如果开启了VOD防盗链需要填写Key以生成签名URL。留空则不使用防盗链。</small>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
保存配置
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Video Page -->
<div id="addVideoPage" class="page-content" style="display: none;">
<div class="card">
<div class="card-header">
<h3>新增媒体</h3>
</div>
<div class="card-body">
<form id="addVideoForm">
<div class="form-group">
<label for="videoTitleCn">中文标题 *</label>
<input type="text" id="videoTitleCn" name="title_cn" required>
</div>
<div class="form-group">
<label for="videoTitleEn">英文标题 *</label>
<input type="text" id="videoTitleEn" name="title_en" required>
</div>
<div class="form-group">
<label for="videoDescCn">中文描述</label>
<textarea id="videoDescCn" name="desc_cn" rows="3"></textarea>
</div>
<div class="form-group">
<label for="videoDescEn">英文描述</label>
<textarea id="videoDescEn" name="desc_en" rows="3"></textarea>
</div>
<div class="form-group">
<label for="videoCover">封面图</label>
<input type="file" id="videoCover" name="cover" accept="image/*">
<small>可选。如不上传,将自动使用腾讯云生成的封面图。支持 JPG, PNG, WEBP 格式,最大 10MB</small>
<div id="coverPreview" style="display: none; margin-top: 10px;">
<img id="coverPreviewImg" src="" alt="Cover Preview" style="max-width: 300px; max-height: 200px; border-radius: 8px;">
</div>
</div>
<div class="form-group">
<label for="videoFile">视频文件 *</label>
<input type="file" id="videoFile" accept="video/*" required>
<small>支持 MP4, AVI, MOV 等格式,支持大文件分片上传</small>
</div>
<!-- Upload Progress -->
<div id="uploadProgress" style="display: none;">
<div class="upload-progress-container">
<div class="upload-info">
<span id="uploadFileName"></span>
<span id="uploadPercent">0%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="upload-status">
<span id="uploadStatus">准备上传...</span>
<span id="uploadSpeed"></span>
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" id="uploadVideoBtn">
<i class="fas fa-upload"></i>
开始上传
</button>
<button type="button" class="btn btn-secondary" id="cancelUploadBtn" style="display: none;">
<i class="fas fa-times"></i>
取消上传
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Add/Edit Partner Modal -->
<div id="partnerModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 id="modalTitle">新增合作伙伴</h3>
<button class="modal-close">&times;</button>
</div>
<form id="partnerForm" enctype="multipart/form-data">
<div class="modal-body">
<input type="hidden" id="partnerId" name="partnerId">
<div class="form-group">
<label for="partnerName">合作伙伴名称 *</label>
<input type="text" id="partnerName" name="name" required>
</div>
<div class="form-group">
<label for="partnerLogo">Logo 图片 *</label>
<input type="file" id="partnerLogo" name="logo" accept="image/*">
<div id="currentLogoPreview" style="display: none; margin-top: 10px;">
<img id="currentLogo" src="" alt="当前 Logo" style="max-width: 200px; max-height: 100px;">
</div>
<small>支持JPG, PNG, GIF, SVG (最大 5MB)</small>
</div>
<div class="form-group">
<label for="partnerUrl">网站 URL</label>
<input type="url" id="partnerUrl" name="url" placeholder="https://example.com">
</div>
<div class="form-group">
<label for="partnerStatus">状态</label>
<select id="partnerStatus" name="status">
<option value="1">启用</option>
<option value="0">禁用</option>
</select>
</div>
<div class="form-group">
<label for="partnerSortOrder">排序</label>
<input type="number" id="partnerSortOrder" name="sort_order" value="0">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary modal-close">取消</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
保存
</button>
</div>
</form>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast"></div>
<!-- Edit Video Modal -->
<div id="videoModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 id="videoModalTitle">编辑视频</h3>
<button class="modal-close" onclick="document.getElementById('videoModal').classList.remove('show')">&times;</button>
</div>
<form id="videoEditForm">
<div class="modal-body">
<input type="hidden" id="editVideoId">
<div class="form-group">
<label for="editTitleCn">中文标题 *</label>
<input type="text" id="editTitleCn" name="title_cn" required>
</div>
<div class="form-group">
<label for="editTitleEn">英文标题 *</label>
<input type="text" id="editTitleEn" name="title_en" required>
</div>
<div class="form-group">
<label for="editDescCn">中文描述</label>
<textarea id="editDescCn" name="desc_cn" rows="3"></textarea>
</div>
<div class="form-group">
<label for="editDescEn">英文描述</label>
<textarea id="editDescEn" name="desc_en" rows="3"></textarea>
</div>
<div class="form-group">
<label for="editStatus">状态</label>
<select id="editStatus" name="status">
<option value="1">启用</option>
<option value="0">禁用</option>
<option value="2">处理中</option>
</select>
</div>
<div class="form-group">
<label for="editSortOrder">排序</label>
<input type="number" id="editSortOrder" name="sort_order" value="0">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="document.getElementById('videoModal').classList.remove('show')">取消</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
保存
</button>
</div>
</form>
</div>
</div>
<!-- 腾讯云VOD上传SDK -->
<script src="https://cdn-go.cn/cdn/vod-js-sdk-v6/latest/vod-js-sdk-v6.js"></script>
<script src="js/admin.js"></script>
</body>
</html>