Compare commits
5 Commits
c989a4973f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de68563f69 | ||
|
|
4f9702352a | ||
| 1129376981 | |||
|
|
5364edfc46 | ||
|
|
0b71afea29 |
183
001/001_r.html
183
001/001_r.html
@@ -258,7 +258,7 @@
|
||||
<tr class="header-row">
|
||||
<td colspan="3" align="center">
|
||||
<h1>内部库存管控系统 V4.2 (非密级)</h1>
|
||||
<p>当前登录: OPERATOR_8821 | <a href="#" onclick="alert('模拟注销')">[注销]</a> | <a href="#">[切换节点]</a> | <a href="#">[系统日志]</a> | <a href="#">[报错]</a></p>
|
||||
<p>当前登录: OPERATOR_8821 | <a href="#" onclick="showCustomAlert('模拟注销')">[注销]</a> | <a href="#">[切换节点]</a> | <a href="#">[系统日志]</a> | <a href="#">[报错]</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -294,39 +294,42 @@
|
||||
<td width="60%" valign="top" class="layout-cell main-content">
|
||||
<h2>库存列表 - 区域 A1</h2>
|
||||
|
||||
<form action="submit_filter">
|
||||
<form id="searchForm" onsubmit="event.preventDefault(); handleSearch();">
|
||||
<table border="0" width="100%" class="filter-table">
|
||||
<tr>
|
||||
<td>关键词: <input type="text" name="kw" size="30" placeholder="输入 ID 或名称"></td>
|
||||
<td>关键词: <input type="text" id="searchInput" name="kw" size="30" placeholder="输入 ID 或名称"></td>
|
||||
<td>
|
||||
类型:
|
||||
<select name="type">
|
||||
<select id="typeSelect" name="type">
|
||||
<option value="all">-- 所有 --</option>
|
||||
<option value="res">电阻</option>
|
||||
<option value="cap">电容</option>
|
||||
<option value="ind">电感</option>
|
||||
<option value="chip">芯片</option>
|
||||
<option value="conn">连接器</option>
|
||||
<option value="res">电阻 (Resistor)</option>
|
||||
<option value="cap">电容 (Capacitor)</option>
|
||||
<option value="ind">电感 (Inductor)</option>
|
||||
<option value="chip">芯片 (Chip)</option>
|
||||
<option value="conn">连接器 (Connector)</option>
|
||||
<option value="other">其他 (Other)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
状态:
|
||||
<label><input type="checkbox" name="st1" checked> 正常</label>
|
||||
<label><input type="checkbox" name="st2"> 警告</label>
|
||||
<label><input type="checkbox" name="st3"> 损坏</label>
|
||||
<label><input type="checkbox" name="st_normal" value="NORMAL" checked> 正常</label>
|
||||
<label><input type="checkbox" name="st_low" value="LOW" checked> 警告</label>
|
||||
<label><input type="checkbox" name="st_crit" value="CRITICAL" checked> 严重</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" style="padding-top:10px;">
|
||||
高级选项:
|
||||
<label><input type="radio" name="sort" value="date"> 按日期</label>
|
||||
排序:
|
||||
<label><input type="radio" name="sort" value="date" checked> 按更新日期</label>
|
||||
<label><input type="radio" name="sort" value="id"> 按ID</label>
|
||||
<label><input type="radio" name="sort" value="wt"> 按重量</label>
|
||||
<label><input type="radio" name="sort" value="pr"> 按优先级</label>
|
||||
<label><input type="radio" name="sort" value="qty"> 按库存量</label>
|
||||
<br><br>
|
||||
<input type="submit" value="开始检索">
|
||||
<input type="reset" value="重置条件">
|
||||
<input type="button" value="导出Excel (不可用)" disabled style="background:#eee; color:#aaa; cursor:not-allowed;">
|
||||
<button type="submit" class="page-btn active" style="padding:6px 20px;">
|
||||
<span id="search-spinner" class="spinner" style="display:none; width:12px; height:12px; border-width:2px; vertical-align:middle; margin-right:5px;"></span>
|
||||
开始检索
|
||||
</button>
|
||||
<button type="button" class="page-btn" onclick="resetSearch()">重置条件</button>
|
||||
<button type="button" class="page-btn" disabled style="opacity:0.6; cursor:not-allowed;">导出Excel</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -705,12 +708,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 6. 通用确认 模态框 -->
|
||||
<div class="modal-overlay" id="confirmModal">
|
||||
<div class="modal-window" style="width: 400px; min-height: auto;">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">操作确认</h3>
|
||||
<span class="modal-close" onclick="closeModal('confirmModal')">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id="confirmMessage" style="font-size: 1rem; color: #334155;">确定执行此操作?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="page-btn" onclick="closeModal('confirmModal')">取消</button>
|
||||
<button class="page-btn active" id="confirmBtnAction">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 7. 通用提示 模态框 (替代 alert) -->
|
||||
<div class="modal-overlay" id="alertModal">
|
||||
<div class="modal-window" style="width: 400px; min-height: auto;">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">系统提示</h3>
|
||||
<span class="modal-close" onclick="closeModal('alertModal')">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id="alertMessage" style="font-size: 1rem; color: #334155; white-space: pre-line;"></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="page-btn active" onclick="closeModal('alertModal')">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast 通知容器 -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
|
||||
<script>
|
||||
// === JavaScript 核心逻辑重构 (SPA模式) ===
|
||||
|
||||
// --- 自定义弹窗逻辑 (替代原生 alert/confirm) ---
|
||||
let onConfirmCallback = null;
|
||||
|
||||
function showCustomAlert(msg) {
|
||||
document.getElementById('alertMessage').innerText = msg;
|
||||
openModal('alertModal');
|
||||
}
|
||||
|
||||
function showCustomConfirm(msg, callback) {
|
||||
document.getElementById('confirmMessage').innerText = msg;
|
||||
onConfirmCallback = callback;
|
||||
openModal('confirmModal');
|
||||
}
|
||||
|
||||
// 初始化绑定 Confirm 按钮事件
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('confirmBtnAction').addEventListener('click', () => {
|
||||
if (typeof onConfirmCallback === 'function') {
|
||||
onConfirmCallback();
|
||||
}
|
||||
closeModal('confirmModal');
|
||||
});
|
||||
});
|
||||
|
||||
// 配置与状态
|
||||
const CONFIG = {
|
||||
totalItems: 358, // 模拟总数据量
|
||||
@@ -735,6 +796,82 @@
|
||||
|
||||
// --- 导航与通用模态框 ---
|
||||
|
||||
// --- 搜索逻辑 ---
|
||||
function handleSearch() {
|
||||
const spinner = document.getElementById('search-spinner');
|
||||
spinner.style.display = 'inline-block';
|
||||
|
||||
// 获取筛选条件
|
||||
const kw = document.getElementById('searchInput').value.toLowerCase().trim();
|
||||
const typeFilter = document.getElementById('typeSelect').value;
|
||||
const checkedStatuses = [];
|
||||
if(document.querySelector('input[name="st_normal"]').checked) checkedStatuses.push('NORMAL');
|
||||
if(document.querySelector('input[name="st_low"]').checked) checkedStatuses.push('LOW');
|
||||
if(document.querySelector('input[name="st_crit"]').checked) checkedStatuses.push('CRITICAL');
|
||||
|
||||
// 获取排序
|
||||
const sortVal = document.querySelector('input[name="sort"]:checked').value;
|
||||
|
||||
// 模拟网络延迟
|
||||
setTimeout(() => {
|
||||
state.filteredData = state.data.filter(item => {
|
||||
// 1. 关键词匹配 (ID, Name, Supplier, Batch)
|
||||
const matchKw = !kw ||
|
||||
item.id.toLowerCase().includes(kw) ||
|
||||
item.name.toLowerCase().includes(kw) ||
|
||||
item.supplier.toLowerCase().includes(kw) ||
|
||||
item.batch.toLowerCase().includes(kw);
|
||||
|
||||
// 2. 类型匹配 (简单的字符串包含判断)
|
||||
let matchType = true;
|
||||
if (typeFilter !== 'all') {
|
||||
if (typeFilter === 'res') matchType = item.name.includes('Resistor');
|
||||
else if (typeFilter === 'cap') matchType = item.name.includes('Capacitor');
|
||||
else if (typeFilter === 'ind') matchType = item.name.includes('Inductor');
|
||||
else if (typeFilter === 'chip') matchType = item.name.includes('MCU') || item.name.includes('Regulator') || item.name.includes('Transistor') || item.name.includes('Diode');
|
||||
else if (typeFilter === 'conn') matchType = item.name.includes('Connector') || item.name.includes('Header');
|
||||
else if (typeFilter === 'other') matchType = !item.name.includes('Resist') && !item.name.includes('Capacit') && !item.name.includes('Induct') && !item.name.includes('Connect');
|
||||
}
|
||||
|
||||
// 3. 状态匹配 (注意: 之前生成的 Mock Status 包含 DAMAGED/PENDING,但Checkbox只有三种,需兼容)
|
||||
// 这里只筛选三种主要显示状态,如果用户没选也没事
|
||||
let matchStatus = false;
|
||||
if (checkedStatuses.length === 0) matchStatus = true; // 如果全不选,默认全显示?或者全不显示?通常全不选意味着什么都不看,或者看全部...
|
||||
// 为了用户体验,全不选就当全选吧 (或者严谨点就是空)
|
||||
// 这里逻辑:只要item.status在checkedStatuses里就显示
|
||||
// 特殊处理: CRITICAL 包含了 Mock 里的 CRITICAL 和 DAMAGED (假设)
|
||||
if (checkedStatuses.includes(item.status)) matchStatus = true;
|
||||
|
||||
// 修正逻辑:如果勾选了CRITICAL,我们把DAMAGED也算进去?
|
||||
if (checkedStatuses.includes('CRITICAL') && item.status === 'DAMAGED') matchStatus = true;
|
||||
|
||||
return matchKw && matchType && matchStatus;
|
||||
});
|
||||
|
||||
// 排序
|
||||
if (sortVal === 'id') {
|
||||
state.filteredData.sort((a,b) => a.id.localeCompare(b.id));
|
||||
} else if (sortVal === 'qty') {
|
||||
state.filteredData.sort((a,b) => b.qty - a.qty); // Fixed: property name is qty
|
||||
} else if (sortVal === 'date') {
|
||||
state.filteredData.sort((a,b) => new Date(b.date) - new Date(a.date));
|
||||
}
|
||||
|
||||
state.currentPage = 1;
|
||||
renderTable();
|
||||
spinner.style.display = 'none';
|
||||
showToast(`检索完成,找到 ${state.filteredData.length} 条记录`, 'success');
|
||||
}, 400);
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
document.getElementById('typeSelect').value = 'all';
|
||||
document.querySelectorAll('input[type="checkbox"]').forEach(c => c.checked = true);
|
||||
document.querySelector('input[value="date"]').checked = true;
|
||||
handleSearch();
|
||||
}
|
||||
|
||||
function openModal(id) {
|
||||
const modal = document.getElementById(id);
|
||||
if (modal) {
|
||||
@@ -1015,17 +1152,17 @@
|
||||
}
|
||||
|
||||
function printDetail() {
|
||||
alert("正在连接打印机... \n(模拟: 发送指令 PCL_PRINT_JOB_001)");
|
||||
showCustomAlert("正在连接打印机... \n(模拟: 发送指令 PCL_PRINT_JOB_001)");
|
||||
}
|
||||
|
||||
// 删除项目
|
||||
function deleteItem(id, btnElement) {
|
||||
if(confirm(`确定要删除物料 ${id} 吗?`)) {
|
||||
// 这只是前端模拟,实际应该发请求
|
||||
showCustomConfirm(`确定要删除物料 ${id} 吗?`, () => {
|
||||
// 这只是前端模拟,实际应该发请求
|
||||
state.data = state.data.filter(d => d.id !== id);
|
||||
applyFilter(); // 重新走一遍筛选和排序
|
||||
showToast(`物料 ${id} 已删除`, "warning");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 批量操作
|
||||
|
||||
13
001/record.json
Normal file
13
001/record.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"step-1": {
|
||||
"query": "我要检索严重状态物料,请你先帮我点击检索栏中的正常状态以取消选中",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-2": {
|
||||
"query": "我要检索严重状态物料,请你再点击检索栏中的警告状态以取消选中",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-3": {
|
||||
|
||||
}
|
||||
}
|
||||
1142
002/002_r.html
1142
002/002_r.html
File diff suppressed because it is too large
Load Diff
392
003/003_r.html
392
003/003_r.html
@@ -113,6 +113,30 @@
|
||||
/* 分页 */
|
||||
.pagination { display: flex; align-items: center; justify-content: flex-end; padding: 15px; gap: 10px; }
|
||||
.pagination button { background: #fff; border: 1px solid #d9d9d9; padding: 5px 10px; border-radius: 4px; cursor: pointer; }
|
||||
|
||||
/* === New Interactive Elements === */
|
||||
/* Modal */
|
||||
.modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: none; justify-content: center; align-items: center; z-index: 1000; }
|
||||
.modal-content { background: #fff; width: 500px; padding: 20px; border-radius: 4px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); animation: fadeIn 0.3s; }
|
||||
.modal-header { font-size: 16px; font-weight: bold; margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 10px; display: flex; justify-content: space-between; }
|
||||
|
||||
/* Drawer (Right Panel) */
|
||||
.drawer-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.2); z-index: 900; display: none; }
|
||||
.drawer { position: fixed; top: 0; right: -450px; width: 450px; height: 100%; background: #fff; box-shadow: -2px 0 8px rgba(0,0,0,0.1); transition: right 0.3s ease; z-index: 901; display: flex; flex-direction: column; }
|
||||
.drawer.open { right: 0; }
|
||||
.drawer-header { padding: 20px; border-bottom: 1px solid #eee; background: #fafafa; display: flex; justify-content: space-between; align-items: center; }
|
||||
.drawer-body { padding: 20px; flex: 1; overflow-y: auto; }
|
||||
|
||||
/* Toast Notification */
|
||||
.toast { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #333; color: #fff; padding: 10px 20px; border-radius: 4px; z-index: 2000; display: none; opacity: 0; transition: opacity 0.3s; }
|
||||
.toast.show { display: block; opacity: 1; }
|
||||
|
||||
/* Form Styles */
|
||||
.form-group { margin-bottom: 15px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; color: #666; font-weight: 500; }
|
||||
.form-input { width: 100%; padding: 8px; border: 1px solid #d9d9d9; border-radius: 4px; box-sizing: border-box; }
|
||||
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -137,10 +161,10 @@
|
||||
<div class="sidebar">
|
||||
<h3>资源列表</h3>
|
||||
<ul>
|
||||
<li><a href="#" class="active">全部实例 (14)</a></li>
|
||||
<li><a href="#">运行中 (10)</a></li>
|
||||
<li><a href="#">已停止 (3)</a></li>
|
||||
<li><a href="#">异常/维护 (1)</a></li>
|
||||
<li><a href="javascript:void(0)" class="active" onclick="filterByStatus('all', this)">全部实例 (14)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="filterByStatus('running', this)">运行中 (10)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="filterByStatus('stopped', this)">已停止 (3)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="filterByStatus('maintenance', this)">异常/维护 (1)</a></li>
|
||||
</ul>
|
||||
|
||||
<h3>配额监控</h3>
|
||||
@@ -169,7 +193,7 @@
|
||||
|
||||
<form class="search-bar">
|
||||
<fieldset>
|
||||
<label>关键词:</label> <input type="text" placeholder="Instance ID / Name">
|
||||
<label>关键词:</label> <input type="text" id="searchInput" placeholder="Instance ID / Name">
|
||||
<label>标签:</label> <input type="text" placeholder="Key:Value">
|
||||
<label>付费类型:</label>
|
||||
<select>
|
||||
@@ -178,17 +202,18 @@
|
||||
<option>按量付费</option>
|
||||
<option>抢占式实例</option>
|
||||
</select>
|
||||
<button type="button" class="btn-primary" onclick="alert('Searching...')">刷新列表</button>
|
||||
<button type="button">重置</button>
|
||||
<button type="button" class="btn-primary" onclick="searchInstances()">刷新列表</button>
|
||||
<button type="button" onclick="resetSearch()">重置</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="toolbar">
|
||||
<button>启动</button>
|
||||
<button>停止</button>
|
||||
<button>重启</button>
|
||||
<button>释放设置</button>
|
||||
<button>修改计费模式</button>
|
||||
<button style="background: var(--primary); color: #fff; border-color: var(--primary);" onclick="openCreateModal()">+ 创建实例</button>
|
||||
<button onclick="performToolbarAction('start')">启动</button>
|
||||
<button onclick="performToolbarAction('stop')">停止</button>
|
||||
<button onclick="performToolbarAction('restart')">重启</button>
|
||||
<button onclick="showToast('功能开发中: 修改释放设置', 'warning')">释放设置</button>
|
||||
<button onclick="showToast('功能开发中: 修改计费模式', 'warning')">修改计费模式</button>
|
||||
</div>
|
||||
|
||||
<div class="instance-list">
|
||||
@@ -221,11 +246,11 @@
|
||||
<span class="status-running">运行中</span>
|
||||
</div>
|
||||
<div class="action-group">
|
||||
<button>远程连接</button>
|
||||
<button>监控</button>
|
||||
<button>更多...</button>
|
||||
<button class="btn-danger" onclick="confirmDelete()">强制停止</button>
|
||||
<button class="btn-danger" onclick="confirmDelete()">彻底销毁</button>
|
||||
<button onclick="remoteConnect('i-bp1j2k3l4m5n')">远程连接</button>
|
||||
<button onclick="openMonitor('i-bp1j2k3l4m5n')">监控</button>
|
||||
<button onclick="showMoreMenu(this)">更多...</button>
|
||||
<button class="btn-danger" onclick="confirmDelete('i-bp1j2k3l4m5n')">强制停止</button>
|
||||
<button class="btn-danger" onclick="confirmDelete('i-bp1j2k3l4m5n', true)">彻底销毁</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -275,8 +300,8 @@
|
||||
<span>未开通</span>
|
||||
</div>
|
||||
<div class="action-group">
|
||||
<button style="color: #fa8c16; font-weight:bold;">立即开通</button>
|
||||
<button>了解详情</button>
|
||||
<button style="color: #fa8c16; font-weight:bold;" onclick="openProductIntro('scaling')">立即开通</button>
|
||||
<button onclick="openProductIntro('scaling_doc')">了解详情</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -404,7 +429,7 @@
|
||||
</div>
|
||||
<div style="grid-column: 1 / -1; margin-top: 5px;">
|
||||
<p>请及时充值,以免影响实例的正常运行。</p>
|
||||
<button style="background: #f5222d; color: white; border: none; padding: 4px 12px; border-radius: 2px;">立即充值</button>
|
||||
<button onclick="openRecharge()" style="background: #f5222d; color: white; border: none; padding: 4px 12px; border-radius: 2px;">立即充值</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -438,10 +463,10 @@
|
||||
</div>
|
||||
|
||||
<div class="pagination">
|
||||
<button>< 上一页</button>
|
||||
<span>第 1 / 5 页</span>
|
||||
<button>下一页 ></button>
|
||||
<select>
|
||||
<button onclick="changePage(-1)">< 上一页</button>
|
||||
<span id="pageInfo">第 1 / 5 页</span>
|
||||
<button onclick="changePage(1)">下一页 ></button>
|
||||
<select onchange="changePageSize(this)">
|
||||
<option>每页 10 条</option>
|
||||
<option>每页 20 条</option>
|
||||
<option>每页 50 条</option>
|
||||
@@ -457,9 +482,159 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 脚本逻辑:处理全选和危险操作确认
|
||||
|
||||
<!-- Components -->
|
||||
|
||||
<!-- Create Instance Modal -->
|
||||
<div id="createModal" class="modal-overlay">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<span>创建新实例 (ECI)</span>
|
||||
<span onclick="closeCreateModal()" style="cursor:pointer; color:#999;">✕</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>实例名称</label>
|
||||
<input type="text" id="newInstanceName" class="form-input" placeholder="例如: Web-Server-02">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>镜像</label>
|
||||
<select id="newInstanceImage" class="form-input">
|
||||
<option value="Ubuntu 22.04 LTS">Ubuntu 22.04 LTS</option>
|
||||
<option value="CentOS 7.9">CentOS 7.9</option>
|
||||
<option value="Aliyun Linux 3">Aliyun Linux 3</option>
|
||||
<option value="Windows Server 2022">Windows Server 2022</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>规格</label>
|
||||
<select id="newInstanceType" class="form-input">
|
||||
<option value="2 vCPU / 4 GiB">ecs.t6-c1m2.large (2 vCPU / 4 GiB)</option>
|
||||
<option value="4 vCPU / 8 GiB">ecs.c7.xlarge (4 vCPU / 8 GiB)</option>
|
||||
<option value="8 vCPU / 16 GiB">ecs.g7.2xlarge (8 vCPU / 16 GiB)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="text-align: right; margin-top: 20px;">
|
||||
<button onclick="closeCreateModal()" style="margin-right: 10px; padding: 6px 15px; border: 1px solid #d9d9d9; background: #fff; cursor: pointer; border-radius: 4px;">取消</button>
|
||||
<button onclick="confirmCreate()" style="padding: 6px 15px; background: var(--primary); color: #fff; border: none; cursor: pointer; border-radius: 4px;">立即购买</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Instance Detail Drawer -->
|
||||
<div id="drawerOverlay" class="drawer-overlay" onclick="closeDrawer()"></div>
|
||||
<div id="detailDrawer" class="drawer">
|
||||
<div class="drawer-header">
|
||||
<h3 id="drawerTitle">Instance Details</h3>
|
||||
<button onclick="closeDrawer()" style="border:none; background:none; cursor:pointer; font-size:16px;">✕</button>
|
||||
</div>
|
||||
<div class="drawer-body">
|
||||
<div style="background: #f5f5f5; padding: 15px; border-radius: 4px; margin-bottom: 20px;">
|
||||
<p><strong>Status:</strong> <span style="color:green">Running</span></p>
|
||||
<p><strong>Region:</strong> CN-East-2 (Zone B)</p>
|
||||
<p><strong>Public IP:</strong> 139.196.128.44</p>
|
||||
<p><strong>Private IP:</strong> 192.168.1.101</p>
|
||||
</div>
|
||||
|
||||
<h4>监控概览 (1 Hour)</h4>
|
||||
<div style="height: 100px; background: #fafafa; border: 1px solid #eee; display: flex; align-items: flex-end; padding: 10px; gap: 5px;">
|
||||
<!-- Fake Chart Bars -->
|
||||
<div style="width: 10%; height: 30%; background: #badde8;"></div>
|
||||
<div style="width: 10%; height: 50%; background: #badde8;"></div>
|
||||
<div style="width: 10%; height: 80%; background: #108ee9;"></div>
|
||||
<div style="width: 10%; height: 60%; background: #badde8;"></div>
|
||||
<div style="width: 10%; height: 40%; background: #badde8;"></div>
|
||||
<div style="width: 10%; height: 90%; background: #f04134;"></div>
|
||||
<div style="width: 10%; height: 50%; background: #badde8;"></div>
|
||||
<div style="width: 10%; height: 30%; background: #badde8;"></div>
|
||||
</div>
|
||||
|
||||
<h4 style="margin-top:20px;">配置信息</h4>
|
||||
<ul style="line-height:2; color:#666;">
|
||||
<li>Instance Type: ecs.g7.xlarge</li>
|
||||
<li>Image ID: ubuntu_22_04_x64_20G_alibase</li>
|
||||
<li>Security Group: sg-bp12345678</li>
|
||||
<li>VPC ID: vpc-bp1abcdefg</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toast" class="toast">Action Successful</div>
|
||||
|
||||
<script>
|
||||
// --- State Management ---
|
||||
|
||||
// Toast
|
||||
function showToast(msg) {
|
||||
const t = document.getElementById('toast');
|
||||
t.innerText = msg;
|
||||
t.classList.add('show');
|
||||
setTimeout(() => t.classList.remove('show'), 3000);
|
||||
}
|
||||
|
||||
// Modal Logic
|
||||
function openCreateModal() {
|
||||
document.getElementById('createModal').style.display = 'flex';
|
||||
}
|
||||
function closeCreateModal() {
|
||||
document.getElementById('createModal').style.display = 'none';
|
||||
document.getElementById('newInstanceName').value = '';
|
||||
}
|
||||
function confirmCreate() {
|
||||
showToast('订单已提交,实例正在初始化...');
|
||||
closeCreateModal();
|
||||
// Here we could simulate adding a row, but for static demo toast is enough
|
||||
setTimeout(() => {
|
||||
// Simulate "Created" by navigating or refreshing? No, just an alert.
|
||||
// Ideally we add a row to DOM
|
||||
addInstanceRow();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function addInstanceRow() {
|
||||
const name = document.getElementById('newInstanceName').value || 'New-Instance-' + Math.floor(Math.random()*1000);
|
||||
const list = document.querySelector('.instance-list');
|
||||
const newRow = document.createElement('div');
|
||||
newRow.className = 'list-row';
|
||||
newRow.innerHTML = `
|
||||
<div><input type="checkbox" class="row-checkbox"></div>
|
||||
<div>
|
||||
<strong onclick="openDrawer('${name}')">${name}</strong><br>
|
||||
<small>镜像: Ubuntu 22.04</small>
|
||||
</div>
|
||||
<div><span>Checking...</span><br><span style="color:#999">192.168.1.${Math.floor(Math.random()*255)}</span></div>
|
||||
<div><span>2 vCPU</span><br><span>4 GiB</span></div>
|
||||
<div><span class="status-running" style="color:#fa8c16">启动中...</span></div>
|
||||
<div class="action-group">
|
||||
<button>管理</button>
|
||||
</div>
|
||||
`;
|
||||
// Insert after header
|
||||
list.insertBefore(newRow, list.children[1]);
|
||||
}
|
||||
|
||||
// Drawer Logic
|
||||
function openDrawer(name) {
|
||||
document.getElementById('drawerTitle').innerText = name || 'Instance Details';
|
||||
document.getElementById('drawerOverlay').style.display = 'block';
|
||||
setTimeout(() => document.getElementById('detailDrawer').classList.add('open'), 10);
|
||||
}
|
||||
function closeDrawer() {
|
||||
document.getElementById('detailDrawer').classList.remove('open');
|
||||
setTimeout(() => document.getElementById('drawerOverlay').style.display = 'none', 300);
|
||||
}
|
||||
|
||||
// Bind click events for all existing instance names
|
||||
document.querySelectorAll('.list-row strong').forEach(el => {
|
||||
// Remove old onclick
|
||||
el.removeAttribute('onclick');
|
||||
el.addEventListener('click', function() {
|
||||
// Get name text
|
||||
const name = this.innerText.split('(')[0].trim() || 'Instance';
|
||||
openDrawer(name);
|
||||
});
|
||||
});
|
||||
|
||||
// Toolbar Actions
|
||||
// 全选/取消全选
|
||||
document.getElementById('selectAll').addEventListener('change', function(e) {
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox');
|
||||
@@ -468,15 +643,174 @@
|
||||
});
|
||||
});
|
||||
|
||||
function performAction(action) {
|
||||
// Get selected
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||
if (checkboxes.length === 0) {
|
||||
alert('请先选择至少一个实例');
|
||||
return;
|
||||
}
|
||||
|
||||
const count = checkboxes.length;
|
||||
if(confirm(`确定要对选中的 ${count} 台实例执行 [${action.toUpperCase()}] 操作吗?`)) {
|
||||
showToast(`指令已下发: ${action.toUpperCase()} ${count} instances`);
|
||||
// Reset selection
|
||||
checkboxes.forEach(c => c.checked = false);
|
||||
document.getElementById('selectAll').checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 危险操作二次确认
|
||||
function confirmDelete() {
|
||||
const userInput = prompt("这是一个高风险操作!\n请输入 'DELETE' 以确认销毁该实例:");
|
||||
if (userInput === 'DELETE') {
|
||||
alert('操作已提交:实例正在销毁中...');
|
||||
} else {
|
||||
alert('操作已取消。');
|
||||
showToast('操作已提交:实例正在销毁中...');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Enhanced Interactivity (New)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// 1. Sidebar Filter
|
||||
function filterByStatus(status, el) {
|
||||
// Update URL hash for simulation
|
||||
window.location.hash = status;
|
||||
|
||||
// Active state
|
||||
document.querySelectorAll('.sidebar li a').forEach(a => a.classList.remove('active'));
|
||||
if(el) el.classList.add('active');
|
||||
|
||||
const rows = document.querySelectorAll('.list-row:not(.ad-row):not(.billing-alert-row)');
|
||||
|
||||
rows.forEach(row => {
|
||||
const statusText = row.querySelector('div:nth-child(5)').innerText.trim();
|
||||
let show = false;
|
||||
|
||||
if (status === 'all') show = true;
|
||||
else if (status === 'running' && (statusText.includes('运行中') || statusText.includes('启动中'))) show = true;
|
||||
else if (status === 'stopped' && statusText.includes('已停止')) show = true;
|
||||
else if (status === 'maintenance' && statusText.includes('维护')) show = true;
|
||||
|
||||
row.style.display = show ? 'grid' : 'none';
|
||||
});
|
||||
showToast(`已筛选: ${el ? el.innerText : status}`);
|
||||
}
|
||||
|
||||
// 2. Toolbar Logic (Renamed to avoid conflict)
|
||||
function performToolbarAction(action) {
|
||||
// Re-use existing logic, just better naming
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||
if (checkboxes.length === 0) {
|
||||
alert('请先勾选需要操作的实例');
|
||||
return;
|
||||
}
|
||||
showToast(`正在对 ${checkboxes.length} 台实例执行 [${action}]...`);
|
||||
setTimeout(() => {
|
||||
showToast('操作指令已下发');
|
||||
checkboxes.forEach(c => c.checked = false);
|
||||
document.getElementById('selectAll').checked = false;
|
||||
}, 800);
|
||||
}
|
||||
|
||||
// 3. Row Actions
|
||||
function remoteConnect(instanceId) {
|
||||
const width = 800;
|
||||
const height = 600;
|
||||
const left = (screen.width - width) / 2;
|
||||
const top = (screen.height - height) / 2;
|
||||
// Open a fake terminal window
|
||||
const win = window.open("", "_blank", `width=${width},height=${height},top=${top},left=${left}`);
|
||||
win.document.write(`
|
||||
<body style="background:#000; color:#0f0; font-family:monospace; padding:20px;">
|
||||
<p>Connecting to ${instanceId}...</p>
|
||||
<p>Authenticating...</p>
|
||||
<p>Welcome to Ubuntu 22.04 LTS</p>
|
||||
<p>root@${instanceId}:~# <span id="cursor">_</span></p>
|
||||
<script>
|
||||
setInterval(() => {
|
||||
const c = document.getElementById('cursor');
|
||||
c.style.visibility = c.style.visibility === 'hidden' ? 'visible' : 'hidden';
|
||||
}, 500);
|
||||
<\/script>
|
||||
</body>
|
||||
`);
|
||||
}
|
||||
|
||||
function openMonitor(instanceId) {
|
||||
openDrawer(instanceId + ' - 实时监控');
|
||||
}
|
||||
|
||||
function showMoreMenu(btn) {
|
||||
// Simple fallback
|
||||
const actions = ['创建快照', '变更配置', '重置密码', '更换操作系统'];
|
||||
const action = prompt(`[${actions.join(' | ')}]\n请输入要执行的操作:`, actions[0]);
|
||||
if(action) {
|
||||
showToast(`正在执行: ${action}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Search Bar
|
||||
function searchInstances() {
|
||||
const val = document.getElementById('searchInput').value;
|
||||
if(!val) {
|
||||
// refresh
|
||||
showToast('刷新列表成功');
|
||||
// reset filters
|
||||
filterByStatus('all', document.querySelector('.sidebar a.active'));
|
||||
} else {
|
||||
showToast(`正在搜索 "${val}"...`);
|
||||
}
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
// Trigger input event to clear filter
|
||||
document.getElementById('searchInput').dispatchEvent(new Event('input'));
|
||||
showToast('搜索条件已重置');
|
||||
}
|
||||
|
||||
// 5. Pagination
|
||||
let currentPage = 1;
|
||||
function changePage(dir) {
|
||||
const newPage = currentPage + dir;
|
||||
if(newPage < 1 || newPage > 5) return;
|
||||
|
||||
currentPage = newPage;
|
||||
document.getElementById('pageInfo').innerText = `第 ${currentPage} / 5 页`;
|
||||
|
||||
// Fake loading effect
|
||||
const list = document.querySelector('.instance-list');
|
||||
list.style.opacity = '0.5';
|
||||
setTimeout(() => {
|
||||
list.style.opacity = '1';
|
||||
// Scroll to top
|
||||
list.scrollIntoView({behavior: "smooth"});
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function changePageSize(select) {
|
||||
showToast(`分页设置已更新: ${select.value}`);
|
||||
}
|
||||
|
||||
// 6. Billing & Ads
|
||||
function openRecharge() {
|
||||
if(confirm("将跳转至支付网关 (Alipay/WeChat)...")) {
|
||||
showToast("正在跳转支付页面...");
|
||||
}
|
||||
}
|
||||
|
||||
function openProductIntro(product) {
|
||||
showToast(`正在打开产品文档: ${product}...`);
|
||||
}
|
||||
|
||||
// Override generic confirmDelete
|
||||
window.confirmDelete = function(instanceId, isHard) {
|
||||
if(confirm(`警告: 确定要${isHard ? '彻底销毁' : '强制停止'}实例 [${instanceId}] 吗?\n此操作不可逆!`)) {
|
||||
showToast('操作已提交');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
925
004/004_r.html
925
004/004_r.html
@@ -5,103 +5,263 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BSOD Help - System_Thread_Exception - TechZone Forums</title>
|
||||
<style>
|
||||
/* CSS Reset */
|
||||
/* === CSS Variables & Reset === */
|
||||
:root {
|
||||
--primary: #1877f2;
|
||||
--secondary: #42b72a;
|
||||
--bg-body: #f0f2f5;
|
||||
--bg-card: #ffffff;
|
||||
--text-main: #1c1e21;
|
||||
--text-sub: #65676b;
|
||||
--border: #dddfe2;
|
||||
--header-height: 60px;
|
||||
--danger: #dc3545;
|
||||
--warning: #ffc107;
|
||||
}
|
||||
|
||||
/* Dark Mode Support */
|
||||
body.dark-mode {
|
||||
--primary: #4599ff;
|
||||
--secondary: #42b72a;
|
||||
--bg-body: #18191a;
|
||||
--bg-card: #242526;
|
||||
--text-main: #e4e6eb;
|
||||
--text-sub: #b0b3b8;
|
||||
--border: #3e4042;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #e9ebee; margin: 0; color: #1c1e21; line-height: 1.5; }
|
||||
a { text-decoration: none; color: #365899; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
background-color: var(--bg-body);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
padding-top: var(--header-height); /* Nav spacing */
|
||||
transition: background 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
a { text-decoration: none; color: var(--primary); cursor: pointer; }
|
||||
a:hover { text-decoration: underline; }
|
||||
ul { padding-left: 20px; }
|
||||
ul { list-style: none; padding: 0; margin: 0; }
|
||||
|
||||
/* 容器布局 */
|
||||
.container { max-width: 1200px; margin: 0 auto; background: transparent; }
|
||||
.content-wrapper { display: flex; gap: 20px; padding: 20px; }
|
||||
.main-column { flex: 3; }
|
||||
.side-column { flex: 1; }
|
||||
/* === Layout Components === */
|
||||
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||||
.layout-grid { display: grid; grid-template-columns: 280px 1fr 300px; gap: 20px; }
|
||||
|
||||
/* 顶部导航 */
|
||||
.header { background: #fff; padding: 15px 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.header h1 { margin: 0; font-size: 24px; color: #4267b2; }
|
||||
.header p { margin: 0; font-size: 12px; color: #999; }
|
||||
.nav-links a { margin-right: 15px; font-weight: bold; color: #4b4f56; }
|
||||
.search-bar input { padding: 5px; border: 1px solid #ccc; border-radius: 3px; }
|
||||
/* Thread View Layout Fix */
|
||||
/* 当处于帖子详情页时,我们将隐藏左侧边栏,只保留 主内容区(1fr) 和 右侧边栏(300px) */
|
||||
.layout-grid.thread-view { grid-template-columns: 1fr 300px; }
|
||||
.layout-grid.thread-view .sidebar { display: none; } /* 关键修复:隐藏左侧导航 */
|
||||
|
||||
/* 帖子样式 */
|
||||
.post-title { background: #fff; padding: 15px; border-radius: 4px; border: 1px solid #ddd; margin-bottom: 10px; }
|
||||
.post-title h2 { margin: 0 0 10px 0; }
|
||||
/* Responsive */
|
||||
@media (max-width: 1000px) {
|
||||
.layout-grid { grid-template-columns: 1fr; }
|
||||
.sidebar { display: none; } /* Hide sidebar on small screens for simplicty */
|
||||
.layout-grid.thread-view { grid-template-columns: 1fr; } /* 移动端响应式 */
|
||||
.layout-grid.thread-view .sidebar-right { display: none; } /* 移动端帖子页隐藏右侧栏 */
|
||||
}
|
||||
|
||||
/* 楼层卡片 (原Table转换) */
|
||||
.post-card { background: #fff; border: 1px solid #ddd; border-radius: 3px; margin-bottom: 15px; display: flex; flex-direction: column; }
|
||||
/* 用CSS强制改变table的默认显示方式,使其像现代Div布局 */
|
||||
.post-card table { width: 100%; border-collapse: collapse; border: none; }
|
||||
.post-card td { border: none; padding: 15px; }
|
||||
.user-info-cell { background: #f7f7f7; border-right: 1px solid #eee !important; width: 140px; text-align: center; font-size: 12px; }
|
||||
.user-info-cell img { width: 80px; height: 80px; border-radius: 50%; background: #ddd; margin-top: 10px; }
|
||||
.content-cell { position: relative; }
|
||||
/* === Fixed Header === */
|
||||
.site-header {
|
||||
position: fixed; top: 0; left: 0; right: 0;
|
||||
height: var(--header-height);
|
||||
background: var(--bg-card);
|
||||
border-bottom: 1px solid var(--border);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
z-index: 1000;
|
||||
display: flex; align-items: center; padding: 0 20px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.logo { font-size: 1.5rem; font-weight: bold; color: var(--primary); display: flex; align-items: center; gap: 10px; }
|
||||
.search-bar { position: relative; width: 400px; }
|
||||
.search-bar input {
|
||||
width: 100%; padding: 8px 15px; border-radius: 20px;
|
||||
border: 1px solid var(--border); background: var(--bg-body);
|
||||
color: var(--text-main);
|
||||
}
|
||||
.nav-user { display: flex; gap: 15px; align-items: center; }
|
||||
.user-avatar-sm { width: 32px; height: 32px; border-radius: 50%; background: #ccc; cursor: pointer; }
|
||||
|
||||
/* 帖子元数据 */
|
||||
.post-meta { font-size: 12px; color: #90949c; margin-bottom: 10px; border-bottom: 1px solid #eee; padding-bottom: 5px; }
|
||||
/* === Cards & Panels === */
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.card-header {
|
||||
padding: 12px 15px; border-bottom: 1px solid var(--border);
|
||||
font-weight: 600; font-size: 0.95rem; display: flex; justify-content: space-between;
|
||||
}
|
||||
.card-body { padding: 15px; }
|
||||
|
||||
/* 附件区域 */
|
||||
fieldset { border: 1px solid #d8dfea; background: #f7f7f7; padding: 10px; margin: 10px 0; border-radius: 4px; }
|
||||
legend { font-weight: bold; color: #4b4f56; }
|
||||
/* === Forum List Styles === */
|
||||
.forum-category-item { display: flex; justify-content: space-between; padding: 10px; border-bottom: 1px solid var(--border); cursor: pointer; }
|
||||
.forum-category-item:hover { background: rgba(0,0,0,0.02); }
|
||||
.thread-item {
|
||||
display: flex; gap: 15px; padding: 15px; border-bottom: 1px solid var(--border);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.thread-item:hover { background: rgba(0,0,0,0.02); transform: translateX(5px); }
|
||||
.thread-stats {
|
||||
display: flex; flex-direction: column; align-items: center; min-width: 60px;
|
||||
color: var(--text-sub); font-size: 0.8rem;
|
||||
}
|
||||
.stat-count { font-size: 1.1rem; font-weight: bold; color: var(--text-main); }
|
||||
.thread-main { flex: 1; }
|
||||
.thread-title { font-size: 1.1rem; font-weight: 500; margin-bottom: 5px; display: block; color: var(--text-main); }
|
||||
.thread-meta { font-size: 0.85rem; color: var(--text-sub); display: flex; gap: 10px; }
|
||||
.tag { padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; background: #eee; color: #555; }
|
||||
.tag.red { background: #fee2e2; color: #b91c1c; }
|
||||
.tag.blue { background: #e0f2fe; color: #0369a1; }
|
||||
|
||||
/* 按钮组 */
|
||||
.action-bar { background: #f6f7f9; border-top: 1px solid #e9ebee; padding: 8px 15px !important; text-align: right !important; }
|
||||
.action-bar button { background: transparent; border: none; color: #4b4f56; cursor: pointer; font-weight: bold; font-size: 12px; margin-left: 10px; }
|
||||
.action-bar button:hover { color: #4267b2; background: #eee; border-radius: 2px; }
|
||||
/* === Post View Styles (Logic Refactored from Tables to Flex) === */
|
||||
.post-container { display: flex; border-bottom: 1px solid var(--border); }
|
||||
.post-sidebar {
|
||||
width: 180px; background: rgba(0,0,0,0.02); border-right: 1px solid var(--border);
|
||||
padding: 20px; text-align: center; flex-shrink: 0;
|
||||
}
|
||||
.post-avatar-lg { width: 100px; height: 100px; border-radius: 4px; background: #ddd; margin-bottom: 10px; object-fit: cover; }
|
||||
.user-badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: bold; margin: 5px 0; }
|
||||
.post-content-area { flex: 1; padding: 20px; position: relative; min-height: 200px; }
|
||||
.post-meta-header {
|
||||
border-bottom: 1px dashed var(--border); padding-bottom: 10px; margin-bottom: 15px;
|
||||
font-size: 0.85rem; color: var(--text-sub); display: flex; justify-content: space-between;
|
||||
}
|
||||
.post-body { font-size: 1rem; line-height: 1.7; min-height: 100px; }
|
||||
.post-signature {
|
||||
margin-top: 30px; border-top: 1px dashed var(--border); padding-top: 10px;
|
||||
color: var(--text-sub); font-size: 0.85rem; font-style: italic;
|
||||
}
|
||||
.post-actions {
|
||||
margin-top: 20px; display: flex; justify-content: flex-end; gap: 10px;
|
||||
}
|
||||
.btn-action {
|
||||
background: transparent; border: 1px solid transparent; color: var(--text-sub);
|
||||
padding: 5px 10px; border-radius: 4px; font-size: 0.85rem; cursor: pointer;
|
||||
}
|
||||
.btn-action:hover { background: rgba(0,0,0,0.05); color: var(--primary); }
|
||||
|
||||
/* 特殊身份标识 */
|
||||
.badge-mod { color: green; font-weight: bold; }
|
||||
.badge-new { color: #888; }
|
||||
/* === Components === */
|
||||
.btn { padding: 8px 16px; border-radius: 6px; border: none; font-weight: 600; cursor: pointer; transition: 0.2s; }
|
||||
.btn-primary { background: var(--primary); color: white; }
|
||||
.btn-primary:hover { opacity: 0.9; }
|
||||
.btn-block { display: block; width: 100%; }
|
||||
|
||||
/* 干扰信息处理 */
|
||||
.ad-banner { background: #fff3cd; color: #856404; padding: 10px; text-align: center; border: 1px solid #ffeeba; border-radius: 4px; margin-bottom: 20px; font-size: 14px; }
|
||||
.ad-banner a { color: #856404; font-weight: bold; text-decoration: underline; }
|
||||
/* Pagination */
|
||||
.pagination { display: flex; gap: 5px; margin-top: 20px; justify-content: center; }
|
||||
.page-num {
|
||||
width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
|
||||
border: 1px solid var(--border); border-radius: 4px; background: var(--bg-card);
|
||||
cursor: pointer;
|
||||
}
|
||||
.page-num.active { background: var(--primary); color: white; border-color: var(--primary); }
|
||||
|
||||
/* 恶意广告楼层处理 */
|
||||
.spam-post { border: 2px solid red; opacity: 0.7; position: relative; }
|
||||
.spam-post::after { content: '警告:疑似广告机器人'; position: absolute; top: 0; right: 0; background: red; color: white; padding: 2px 10px; font-size: 10px; }
|
||||
.fake-download-area { opacity: 0.3; pointer-events: none; /* 让假按钮无法点击 */ filter: grayscale(100%); }
|
||||
.fake-download-area::before { content: ' [系统已屏蔽广告链接] '; color: red; font-weight: bold; }
|
||||
/* Modals */
|
||||
.modal-backdrop {
|
||||
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(0,0,0,0.5); z-index: 2000;
|
||||
display: none; justify-content: center; align-items: center;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
.modal-backdrop.show { display: flex; }
|
||||
.modal-panel {
|
||||
background: var(--bg-card); width: 500px; max-width: 90%;
|
||||
border-radius: 12px; box-shadow: 0 20px 50px rgba(0,0,0,0.3);
|
||||
overflow: hidden; animation: slideUp 0.3s ease;
|
||||
}
|
||||
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
|
||||
|
||||
/* 侧边栏 */
|
||||
.sidebar-box { background: #fff; padding: 15px; border: 1px solid #ddd; margin-bottom: 20px; border-radius: 4px; }
|
||||
.sidebar-box h3 { margin-top: 0; font-size: 14px; border-left: 3px solid #4267b2; padding-left: 10px; }
|
||||
.sidebar-box ul { padding-left: 15px; font-size: 13px; }
|
||||
.sidebar-box li { margin-bottom: 8px; }
|
||||
/* Toast */
|
||||
.toast-box {
|
||||
position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%);
|
||||
background: #333; color: white; padding: 12px 24px; border-radius: 30px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 3000;
|
||||
display: none; font-weight: 500;
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.footer { text-align: center; color: #777; font-size: 12px; padding: 20px; border-top: 1px solid #ccc; margin-top: 20px; background: #fff; }
|
||||
/* Spam Style */
|
||||
.spam-mask { opacity: 0.5; filter: grayscale(1); pointer-events: none; position: relative; }
|
||||
.spam-mask::after {
|
||||
content: "系统已屏蔽此内容"; position: absolute; top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%); color: red; font-weight: bold; border: 2px solid red;
|
||||
padding: 5px 10px; transform: rotate(-10deg);
|
||||
}
|
||||
|
||||
/* 快速回复 */
|
||||
.quick-reply { background: #fff; padding: 20px; border: 1px solid #ddd; border-radius: 4px; }
|
||||
.quick-reply textarea { width: 100%; padding: 10px; border: 1px solid #ccc; margin-bottom: 10px; font-family: inherit; }
|
||||
.btn-primary { background: #4267b2; color: white; border: none; padding: 5px 15px; border-radius: 2px; cursor: pointer; }
|
||||
/* Editor Toolbar */
|
||||
.editor-toolbar {
|
||||
border: 1px solid var(--border); border-bottom: none;
|
||||
background: rgba(0,0,0,0.02); padding: 5px; display: flex; gap: 5px;
|
||||
}
|
||||
.tool-btn {
|
||||
width: 30px; height: 30px; border: 1px solid transparent; background: transparent;
|
||||
border-radius: 4px; cursor: pointer; display: flex; justify-content: center; align-items: center;
|
||||
}
|
||||
.tool-btn:hover { background: rgba(0,0,0,0.1); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body id="body">
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div>
|
||||
<h1>TechZone 硬件技术论坛</h1>
|
||||
<p>全球最大的极客交流社区</p>
|
||||
<!-- Navbar -->
|
||||
<header class="site-header">
|
||||
<div class="logo">
|
||||
<span style="font-size:2rem;">🛠️</span> TechZone
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<nav>
|
||||
<a href="#">首页</a>
|
||||
<a href="#">硬件专区</a>
|
||||
<a href="#">软件分享</a>
|
||||
<a href="#">灌水区</a>
|
||||
<a href="#">注册/登录</a>
|
||||
</nav>
|
||||
<br>
|
||||
<form class="search-bar">
|
||||
<input type="text" placeholder="搜索帖子...">
|
||||
<button class="btn-primary">搜索</button>
|
||||
</form>
|
||||
<div class="search-bar">
|
||||
<input type="text" id="searchInput" placeholder="搜索帖子、用户或资源..." onkeydown="if(event.key==='Enter') doSearch()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-user" id="navUser">
|
||||
<button class="btn btn-primary" onclick="openModal('loginModal')">注册 / 登录</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Layout -->
|
||||
<div class="container layout-grid" id="mainLayout">
|
||||
|
||||
<!-- Left Sidebar -->
|
||||
<nav class="sidebar">
|
||||
<div class="card">
|
||||
<div class="card-header">板块导航</div>
|
||||
<div class="card-body" style="padding:0;">
|
||||
<div class="forum-category-item" onclick="switchView('home')">🏠 论坛首页</div>
|
||||
<div class="forum-category-item" onclick="filterCategory('hardware')">🖥️ 硬件专区</div>
|
||||
<div class="forum-category-item" onclick="filterCategory('software')">💿 软件分享</div>
|
||||
<div class="forum-category-item" onclick="filterCategory('water')">🌊 灌水吐槽</div>
|
||||
<div class="forum-category-item" onclick="filterCategory('market')">💹 二手交易</div>
|
||||
<div class="forum-category-item" onclick="filterCategory('feedback')">📢 站务公告</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">我的状态</div>
|
||||
<div class="card-body">
|
||||
<p style="color:#666; font-size:0.9rem;">请先登录以查看您的积分和任务。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="border-color: #ffeeba; background:#fffdf5;">
|
||||
<div class="card-header" style="color:#856404;">📅 每日签到</div>
|
||||
<div class="card-body">
|
||||
<p style="font-size:0.8rem; margin-bottom:10px;">今日已签到: 12,503 人</p>
|
||||
<button class="btn btn-block" style="background:#ffc107; color:#333;" onclick="showToast('请先登录!', 'warning')">立即签到 (+5 积分)</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<main class="main-content">
|
||||
<div id="loading" style="text-align:center; padding:50px;">
|
||||
<div style="font-size:2rem; animation: spin 1s infinite linear;">⚙️</div>
|
||||
<p>正在加载社区内容...</p>
|
||||
</div>
|
||||
<div id="contentArea"></div>
|
||||
|
||||
<!-- Old content place holder to be deleted by JS or ignored -->
|
||||
<div style="display:none;">
|
||||
|
||||
|
||||
<div class="ad-banner">
|
||||
<p>【通告】2025新款显卡预售开启,点击查看详情 >></p>
|
||||
@@ -142,7 +302,7 @@
|
||||
<fieldset>
|
||||
<legend>附件下载</legend>
|
||||
<p>文件: Minidump_20251221.zip (256 KB)</p>
|
||||
<a href="#" onclick="alert('开始下载真实文件...')">[点击下载附件]</a>
|
||||
<a href="#" onclick="showCustomAlert('开始下载真实文件...')">[点击下载附件]</a>
|
||||
</fieldset>
|
||||
|
||||
<div align="center" class="fake-download-area">
|
||||
@@ -382,30 +542,609 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>Copyright © 2000-2025 TechZone Inc. All Rights Reserved.</p>
|
||||
<p><a href="#">联系我们</a> | <a href="#">免责声明</a> | <a href="#">广告合作</a> | <a href="#">手机版</a></p>
|
||||
<p>页面执行时间 0.045秒</p>
|
||||
</div> <!-- /End hidden content -->
|
||||
</main>
|
||||
|
||||
<!-- Right Sidebar -->
|
||||
<aside class="sidebar-right">
|
||||
<div class="card">
|
||||
<div class="card-header">🔥 24小时热帖</div>
|
||||
<div class="card-body" style="padding:0;">
|
||||
<ul id="hotThreadsList" style="padding:0; margin:0;">
|
||||
<!-- JS Generated -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">📊 社区统计</div>
|
||||
<div class="card-body" style="font-size:0.85rem; line-height:2;">
|
||||
<div>在线会员: <strong style="color:green">1,024</strong></div>
|
||||
<div>今日发帖: <strong>5,231</strong></div>
|
||||
<div>总帖子数: <strong>8.4M</strong></div>
|
||||
<div>服务器延迟: <span id="pingValue">12ms</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Modals -->
|
||||
<div class="modal-backdrop" id="confirmModal">
|
||||
<div class="modal-panel" style="width: 400px;">
|
||||
<div class="card-header">
|
||||
操作确认 <span style="cursor:pointer; float:right;" onclick="closeModal('confirmModal')">×</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p id="confirmMessage" style="margin-bottom: 20px;">确定执行此操作?</p>
|
||||
<div style="text-align: right;">
|
||||
<button class="btn" onclick="closeModal('confirmModal')">取消</button>
|
||||
<button class="btn btn-primary" id="confirmBtnAction">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" id="alertModal">
|
||||
<div class="modal-panel" style="width: 400px;">
|
||||
<div class="card-header">
|
||||
提示 <span style="cursor:pointer; float:right;" onclick="closeModal('alertModal')">×</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p id="alertMessage" style="margin-bottom: 20px;"></p>
|
||||
<div style="text-align: right;">
|
||||
<button class="btn btn-primary" onclick="closeModal('alertModal')">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" id="loginModal">
|
||||
<div class="modal-panel">
|
||||
<div class="card-header">
|
||||
用户登录 <span style="cursor:pointer; float:right;" onclick="closeModal('loginModal')">×</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div style="margin-bottom:15px;">
|
||||
<label style="display:block; margin-bottom:5px;">用户名 / 邮箱</label>
|
||||
<input type="text" id="loginUser" class="form-control" style="width:100%; padding:8px;" value="TechUser_2026">
|
||||
</div>
|
||||
<div style="margin-bottom:20px;">
|
||||
<label style="display:block; margin-bottom:5px;">密码</label>
|
||||
<input type="password" class="form-control" style="width:100%; padding:8px;" value="123456">
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block" onclick="doLogin()">登录</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" id="newThreadModal">
|
||||
<div class="modal-panel" style="width:800px;">
|
||||
<div class="card-header">
|
||||
发布新主题 <span style="cursor:pointer; float:right;" onclick="closeModal('newThreadModal')">×</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<input type="text" id="newPostTitle" placeholder="请输入标题..." style="width:100%; padding:10px; font-size:1.1rem; margin-bottom:10px; border:1px solid #ddd; border-radius:4px;">
|
||||
<div class="editor-toolbar">
|
||||
<button class="tool-btn"><b>B</b></button>
|
||||
<button class="tool-btn"><i>I</i></button>
|
||||
<button class="tool-btn"><u>U</u></button>
|
||||
<button class="tool-btn" onclick="insertText(' [code] ', ' [/code] ')">Code</button>
|
||||
<button class="tool-btn">🔗</button>
|
||||
<button class="tool-btn">📷</button>
|
||||
</div>
|
||||
<textarea id="newPostContent" style="width:100%; height:300px; padding:10px; border:1px solid #ddd; border-top:none; resize:vertical;" placeholder="请详细描述您的问题..."></textarea>
|
||||
<div style="margin-top:10px; text-align:right;">
|
||||
<button class="btn" onclick="closeModal('newThreadModal')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitNewThread()">发布帖子</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast-box" id="toast"></div>
|
||||
|
||||
<script>
|
||||
function likePost(btn) {
|
||||
let text = btn.innerText;
|
||||
let count = parseInt(text.match(/\d+/)[0]);
|
||||
btn.innerText = "支持 (" + (count + 1) + ")";
|
||||
btn.style.color = "red";
|
||||
// === Single Page Application Logic (SPA) ===
|
||||
|
||||
// --- Custom Alert/Confirm Logic ---
|
||||
let onConfirmCallback = null;
|
||||
|
||||
function showCustomAlert(msg) {
|
||||
document.getElementById('alertMessage').innerText = msg;
|
||||
openModal('alertModal');
|
||||
}
|
||||
|
||||
function replyPost() {
|
||||
document.querySelector('textarea').focus();
|
||||
document.querySelector('textarea').value = "回复 楼主:";
|
||||
function showCustomConfirm(msg, callback) {
|
||||
document.getElementById('confirmMessage').innerText = msg;
|
||||
onConfirmCallback = callback;
|
||||
openModal('confirmModal');
|
||||
}
|
||||
|
||||
function reportPost() {
|
||||
alert("举报成功!管理员将尽快审核。");
|
||||
// Bind Confirm Action
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const confirmBtn = document.getElementById('confirmBtnAction');
|
||||
if(confirmBtn) {
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
if (typeof onConfirmCallback === 'function') {
|
||||
onConfirmCallback();
|
||||
}
|
||||
closeModal('confirmModal');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const DB = {
|
||||
users: [
|
||||
{ id: 1, name: 'System_Admin', role: 'admin', avatar: 'https://ui-avatars.com/api/?name=SA&background=0D8ABC&color=fff' },
|
||||
{ id: 2, name: 'Hardware_Guru', role: 'mod', avatar: 'https://ui-avatars.com/api/?name=HG&background=ff5722&color=fff' },
|
||||
{ id: 3, name: 'Newbie_User_007', role: 'user', avatar: 'https://ui-avatars.com/api/?name=NU&background=4caf50&color=fff' },
|
||||
{ id: 99, name: 'Spam_Bot_X', role: 'banned', avatar: '' }
|
||||
],
|
||||
threads: [], // Will be generated
|
||||
};
|
||||
|
||||
const STATE = {
|
||||
currentUser: null, // null = guest
|
||||
currentView: 'home',
|
||||
currentCategory: 'all',
|
||||
viewingThreadId: null,
|
||||
notifications: [],
|
||||
page: 1
|
||||
};
|
||||
|
||||
// --- Mock Data Generator ---
|
||||
function initData() {
|
||||
// 预设的高质量模拟数据源
|
||||
const mockSources = [
|
||||
{
|
||||
title: "RTX 5090 性能偷跑,功耗高达 600W?",
|
||||
cat: "hardware",
|
||||
content: "据外媒爆料,下一代旗舰显卡 RTX 5090 的 TGP 可能高达 600W。这意味着现有的 ATX 3.0 电源可能都要退役了。<br><br>从泄露的 PCB 设计图来看,核心面积比 4090 增加了 15%,显存可能采用 GDDR7。大家怎么看?我是准备换电源了。",
|
||||
replies: ["600W?这不得开个空调对着吹?", "电费伤不起啊,还是继续用我的 1060 吧。", "AMD Yes! 只要苏妈不跟进这种功耗竞赛。", "消息保真吗?感觉像是烟雾弹。", "正好冬天到了,不仅能玩游戏还能取暖,赢麻了!"]
|
||||
},
|
||||
{
|
||||
title: "求助:Win12 更新后蓝屏 Critical_Process_Died",
|
||||
cat: "software",
|
||||
content: "昨晚手贱更新了 Windows 12 预览版(Build 26000),重启后直接蓝屏,进不去系统。<br><br>错误代码:Critical_Process_Died。<br>尝试过安全模式也进不去,手头没有 PE 盘。里面有重要的毕业论文,求大神支招!不要重装系统啊!",
|
||||
replies: ["预览版也敢主力机更新?勇士。", "试试制作一个 Linux Live USB 进去把文件拷出来。", "可能是驱动冲突,进 RE 模式回退更新试试。", "Critical_Process_Died 一般是系统核心文件损坏,大概率要重装了。", "没有备份吗?那基本凉了。"]
|
||||
},
|
||||
{
|
||||
title: "【装机作业】白色海景房,颜值即正义!",
|
||||
cat: "hardware",
|
||||
content: "心心念念的白色海景房终于装好了!<br><br>配置单:<br>- CPU: i7-14700K<br>- MB: ROG Z790吹雪<br>- RAM: 威刚 吹雪联名 D5 6400<br>- GPU: 影驰 名人堂 4080<br>- Case: 联力 O11D Evo<br><br>[图片] 效果炸裂,光污染拉满。就是理线理得我腰酸背痛。",
|
||||
replies: ["富哥V50看看实力。", "这理线水平可以啊,强迫症表示很舒适。", "全白确实好看,就是容易积灰,记得常清理。", "我也准备抄作业,这一套下来得 2W 吧?", "只有我关注桌子也是白的吗?"]
|
||||
},
|
||||
{
|
||||
title: "Python 爬虫总是被封 IP 怎么办?",
|
||||
cat: "software",
|
||||
content: "最近在写一个爬虫抓取某电商平台的数据,但是频率稍微高一点就 403 Forbidden。<br><br>已经加了 User-Agent 池,延时也设了随机 1-3 秒,还是不行。是不是必须得上收费代理了?有没有开源好用的代理池推荐?",
|
||||
replies: ["现在的反爬都很智能了,光换 UA 没用的。", "建议买隧道代理,免费的不稳定而且慢。", "看看有没有验证码或者 Cookie 追踪,封 IP 只是最后手段。", "降低频率吧,或者用 Selenium 模拟浏览器行为。", "少爬点吧,小心律师函警告 [滑稽]"]
|
||||
},
|
||||
{
|
||||
title: "AMD YES! Ryzen 9000 系列参数前瞻",
|
||||
cat: "hardware",
|
||||
content: "AMD 官方 PPT 终于放出来了,Zen 5 架构 IPC 提升 15%!<br><br>最关键的是,积热问题似乎得到了改善。首发价格如果能维持在 7000 系列的水平,Intel 这一代又要被吊打了。大家冲不冲?",
|
||||
replies: ["AMD Yes! 喊就完事了。", "首发肯定贵,等半年降价才是 真·YES。", "只要不换主板接口,我就冲。", "积热改善?我不信,除非你有实测。", "Intel 15代也要出来了,如果不急可以再等等。"]
|
||||
},
|
||||
{
|
||||
title: "机械键盘轴体推荐:红轴还是茶轴?",
|
||||
cat: "hardware",
|
||||
content: "想入把机械键盘办公用,偶尔打打 LOL。<br><br>之前用过青轴,太吵了被同事投诉。现在纠结红轴和茶轴,听说红轴软绵绵的?茶轴又有段落感?<br>要求:声音小,手感好,久打不累。",
|
||||
replies: ["办公绝对红轴,行云流水。", "茶轴是万用轴,有段落感打字比较爽。", "这就不得不推荐金粉轴了,比红轴还轻,办公神器。", "建议买个试轴器,几十块钱,把所有轴都摸一遍。", "静电容一步到位,退烧之选。"]
|
||||
},
|
||||
{
|
||||
title: "显示器选购指南:IPS vs OLED",
|
||||
cat: "hardware",
|
||||
content: "现在的 OLED 显示器越来越便宜了,27寸 2K 240Hz 只要 3000 多。<br><br>但是很担心烧屏问题。我是重度 Windows 用户,任务栏常驻。IPS 的 Nano-IPS 面板对比度又不行。到底该怎么选?主要用途是看电影和 3A 游戏。",
|
||||
replies: ["看电影绝对 OLED,黑场效果无敌。", "重度办公就算了吧,半年必烧。", "现在的 OLED 都有防烧屏技术,没那么脆弱。", "Mini-LED 考虑一下?折中方案。", "只要你有钱,坏了就换,那就无脑 OLED。"]
|
||||
},
|
||||
{
|
||||
title: "公司服务器被雷劈了,如何恢复数据?",
|
||||
cat: "water",
|
||||
content: "真实惨案。昨天雷雨天,机房不知怎么回事遭雷击了,UPS 也没抗住。<br><br>现在 RAID 卡报错,有两块盘亮红灯。虽然有异地备份,但是是一周前的... 老板脸都绿了,让我死马当活马医,求靠谱的数据恢复机构!",
|
||||
replies: ["这是物理损坏了,软件没救的,找专业开盘公司吧。", "同情楼主,这锅不该你背,是机房建设的问题。", "以前我们也遇到过,花了十几万才找回部分数据。", "千万别通电了!越通电损坏越严重!", "一周前的备份不错了,要是没备份你现在已经失业了。"]
|
||||
},
|
||||
{
|
||||
title: "小白求推荐 3000 元价位组装机",
|
||||
cat: "hardware",
|
||||
content: "预算只有 3000,想组一台能玩《黑神话:悟空》的主机。<br><br>不要求全高画质,1080P 中画质流畅就行。目前看了 12400F + 6600 的组合,这套稳吗?还是说等等党终将胜利?",
|
||||
replies: ["3000 玩 3A 有点勉强,建议加钱上 4060。", "12400F + 6600 性价比很高,1080P 没问题。", "二手市场淘一淘?3000 能收到不错的配置。", "电源别省,炸了就是全家桶。", "黑悟空优化怎么样还不知道,建议等游戏出了再买。"]
|
||||
},
|
||||
{
|
||||
title: "Linux 下如何配置 Nginx 反向代理?",
|
||||
cat: "software",
|
||||
content: "我在 Ubuntu 上部署了一个 Node.js 服务,跑在 3000 端口。<br><br>现在想通过域名直接访问,配置了 Nginx 的 proxy_pass,但是静态资源全都 404 了。有没有完整的 conf 模板可以参考一下?我是新手,文档看不太懂。",
|
||||
replies: ["静态资源要单独配 root 或 alias。", "直接贴你的配置文件出来,不然怎么帮你改?", "建议用 Docker 部署 Nginx Proxy Manager,图形化界面很方便。", "chatGPT 很擅长写配置,直接问它。", "注意 location 的匹配优先级,可能是被覆盖了。"]
|
||||
}
|
||||
];
|
||||
|
||||
for (let i = 0; i < 45; i++) {
|
||||
const seed = mockSources[i % mockSources.length]; // 循环使用模板
|
||||
const author = DB.users[Math.floor(Math.random() * 3)];
|
||||
|
||||
// 随机波动回复数和浏览量
|
||||
const replyCount = Math.floor(Math.random() * 150) + (seed.replies.length * 5);
|
||||
const viewCount = replyCount * (Math.floor(Math.random() * 40) + 20);
|
||||
|
||||
// 稍微修改标题以避免完全重复
|
||||
let titleVariant = seed.title;
|
||||
if (i >= mockSources.length) {
|
||||
const suffixes = ["(求助)", "[讨论]", "...", "!!", "(更新)"];
|
||||
titleVariant += " " + suffixes[i % suffixes.length];
|
||||
}
|
||||
|
||||
// 将预设回复存入 customReplies 属性,以便详情页生成时调用
|
||||
DB.threads.push({
|
||||
id: 1000 + i,
|
||||
title: titleVariant,
|
||||
author: author,
|
||||
date: new Date(Date.now() - Math.floor(Math.random() * 2000000000)).toISOString(),
|
||||
category: seed.cat,
|
||||
views: viewCount,
|
||||
replies: replyCount,
|
||||
isHot: replyCount > 80,
|
||||
content: seed.content, // 使用真实内容
|
||||
mockReplies: seed.replies // 传递特定话题的回复池
|
||||
});
|
||||
}
|
||||
|
||||
// Add fake sidebar hot data
|
||||
const hotList = document.getElementById('hotThreadsList');
|
||||
DB.threads.slice(0, 5).sort((a,b) => b.replies - a.replies).forEach(t => {
|
||||
hotList.innerHTML += `
|
||||
<li class="thread-item" style="padding:10px; border:none;" onclick="openThread(${t.id})">
|
||||
<span style="color:var(--primary); font-weight:bold;">${t.replies}</span>
|
||||
<a href="javascript:void(0)" style="margin-left:10px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${t.title}</a>
|
||||
</li>`;
|
||||
});
|
||||
}
|
||||
|
||||
// --- Core View Logic ---
|
||||
function renderApp() {
|
||||
const container = document.getElementById('contentArea');
|
||||
container.innerHTML = '';
|
||||
|
||||
document.getElementById('loading').style.display = 'block';
|
||||
|
||||
// Simulate network delay
|
||||
setTimeout(() => {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
if (STATE.currentView === 'home') {
|
||||
renderHome(container);
|
||||
} else if (STATE.currentView === 'thread') {
|
||||
renderThreadDetail(container, STATE.viewingThreadId);
|
||||
}
|
||||
|
||||
// Update UI User State
|
||||
updateUserUI();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function renderHome(container) {
|
||||
// Filter Logic
|
||||
let data = DB.threads;
|
||||
if (STATE.currentCategory !== 'all') {
|
||||
data = data.filter(t => t.category === STATE.currentCategory);
|
||||
}
|
||||
|
||||
// Toolbar
|
||||
const toolbar = document.createElement('div');
|
||||
toolbar.className = 'card';
|
||||
toolbar.innerHTML = `
|
||||
<div class="card-body" style="display:flex; justify-content:space-between; align-items:center; padding:10px 15px;">
|
||||
<div>
|
||||
<span style="font-weight:bold; font-size:1.1rem;">${getCategoryName(STATE.currentCategory)}</span>
|
||||
<span style="color:#888; margin-left:10px; font-size:0.9rem;">共 ${data.length} 个主题</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-primary" onclick="openModal('newThreadModal')">✍️ 发帖</button>
|
||||
<select style="padding:5px; border-radius:4px; border:1px solid #ddd; margin-left:10px;" onchange="showToast('排序功能开发中...', 'info')">
|
||||
<option>最新回复</option>
|
||||
<option>最新发布</option>
|
||||
<option>最多浏览</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(toolbar);
|
||||
|
||||
// List
|
||||
const listCard = document.createElement('div');
|
||||
listCard.className = 'card';
|
||||
// Header
|
||||
listCard.innerHTML = `<div class="card-header" style="color:#666; font-size:0.8rem;">
|
||||
<span style="flex:1;">主题</span>
|
||||
<span style="width:100px; text-align:center;">作者</span>
|
||||
<span style="width:80px; text-align:center;">回复/查看</span>
|
||||
<span style="width:120px; text-align:right;">最后发表</span>
|
||||
</div>`;
|
||||
|
||||
const listBody = document.createElement('div');
|
||||
|
||||
data.slice(0, 15).forEach(t => {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'thread-item';
|
||||
row.onclick = () => openThread(t.id);
|
||||
row.style.cursor = 'pointer';
|
||||
|
||||
let tagsHtml = '';
|
||||
if(t.isHot) tagsHtml += `<span class="tag red">HOT</span> `;
|
||||
if(t.category === 'hardware') tagsHtml += `<span class="tag blue">硬件</span> `;
|
||||
|
||||
row.innerHTML = `
|
||||
<div class="thread-stats">
|
||||
<span class="stat-count">${t.replies}</span>
|
||||
</div>
|
||||
<div class="thread-main">
|
||||
<span class="thread-title">${tagsHtml}${t.title}</span>
|
||||
<span class="thread-meta">
|
||||
发布于 ${formatDate(t.date)}
|
||||
${t.replies > 50 ? '🔥' : ''}
|
||||
</span>
|
||||
</div>
|
||||
<div style="width:100px; text-align:center; font-size:0.85rem;">
|
||||
<img src="${t.author.avatar}" style="width:20px; vertical-align:middle; border-radius:50%;">
|
||||
${t.author.name}
|
||||
</div>
|
||||
<div style="width:120px; text-align:right; font-size:0.8rem; color:#888;">
|
||||
${timeAgo(t.date)}
|
||||
</div>
|
||||
`;
|
||||
listBody.appendChild(row);
|
||||
});
|
||||
|
||||
listCard.appendChild(listBody);
|
||||
|
||||
// Manual Pagination
|
||||
const pagination = document.createElement('div');
|
||||
pagination.className = 'pagination';
|
||||
pagination.innerHTML = `
|
||||
<div class="page-num active">1</div>
|
||||
<div class="page-num">2</div>
|
||||
<div class="page-num">3</div>
|
||||
<div class="page-num">...</div>
|
||||
<div class="page-num">9</div>
|
||||
`;
|
||||
|
||||
container.appendChild(listCard);
|
||||
container.appendChild(pagination);
|
||||
}
|
||||
|
||||
function renderThreadDetail(container, threadId) {
|
||||
const thread = DB.threads.find(t => t.id === threadId);
|
||||
if(!thread) { container.innerHTML = "Thread Not Found"; return; }
|
||||
|
||||
// Breadcrumb
|
||||
container.innerHTML = `
|
||||
<div style="margin-bottom:15px; font-size:0.9rem;">
|
||||
<a onclick="switchView('home')">首页</a> > ${getCategoryName(thread.category)} > 正文
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="post-title" style="border:none; border-bottom:1px solid var(--border);">
|
||||
<h1 style="font-size:1.5rem; margin:0;">${thread.title}</h1>
|
||||
<div style="margin-top:10px; font-size:0.85rem; color:#666;">
|
||||
<span style="color:red;">[阅读权限 10]</span>
|
||||
浏览: ${thread.views} | 回复: ${thread.replies}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Generate Posts (Mock Replies)
|
||||
const posts = generateMockReplies(thread);
|
||||
|
||||
posts.forEach((post, index) => {
|
||||
const isLouZhu = index === 0;
|
||||
const postEl = document.createElement('div');
|
||||
postEl.className = 'card';
|
||||
if(post.isSpam) postEl.classList.add('spam-mask'); // CSS logic for spam
|
||||
|
||||
postEl.innerHTML = `
|
||||
<div class="post-container">
|
||||
<div class="post-sidebar">
|
||||
<img src="${post.author.avatar}" class="post-avatar-lg">
|
||||
<div style="font-weight:bold; color:var(--primary);">${post.author.name}</div>
|
||||
<div class="user-badge" style="background:${post.author.role === 'admin' ? '#000' : '#eee'}; color:${post.author.role === 'admin' ? '#fff' : '#333'}">
|
||||
${post.author.role.toUpperCase()}
|
||||
</div>
|
||||
<ul style="font-size:0.8rem; text-align:left; margin-top:10px; color:#666; padding-left:10px;">
|
||||
<li>UID: ${post.author.id}</li>
|
||||
<li>帖子: ${Math.floor(Math.random()*1000)}</li>
|
||||
<li>金币: ${Math.floor(Math.random()*5000)}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="post-content-area">
|
||||
<div class="post-meta-header">
|
||||
<span>发表于 ${formatDate(post.date)} ${isLouZhu ? '<span class="tag red">楼主</span>' : `#${index}楼`}</span>
|
||||
<span>只看该作者 | 倒序排列</span>
|
||||
</div>
|
||||
<div class="post-body">
|
||||
${post.content}
|
||||
${post.attachment ? renderAttachment(post.attachment) : ''}
|
||||
</div>
|
||||
<div class="post-signature">
|
||||
${post.signature || '这个人很懒,什么都没写。'}
|
||||
</div>
|
||||
<div class="post-actions">
|
||||
<button class="btn-action" onclick="showToast('已举报', 'success')">举报</button>
|
||||
<button class="btn-action">支持(${Math.floor(Math.random()*10)})</button>
|
||||
<button class="btn-action" onclick="openReply()">回复</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(postEl);
|
||||
});
|
||||
|
||||
// Quick Reply Box
|
||||
const replyBox = document.createElement('div');
|
||||
replyBox.className = 'card';
|
||||
replyBox.innerHTML = `
|
||||
<div class="card-header">快速回复</div>
|
||||
<div class="card-body">
|
||||
<textarea style="width:100%; height:100px; padding:10px; border:1px solid #ddd;"></textarea>
|
||||
<button class="btn btn-primary" style="margin-top:10px;" onclick="showToast('回复成功!(+1 积分)', 'success')">发表回复</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(replyBox);
|
||||
}
|
||||
|
||||
// --- Utils & Helpers ---
|
||||
function generateMockReplies(thread) {
|
||||
// Always include the OP
|
||||
const list = [{
|
||||
author: thread.author,
|
||||
date: thread.date,
|
||||
content: thread.content, // Now uses the realistic content content from initData
|
||||
signature: "System.out.println('Hello World');",
|
||||
attachment: thread.category === 'software' ? { name: "Error_Log.txt", size: "256 KB" } :
|
||||
thread.category === 'hardware' ? { name: "BIOS_Backup.bin", size: "16 MB" } : null
|
||||
}];
|
||||
|
||||
// Context-aware reply pool
|
||||
const genericReplies = [
|
||||
"楼主好人一生平安。", "这个教程太详细了,必须收藏!",
|
||||
"前排围观大神。", "我也觉得是这样,完全同意。",
|
||||
"有一说一,这个性价比确实高。", "建议楼主左转图吧,那里老哥个个是人才。",
|
||||
"路过帮顶。", "不明觉厉。", "火钳刘明。"
|
||||
];
|
||||
|
||||
// Use thread-specific replies first, then generic ones
|
||||
const availableReplies = (thread.mockReplies && thread.mockReplies.length > 0)
|
||||
? [...thread.mockReplies, ...genericReplies]
|
||||
: genericReplies;
|
||||
|
||||
// Generate random replies (between 3 and 10)
|
||||
const count = Math.floor(Math.random() * 8) + 3;
|
||||
|
||||
for(let i=0; i<count; i++) {
|
||||
// Pick a reply and ensure we don't repeat too often if possible
|
||||
const replyText = availableReplies[i % availableReplies.length];
|
||||
|
||||
list.push({
|
||||
author: DB.users[Math.floor(Math.random() * DB.users.length)],
|
||||
date: new Date(new Date(thread.date).getTime() + (i+1)*Math.random()*3600000).toISOString(), // Time progresses
|
||||
content: replyText,
|
||||
signature: `Signature_User_${Math.floor(Math.random()*999)}`
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function renderAttachment(att) {
|
||||
return `
|
||||
<fieldset style="border:1px solid #ddd; padding:10px; margin-top:20px; background:#f9f9f9;">
|
||||
<legend style="font-weight:bold;">附件</legend>
|
||||
📄 ${att.name} (${att.size}) <a href="#">[点击下载]</a>
|
||||
</fieldset>
|
||||
`;
|
||||
}
|
||||
|
||||
function getCategoryName(cat) {
|
||||
const map = { all: '全部主题', hardware: '硬件专区', software: '软件分享', water: '灌水吐槽', market: '二手交易', feedback: '站务公告' };
|
||||
return map[cat] || '未知板块';
|
||||
}
|
||||
|
||||
// --- Actions ---
|
||||
function switchView(viewName) {
|
||||
STATE.currentView = viewName;
|
||||
// Reset layout if needed
|
||||
document.getElementById('mainLayout').className = viewName === 'thread' ? 'container layout-grid thread-view' : 'container layout-grid';
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function openThread(id) {
|
||||
STATE.viewingThreadId = id;
|
||||
switchView('thread');
|
||||
}
|
||||
|
||||
function filterCategory(cat) {
|
||||
STATE.currentCategory = cat;
|
||||
switchView('home');
|
||||
}
|
||||
|
||||
// Modal & Toast
|
||||
function openModal(id) {
|
||||
document.getElementById(id).classList.add('show');
|
||||
}
|
||||
function closeModal(id) {
|
||||
document.getElementById(id).classList.remove('show');
|
||||
}
|
||||
function showToast(msg, type) {
|
||||
const t = document.getElementById('toast');
|
||||
t.innerText = msg;
|
||||
t.style.display = 'block';
|
||||
t.style.background = type === 'warning' ? '#ff9800' : (type === 'success' ? '#4caf50' : '#333');
|
||||
setTimeout(() => t.style.display = 'none', 3000);
|
||||
}
|
||||
|
||||
// Auth Simulation
|
||||
function doLogin() {
|
||||
const user = document.getElementById('loginUser').value;
|
||||
closeModal('loginModal');
|
||||
STATE.currentUser = { name: user || "User" };
|
||||
showToast(`欢迎回来,${STATE.currentUser.name}`, 'success');
|
||||
updateUserUI();
|
||||
}
|
||||
|
||||
function updateUserUI() {
|
||||
const nav = document.getElementById('navUser');
|
||||
if (STATE.currentUser) {
|
||||
nav.innerHTML = `
|
||||
<div style="display:flex; align-items:center; gap:10px; cursor:pointer;">
|
||||
<span style="font-weight:bold;">${STATE.currentUser.name}</span>
|
||||
<div class="user-avatar-sm" style="background:#4caf50;"></div>
|
||||
<button class="btn" style="padding:2px 8px; font-size:0.8rem;" onclick="location.reload()">注销</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(iso) {
|
||||
return iso.replace('T', ' ').substring(0, 16);
|
||||
}
|
||||
|
||||
function timeAgo(props) {
|
||||
return "1小时前"; // Simplified
|
||||
}
|
||||
|
||||
function insertText(prefix, suffix) {
|
||||
const area = document.getElementById('newPostContent');
|
||||
area.value += prefix + suffix;
|
||||
}
|
||||
|
||||
function submitNewThread() {
|
||||
closeModal('newThreadModal');
|
||||
showToast('发布成功!(模拟)', 'success');
|
||||
// Fake add
|
||||
setTimeout(() => {
|
||||
DB.threads.unshift({
|
||||
id: 9999,
|
||||
title: document.getElementById('newPostTitle').value || "无标题",
|
||||
author: STATE.currentUser || DB.users[2],
|
||||
replies: 0, views: 1, category: 'hardware',
|
||||
date: new Date().toISOString(),
|
||||
isHot: false
|
||||
});
|
||||
renderHome(document.getElementById('contentArea'));
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// --- Init ---
|
||||
window.onload = function() {
|
||||
initData();
|
||||
renderApp();
|
||||
|
||||
// Background Ping Simulation
|
||||
setInterval(() => {
|
||||
const ms = Math.floor(Math.random() * 50) + 10;
|
||||
document.getElementById('pingValue').innerText = ms + 'ms';
|
||||
document.getElementById('pingValue').style.color = ms > 100 ? 'red' : 'green';
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
1197
005/005_r.html
1197
005/005_r.html
File diff suppressed because it is too large
Load Diff
721
006/006_r.html
721
006/006_r.html
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BitMatrix Pro Exchange - BTC/USDT</title>
|
||||
|
||||
<style>
|
||||
/* === 全局样式 === */
|
||||
:root {
|
||||
@@ -35,6 +36,97 @@
|
||||
h1, h2, h3, h4 { margin: 0; font-weight: 500; }
|
||||
hr { border: 0; border-top: 1px solid var(--border); margin: 0; }
|
||||
|
||||
/* Inteactive Elements Styles */
|
||||
.chart-time-btn {
|
||||
background: transparent; border: none; color: var(--text-secondary); cursor: pointer; font-size: 11px; padding: 2px 5px;
|
||||
}
|
||||
.chart-time-btn.active { color: var(--accent); font-weight: bold; }
|
||||
.chart-time-btn:hover { color: var(--text-primary); }
|
||||
|
||||
.trade-tab {
|
||||
flex: 1; background: transparent; border: none; color: var(--text-secondary); cursor: pointer; padding-bottom: 5px; border-bottom: 2px solid transparent;
|
||||
}
|
||||
.trade-tab.active { color: var(--accent); border-bottom: 2px solid var(--accent); font-weight: bold; }
|
||||
|
||||
#market-sidebar li, #order-book li { cursor: pointer; }
|
||||
#order-book li:hover { background-color: #2b3139; }
|
||||
|
||||
/* === 更多样式 (填充到900+行的内容) === */
|
||||
/* 高级设置面板 (New Section) */
|
||||
#advanced-panel {
|
||||
grid-column: 1 / -1;
|
||||
background: #181d24;
|
||||
padding: 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
#advanced-panel h4 { color: var(--text-primary); margin-bottom: 10px; border-bottom: 1px solid var(--border); padding-bottom: 5px;}
|
||||
#advanced-panel ul li { margin-bottom: 5px; cursor: pointer; }
|
||||
#advanced-panel ul li:hover { color: var(--accent); text-decoration: underline; }
|
||||
|
||||
/* 页底免责声明扩展 */
|
||||
.disclaimer-long {
|
||||
font-size: 10px; color: #444; margin-top: 20px; padding: 10px 0; border-top: 1px solid #222;
|
||||
}
|
||||
|
||||
/* 模态框动画 */
|
||||
#modal-content { animation: dropDown 0.3s ease; }
|
||||
@keyframes dropDown { from { transform: translateY(-50px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
|
||||
|
||||
/* 滚动条美化 */
|
||||
::-webkit-scrollbar { width: 6px; }
|
||||
::-webkit-scrollbar-track { background: var(--bg-dark); }
|
||||
::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #555; }
|
||||
|
||||
/* Tooltip */
|
||||
.tooltip { position: relative; display: inline-block; cursor: help; border-bottom: 1px dotted #777; }
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden; width: 200px; background-color: #333; color: #fff; text-align: center;
|
||||
border-radius: 4px; padding: 5px; position: absolute; z-index: 10; bottom: 125%; left: 50%;
|
||||
margin-left: -100px; opacity: 0; transition: opacity 0.3s;
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,0.5);
|
||||
font-size: 11px;
|
||||
}
|
||||
.tooltip:hover .tooltiptext { visibility: visible; opacity: 1; }
|
||||
|
||||
/* API Status Panel */
|
||||
#api-status {
|
||||
padding: 10px; background: #000; color: #0f0; font-family: monospace; height: 100px; overflow: hidden;
|
||||
font-size: 10px; border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
/* Extended Grid Layout for Footer Area */
|
||||
#layout-bottom {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
background: var(--bg-panel);
|
||||
border-top: 1px solid var(--border);
|
||||
height: 200px; /* Reduced for layout fit */
|
||||
}
|
||||
|
||||
/* 深度图视觉模拟 */
|
||||
.depth-visual {
|
||||
height: 50px;
|
||||
margin-top: 10px;
|
||||
background: linear-gradient(to right, rgba(14, 203, 129, 0.2) 50%, rgba(246, 70, 93, 0.2) 50%);
|
||||
border: 1px solid var(--border);
|
||||
position: relative;
|
||||
}
|
||||
.depth-label { position: absolute; top: 15px; width: 100%; text-align: center; color: #666; font-size: 10px; }
|
||||
|
||||
/* Table Styles for Assets */
|
||||
.asset-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
||||
.asset-table th { text-align: left; color: var(--text-secondary); padding: 5px; font-size: 11px; }
|
||||
.asset-table td { padding: 5px; border-bottom: 1px solid #2b3139; font-size: 11px; }
|
||||
.asset-table tr:hover { background: #2b3139; }
|
||||
|
||||
.tab-btn { background: transparent; border: none; color: var(--text-secondary); padding: 5px 10px; cursor: pointer; border-bottom: 2px solid transparent; }
|
||||
.tab-btn.active { color: var(--accent); border-bottom: 2px solid var(--accent); }
|
||||
|
||||
/* === 顶部通告 (干扰) === */
|
||||
#top-banner {
|
||||
background: #2b3139;
|
||||
@@ -217,7 +309,8 @@
|
||||
#footer p { margin: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<body style="overflow-y: auto;">
|
||||
|
||||
<div id="app-root">
|
||||
|
||||
@@ -252,13 +345,13 @@
|
||||
<button type="button" style="display:none;">搜</button>
|
||||
</form>
|
||||
<ul>
|
||||
<li><a href="#">BTC/USDT - 98,542.00</a></li>
|
||||
<li><a href="#">ETH/USDT - 3,850.00</a></li>
|
||||
<li><a href="#">SOL/USDT - 145.20</a></li>
|
||||
<li><a href="#">DOGE/USDT - 0.12</a></li>
|
||||
<li><a href="#" style="color:#f6465d;">PEPE/USDT (热) - 0.00001</a></li>
|
||||
<li><a href="#" style="color:#f6465d;">SCAM/USDT (新) - 1.00</a></li>
|
||||
<li><a href="#">BNB/USDT - 600.00</a></li>
|
||||
<li onclick="switchMarket('BTC/USDT', 98542.00)"><a href="javascript:void(0)">BTC/USDT - 98,542.00</a></li>
|
||||
<li onclick="switchMarket('ETH/USDT', 3850.00)"><a href="javascript:void(0)">ETH/USDT - 3,850.00</a></li>
|
||||
<li onclick="switchMarket('SOL/USDT', 145.20)"><a href="javascript:void(0)">SOL/USDT - 145.20</a></li>
|
||||
<li onclick="switchMarket('DOGE/USDT', 0.1205)"><a href="javascript:void(0)">DOGE/USDT - 0.1205</a></li>
|
||||
<li onclick="switchMarket('PEPE/USDT', 0.00001)"><a href="javascript:void(0)" style="color:#f6465d;">PEPE/USDT (热) - 0.00001</a></li>
|
||||
<li onclick="switchMarket('SCAM/USDT', 1.00)"><a href="javascript:void(0)" style="color:#f6465d;">SCAM/USDT (新) - 1.00</a></li>
|
||||
<li onclick="switchMarket('BNB/USDT', 600.00)"><a href="javascript:void(0)">BNB/USDT - 600.00</a></li>
|
||||
</ul>
|
||||
|
||||
<div style="margin-top:20px; color:#555; font-size:11px;">
|
||||
@@ -272,14 +365,22 @@
|
||||
<div id="center-panel">
|
||||
|
||||
<div id="chart-area">
|
||||
<div style="border: 1px solid black; height: 300px; padding: 20px;">
|
||||
<div style="height: 30px; background: var(--bg-dark); display: flex; align-items: center; padding: 0 10px; gap: 10px; border-bottom: 1px solid var(--border);">
|
||||
<span style="color:var(--text-secondary);">时间:</span>
|
||||
<button class="chart-time-btn active" onclick="switchChartTime(this, '15m')">15m</button>
|
||||
<button class="chart-time-btn" onclick="switchChartTime(this, '1H')">1H</button>
|
||||
<button class="chart-time-btn" onclick="switchChartTime(this, '4H')">4H</button>
|
||||
<button class="chart-time-btn" onclick="switchChartTime(this, '1D')">1D</button>
|
||||
</div>
|
||||
<div id="chart-content" style="border: none !important; height: 270px; display: flex; flex-direction: column; justify-content: center; align-items: center; color: var(--text-secondary);">
|
||||
<h3>[Interactive K-Line Chart Loading...]</h3>
|
||||
<p>TradingView Module not loaded.</p>
|
||||
<p>Loading scripts...</p>
|
||||
<p>Connecting to WebSocket wss://api.bitmatrix.com...</p>
|
||||
</div>
|
||||
<div style="background-color: yellow;">
|
||||
<small>Warning: Connection latency > 500ms. Data may be delayed.</small>
|
||||
<!-- Delay 警告 -->
|
||||
<div style="position: absolute; top: 40px; right: 10px; background: rgba(246, 70, 93, 0.2); color: var(--down); padding: 5px 10px; border-radius: 4px; border: 1px solid var(--down);">
|
||||
<small>Live Data Delay > 500ms</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -289,12 +390,12 @@
|
||||
<div class="book-column">
|
||||
<h4>卖盘 (Asks)</h4>
|
||||
<ul>
|
||||
<li><span>98,545.00</span> - <span>0.52 BTC</span></li>
|
||||
<li><span>98,544.50</span> - <span>0.11 BTC</span></li>
|
||||
<li><span>98,544.00</span> - <span>1.20 BTC</span></li>
|
||||
<li><span>98,543.50</span> - <span>0.05 BTC</span></li>
|
||||
<li><span>98,543.00</span> - <span>0.88 BTC</span></li>
|
||||
<li><span>98,542.50</span> - <span>2.00 BTC</span></li>
|
||||
<li onclick="fillForm(98545.00, 0.52)"><span>98,545.00</span> - <span>0.52 BTC</span></li>
|
||||
<li onclick="fillForm(98544.50, 0.11)"><span>98,544.50</span> - <span>0.11 BTC</span></li>
|
||||
<li onclick="fillForm(98544.00, 1.20)"><span>98,544.00</span> - <span>1.20 BTC</span></li>
|
||||
<li onclick="fillForm(98543.50, 0.05)"><span>98,543.50</span> - <span>0.05 BTC</span></li>
|
||||
<li onclick="fillForm(98543.00, 0.88)"><span>98,543.00</span> - <span>0.88 BTC</span></li>
|
||||
<li onclick="fillForm(98542.50, 2.00)"><span>98,542.50</span> - <span>2.00 BTC</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -303,28 +404,29 @@
|
||||
</div>
|
||||
|
||||
<div class="current-price">
|
||||
<h2>98,542.00 <small style="font-size:14px; color:#888;">≈ ¥705,321.00</small></h2>
|
||||
<h2 id="current-price-display">98,542.00 <small style="font-size:14px; color:#888;">≈ ¥705,321.00</small></h2>
|
||||
</div>
|
||||
|
||||
<div class="book-column">
|
||||
<h4>买盘 (Bids)</h4>
|
||||
<ul>
|
||||
<li><span>98,541.50</span> - <span>0.33 BTC</span></li>
|
||||
<li><span>98,541.00</span> - <span>5.00 BTC</span></li>
|
||||
<li><span>98,540.50</span> - <span>0.20 BTC</span></li>
|
||||
<li><span>98,540.00</span> - <span>1.50 BTC</span></li>
|
||||
<li><span>98,539.50</span> - <span>0.10 BTC</span></li>
|
||||
<li><span>98,539.00</span> - <span>0.01 BTC</span></li>
|
||||
<li onclick="fillForm(98541.50, 0.33)"><span>98,541.50</span> - <span>0.33 BTC</span></li>
|
||||
<li onclick="fillForm(98541.00, 5.00)"><span>98,541.00</span> - <span>5.00 BTC</span></li>
|
||||
<li onclick="fillForm(98540.50, 0.20)"><span>98,540.50</span> - <span>0.20 BTC</span></li>
|
||||
<li onclick="fillForm(98540.00, 1.50)"><span>98,540.00</span> - <span>1.50 BTC</span></li>
|
||||
<li onclick="fillForm(98539.50, 0.10)"><span>98,539.50</span> - <span>0.10 BTC</span></li>
|
||||
<li onclick="fillForm(98539.00, 0.01)"><span>98,539.00</span> - <span>0.01 BTC</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:交易与聊天 -->
|
||||
<div id="right-panel">
|
||||
|
||||
<div id="trade-form">
|
||||
<h3>现货交易</h3>
|
||||
<form>
|
||||
<form onsubmit="event.preventDefault();">
|
||||
<div>
|
||||
<label>类型:</label>
|
||||
<input type="radio" name="type" checked> 限价
|
||||
@@ -344,23 +446,37 @@
|
||||
<br><small>借币利率 0.05%/天</small>
|
||||
</div>
|
||||
|
||||
<p style="margin-bottom: 10px; color:#aaa;">可用余额: Loading...</p>
|
||||
|
||||
<div class="btn-group">
|
||||
<button type="button" onclick="executeTrade('buy')">买入 BTC</button>
|
||||
<button type="button" onclick="executeTrade('sell')">卖出 BTC</button>
|
||||
</div>
|
||||
</form>
|
||||
<p style="margin-top:10px; color:#aaa;">可用余额: 0.00 USDT <a href="#" style="color:#fcd535;">[充值]</a></p>
|
||||
</div>
|
||||
|
||||
<div id="recent-trades">
|
||||
<h3 style="padding:10px; border-bottom:1px solid #2b3139;">最新成交</h3>
|
||||
<ul id="trade-list">
|
||||
<li><small>12:00:01</small> - 98,542.00 - 0.0021</li>
|
||||
<li><small>12:00:02</small> - 98,541.50 - 0.0100</li>
|
||||
<li><small>12:00:02</small> - 98,542.10 - 0.5000</li>
|
||||
<li><small>12:00:03</small> - 98,542.00 - 0.0001</li>
|
||||
<li><small>12:00:05</small> - 98,542.00 - 0.0332</li>
|
||||
</ul>
|
||||
<div style="padding:10px; border-bottom:1px solid #2b3139; display: flex; gap: 10px;">
|
||||
<button class="trade-tab active" id="tab-btn-recent" onclick="switchTradeTab('recent')">最新成交</button>
|
||||
<button class="trade-tab" id="tab-btn-orders" onclick="switchTradeTab('orders')">当前委托</button>
|
||||
</div>
|
||||
|
||||
<div id="trade-list-container">
|
||||
<ul id="trade-list">
|
||||
<li><small>12:00:01</small> - 98,542.00 - 0.0021</li>
|
||||
<li><small>12:00:02</small> - 98,541.50 - 0.0100</li>
|
||||
<li><small>12:00:02</small> - 98,542.10 - 0.5000</li>
|
||||
<li><small>12:00:03</small> - 98,542.00 - 0.0001</li>
|
||||
<li><small>12:00:05</small> - 98,542.00 - 0.0332</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="my-orders-container" style="display: none; padding: 10px;">
|
||||
<p style="color: #666; font-size: 11px; text-align: center; margin-bottom: 5px;">- 仅显示当前未成交委托 -</p>
|
||||
<ul id="my-orders-list">
|
||||
<!-- Orders will be injected here -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chat-room">
|
||||
@@ -384,6 +500,197 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="layout-bottom">
|
||||
<div style="padding: 10px; border-right: 1px solid var(--border); overflow-y: auto;">
|
||||
<h3>资产概览</h3>
|
||||
<div style="margin: 10px 0;">
|
||||
<button class="tab-btn active" onclick="switchTab('assets')">资金账户</button>
|
||||
<button class="tab-btn" onclick="switchTab('contract')">合约账户</button>
|
||||
<button class="tab-btn" onclick="switchTab('finance')">理财账户</button>
|
||||
</div>
|
||||
|
||||
<!-- 资金账户表格 -->
|
||||
<div id="tab-assets" class="asset-tab-content">
|
||||
<table class="asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>币种</th>
|
||||
<th>可用</th>
|
||||
<th>冻结</th>
|
||||
<th>BTC估值</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>USDT</td>
|
||||
<td id="asset-usdt-free">10,000.00</td>
|
||||
<td id="asset-usdt-lock">0.00</td>
|
||||
<td>0.1015</td>
|
||||
<td><a href="javascript:void(0)" onclick="showDeposit()">充值</a> <a href="javascript:void(0)" onclick="showAlert('提现维护中')">提现</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BTC</td>
|
||||
<td id="asset-btc-free">0.5000</td>
|
||||
<td id="asset-btc-lock">0.00</td>
|
||||
<td>0.5000</td>
|
||||
<td><a href="javascript:void(0)" onclick="showDeposit()">充值</a> <a href="javascript:void(0)" onclick="showAlert('提现维护中')">提现</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ETH</td>
|
||||
<td>0.0000</td>
|
||||
<td>0.00</td>
|
||||
<td>0.0000</td>
|
||||
<td><a href="javascript:void(0)" onclick="showDeposit()">充值</a> <a href="javascript:void(0)" onclick="showAlert('提现维护中')">提现</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 合约账户表格 (默认隐藏) -->
|
||||
<div id="tab-contract" class="asset-tab-content" style="display: none;">
|
||||
<table class="asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>币种</th>
|
||||
<th>权益</th>
|
||||
<th>未实现盈亏</th>
|
||||
<th>保证金率</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align:center; padding: 20px; color:#666;">暂无合约资产,请划转资金</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 理财账户表格 (默认隐藏) -->
|
||||
<div id="tab-finance" class="asset-tab-content" style="display: none;">
|
||||
<table class="asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>项目</th>
|
||||
<th>总投入</th>
|
||||
<th>昨日收益</th>
|
||||
<th>累计收益</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align:center; padding: 20px; color:#666;">尚未参与任何理财项目</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="padding: 10px; display:flex; flex-direction: column;">
|
||||
<div style="display:flex; justify-content: space-between; align-items: center;">
|
||||
<h3>系统日志 / API 状态</h3>
|
||||
<span style="color:#0ecb81; font-size:10px;">● 所有系统正常运行</span>
|
||||
</div>
|
||||
<div id="api-status">
|
||||
> Initializing system check... [OK]<br>
|
||||
> Connecting to matching engine... [OK]<br>
|
||||
> Syncing order book... [OK]<br>
|
||||
> Loading user wallet... [OK]<br>
|
||||
> WebSocket latency: 45ms<br>
|
||||
> Server Load: 12%<br>
|
||||
</div>
|
||||
<div class="depth-visual">
|
||||
<div class="depth-label">Market Depth Visualization (Simulated)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="advanced-panel">
|
||||
<div>
|
||||
<h4>关于我们</h4>
|
||||
<ul>
|
||||
<li><a href="#">关于 BitMatrix</a></li>
|
||||
<li><a href="#">商务合作</a></li>
|
||||
<li><a href="#">社区建设</a></li>
|
||||
<li><a href="#">招纳贤才 <span style="background:var(--accent); color:black; padding:0 2px; border-radius:2px; font-size:10px;">HOT</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>客户服务</h4>
|
||||
<ul>
|
||||
<li><a href="#">帮助中心</a></li>
|
||||
<li><a href="#">提交工单</a></li>
|
||||
<li><a href="#">API 文档</a></li>
|
||||
<li><a href="#">费率标准</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>条款说明</h4>
|
||||
<ul>
|
||||
<li><a href="#">用户协议</a></li>
|
||||
<li><a href="#">隐私政策</a></li>
|
||||
<li><a href="#">法律声明</a></li>
|
||||
<li><a href="#">Cookies 设置</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>社区媒体</h4>
|
||||
<div style="display:flex; gap:10px; font-size:20px;">
|
||||
<a href="#" class="tooltip">X<span class="tooltiptext">关注我们的 Twitter</span></a>
|
||||
<a href="#" class="tooltip">T<span class="tooltiptext">加入 Telegram 群组</span></a>
|
||||
<a href="#" class="tooltip">D<span class="tooltiptext">加入 Discord 社区</span></a>
|
||||
<a href="#" class="tooltip">R<span class="tooltiptext">浏览 Reddit 讨论区</span></a>
|
||||
</div>
|
||||
<p style="font-size:10px; color:#666; margin-top:10px;">扫描二维码下载 APP (iOS/Android)</p>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer-long" style="grid-column: 1 / -1;">
|
||||
<p><strong>风险提示:</strong> 数字资产交易具有极高的风险,可能导致部分或全部损失。请确保您充分了解涉及的风险,并在根据您的经验水平、投资目标选择交易产品之前寻求独立的财务建议。BitMatrix 不对您的任何交易损失负责。过往表现不代表未来收益。</p>
|
||||
<p>BitMatrix Pro 致力于遵守各运营地的法律法规。某些服务可能在特定司法管辖区不可用,包括但不限于美国、新加坡、伊朗、朝鲜等。</p>
|
||||
<p>CopyRight © 2025 BitMatrix Technology Ltd. All Rights Reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
<div id="modal-backdrop" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);">
|
||||
<div id="modal-content" style="background-color: var(--bg-panel); margin: 15% auto; padding: 20px; border: 1px solid var(--border); width: 400px; color: var(--text-primary);">
|
||||
<p id="modal-message"></p>
|
||||
<div style="text-align: right; margin-top: 20px;">
|
||||
<button id="modal-cancel-btn" style="background-color: transparent; border: 1px solid var(--text-secondary); color: var(--text-primary); padding: 5px 15px; cursor: pointer; display: none;">取消</button>
|
||||
<button id="modal-ok-btn" style="background-color: var(--accent); border: none; color: black; padding: 5px 15px; cursor: pointer; margin-left: 10px;">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 充值模态框 (New) -->
|
||||
<div id="deposit-modal" style="display: none; position: fixed; z-index: 1001; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.6);">
|
||||
<div style="background-color: var(--bg-panel); margin: 10% auto; padding: 25px; border: 1px solid var(--border); width: 350px; color: var(--text-primary); text-align: center; border-radius: 8px;">
|
||||
<h3 style="margin-bottom: 20px;">充值 USDT (ERC-20)</h3>
|
||||
|
||||
<div style="background: white; padding: 20px; width: 150px; height: 150px; margin: 0 auto; display: flex; justify-content: center; align-items: center;">
|
||||
<!-- Pseudo QR Code -->
|
||||
<div style="width: 100%; height: 100%; background-image: radial-gradient(black 40%, transparent 40%), radial-gradient(black 40%, transparent 40%); background-position: 0 0, 10px 10px; background-size: 20px 20px; opacity: 0.8;"></div>
|
||||
</div>
|
||||
|
||||
<p style="margin-top: 15px; color: var(--text-secondary); font-size: 11px;">充值地址</p>
|
||||
<div style="background: #111; padding: 10px; border-radius: 4px; font-family: monospace; word-break: break-all; border: 1px solid #333;">
|
||||
0x71C7656EC7ab88b098defB751B7401B5f6d8976F
|
||||
</div>
|
||||
|
||||
<p style="color: var(--down); font-size: 10px; margin-top: 20px;">*请勿向此地址充值任何非 USDT 资产,否则将无法找回。</p>
|
||||
|
||||
<div style="margin-top: 20px; display: flex; gap: 10px; justify-content: center;">
|
||||
<button onclick="document.getElementById('deposit-modal').style.display='none'" style="background: #333; color: white; border: none; padding: 8px 20px; cursor: pointer; border-radius: 4px;">关闭</button>
|
||||
<button onclick="simulateDeposit()" style="background: var(--up); color: white; border: none; padding: 8px 20px; cursor: pointer; border-radius: 4px;">模拟到账</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p>联系我们 | API 文档 | 费率标准 | 上币申请</p>
|
||||
<p>© 2025 BitMatrix. All rights reserved.</p>
|
||||
@@ -394,15 +701,313 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function executeTrade(type) {
|
||||
if(type === 'buy') {
|
||||
alert("错误:可用 USDT 余额不足,请充值。");
|
||||
// System State
|
||||
const SYSTEM_STATE = {
|
||||
balance: { usdt: 10000, btc: 0.5 },
|
||||
user: { loggedIn: true, name: 'User_888' },
|
||||
market: { pair: 'BTC/USDT', price: 98542.00, trend: 'down' },
|
||||
orders: [] // Store current orders
|
||||
};
|
||||
|
||||
// --- Custom Modal Logic ---
|
||||
let modalCallback = null;
|
||||
|
||||
function showModal(message, isConfirm = false, callback = null) {
|
||||
const modal = document.getElementById('modal-backdrop');
|
||||
const msgEl = document.getElementById('modal-message');
|
||||
const cancelBtn = document.getElementById('modal-cancel-btn');
|
||||
const okBtn = document.getElementById('modal-ok-btn');
|
||||
|
||||
msgEl.innerText = message;
|
||||
modal.style.display = "block";
|
||||
|
||||
modalCallback = callback;
|
||||
|
||||
if (isConfirm) {
|
||||
cancelBtn.style.display = "inline-block";
|
||||
cancelBtn.onclick = function() {
|
||||
modal.style.display = "none";
|
||||
modalCallback = null;
|
||||
}
|
||||
} else {
|
||||
alert("错误:可用 BTC 余额不足,请充值。");
|
||||
cancelBtn.style.display = "none";
|
||||
}
|
||||
|
||||
okBtn.onclick = function() {
|
||||
modal.style.display = "none";
|
||||
if (modalCallback) {
|
||||
modalCallback();
|
||||
modalCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 简单的价格模拟跳动
|
||||
function showAlert(msg) { showModal(msg, false); }
|
||||
function showConfirm(msg, callback) { showModal(msg, true, callback); }
|
||||
// --- End Custom Modal Logic ---
|
||||
|
||||
// --- Interactive features ---
|
||||
|
||||
function switchMarket(pair, price) {
|
||||
document.title = `BitMatrix Pro Exchange - ${pair}`;
|
||||
document.querySelector('#header h1').innerText = `BitMatrix Pro | ${pair}`;
|
||||
document.getElementById('header-price').innerText = price.toFixed(2);
|
||||
SYSTEM_STATE.market.pair = pair;
|
||||
SYSTEM_STATE.market.price = price;
|
||||
|
||||
// Reset Chart
|
||||
document.getElementById('chart-content').innerHTML = `
|
||||
<h3>Loading ${pair} Chart...</h3>
|
||||
<p>Fetching historical data...</p>
|
||||
`;
|
||||
setTimeout(() => {
|
||||
document.getElementById('chart-content').innerHTML = `
|
||||
<h3>${pair} Chart Loaded</h3>
|
||||
<p>Timeframe: 15m</p>
|
||||
<p style="color:#0ecb81; font-size: 20px;">▲ ${price.toFixed(2)}</p>
|
||||
`;
|
||||
}, 800);
|
||||
|
||||
// Update Price Display in Order Book
|
||||
document.getElementById('current-price-display').innerHTML = `${price.toFixed(2)} <small style="font-size:14px; color:#888;">≈ ¥${(price * 7.15).toFixed(2)}</small>`;
|
||||
}
|
||||
|
||||
function switchChartTime(btn, period) {
|
||||
document.querySelectorAll('.chart-time-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
const content = document.getElementById('chart-content');
|
||||
content.innerHTML = `<p>Loading ${period} data...</p>`;
|
||||
setTimeout(() => {
|
||||
content.innerHTML = `
|
||||
<h3>${SYSTEM_STATE.market.pair} Chart</h3>
|
||||
<p>Timeframe: ${period}</p>
|
||||
<p style="color:#0ecb81; font-size: 20px;">▲ ${SYSTEM_STATE.market.price.toFixed(2)}</p>
|
||||
<div style="height: 100px; width: 80%; background: linear-gradient(transparent, #0ecb81 30%, transparent); opacity: 0.3;"></div>
|
||||
`;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function fillForm(price, amount) {
|
||||
const inputs = document.querySelectorAll('#trade-form input[type="text"]');
|
||||
inputs[0].value = price.toFixed(2);
|
||||
inputs[1].value = amount.toFixed(4);
|
||||
}
|
||||
|
||||
function switchTradeTab(tab) {
|
||||
document.querySelectorAll('.trade-tab').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById(`tab-btn-${tab}`).classList.add('active');
|
||||
|
||||
if (tab === 'recent') {
|
||||
document.getElementById('trade-list-container').style.display = 'block';
|
||||
document.getElementById('my-orders-container').style.display = 'none';
|
||||
} else {
|
||||
document.getElementById('trade-list-container').style.display = 'none';
|
||||
document.getElementById('my-orders-container').style.display = 'block';
|
||||
updateMyOrders();
|
||||
}
|
||||
}
|
||||
|
||||
function updateMyOrders() {
|
||||
const list = document.getElementById('my-orders-list');
|
||||
list.className = 'my-order-list-style'; // Can add style later if needed
|
||||
list.innerHTML = '';
|
||||
if (SYSTEM_STATE.orders.length === 0) {
|
||||
list.innerHTML = '<li style="text-align: center; color: #555; padding: 20px;">暂无委托</li>';
|
||||
return;
|
||||
}
|
||||
SYSTEM_STATE.orders.forEach((order, index) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.cssText = "padding: 5px 0; border-bottom: 1px solid #333; display: flex; justify-content: space-between; align-items: center;";
|
||||
li.innerHTML = `
|
||||
<div>
|
||||
<span style="color:${order.type === 'buy' ? '#0ecb81' : '#f6465d'}">${order.type.toUpperCase()}</span>
|
||||
<span>${order.pair}</span><br>
|
||||
<small>Price: ${order.price}</small> <small>Amt: ${order.amount}</small>
|
||||
</div>
|
||||
<button onclick="cancelOrder(${index})" style="background: transparent; border: 1px solid #555; color: #888; cursor: pointer; padding: 2px 5px; font-size: 10px;">撤单</button>
|
||||
`;
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
function cancelOrder(index) {
|
||||
showConfirm("确认撤销此委托单吗?", () => {
|
||||
const order = SYSTEM_STATE.orders[index];
|
||||
// Return funds
|
||||
if (order.type === 'buy') {
|
||||
SYSTEM_STATE.balance.usdt += order.total;
|
||||
} else {
|
||||
SYSTEM_STATE.balance.btc += order.amount;
|
||||
}
|
||||
SYSTEM_STATE.orders.splice(index, 1);
|
||||
showAlert("撤单成功");
|
||||
updateBalanceDisplay();
|
||||
updateMyOrders();
|
||||
updateAssetTables(); // Refresh assets
|
||||
});
|
||||
}
|
||||
|
||||
function switchTab(tabName) {
|
||||
document.querySelectorAll('.asset-tab-content').forEach(el => el.style.display = 'none');
|
||||
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
|
||||
|
||||
document.getElementById(`tab-${tabName}`).style.display = 'block';
|
||||
// Simple active class logic: Find button by text content is hard, so just relying on user click flow or add IDs to buttons.
|
||||
// For now, let's just make the clicked button active.
|
||||
event.target.classList.add('active'); // "event" is available from the onclick inline call
|
||||
}
|
||||
|
||||
function updateAssetTables() {
|
||||
document.getElementById('asset-usdt-free').innerText = SYSTEM_STATE.balance.usdt.toFixed(2);
|
||||
document.getElementById('asset-btc-free').innerText = SYSTEM_STATE.balance.btc.toFixed(4);
|
||||
}
|
||||
|
||||
// --- Core Logic ---
|
||||
|
||||
// Initial Render
|
||||
function updateBalanceDisplay() {
|
||||
const balanceEl = document.querySelector("#trade-form p");
|
||||
balanceEl.innerHTML = `可用余额: <strong>${SYSTEM_STATE.balance.usdt.toFixed(2)} USDT</strong> / <strong>${SYSTEM_STATE.balance.btc.toFixed(4)} BTC</strong> <a href="#" style="color:#fcd535;" onclick="showDeposit()">[充值]</a>`;
|
||||
updateAssetTables();
|
||||
}
|
||||
|
||||
function showDeposit() {
|
||||
document.getElementById('deposit-modal').style.display = 'block';
|
||||
}
|
||||
|
||||
function simulateDeposit() {
|
||||
document.getElementById('deposit-modal').style.display = 'none';
|
||||
showAlert("模拟充值成功!账户增加 10,000 USDT");
|
||||
SYSTEM_STATE.balance.usdt += 10000;
|
||||
updateBalanceDisplay();
|
||||
}
|
||||
|
||||
function executeTrade(type) {
|
||||
const priceInput = document.querySelector('#trade-form input[type="text"]:nth-of-type(1)');
|
||||
const amountInput = document.querySelector('#trade-form input[type="text"]:nth-of-type(2)');
|
||||
const leverageCheck = document.querySelector('#trade-form input[type="checkbox"]');
|
||||
const typeRadio = document.querySelector('input[name="type"]:checked');
|
||||
|
||||
const price = parseFloat(priceInput.value);
|
||||
const amount = parseFloat(amountInput.value);
|
||||
const isLeverage = leverageCheck.checked;
|
||||
const isMarket = document.querySelectorAll('input[name="type"]')[1].checked; // Simple check
|
||||
|
||||
if (isNaN(price) || isNaN(amount) || amount <= 0) {
|
||||
showAlert("请输入有效的价格和数量");
|
||||
return;
|
||||
}
|
||||
|
||||
const total = price * amount;
|
||||
|
||||
if (isLeverage) {
|
||||
showConfirm(`警告:您开启了 100x 高倍杠杆。\n风险极高,是否继续?`, () => {
|
||||
processOrder(type, price, amount, total, true, isMarket);
|
||||
});
|
||||
} else {
|
||||
processOrder(type, price, amount, total, false, isMarket);
|
||||
}
|
||||
}
|
||||
|
||||
function processOrder(type, price, amount, total, leverage, isMarket) {
|
||||
// Validation with local state
|
||||
if(type === 'buy') {
|
||||
if (SYSTEM_STATE.balance.usdt < total) { showAlert("错误:可用 USDT 余额不足。"); return; }
|
||||
} else {
|
||||
if (SYSTEM_STATE.balance.btc < amount) { showAlert("错误:可用 BTC 余额不足。"); return; }
|
||||
}
|
||||
|
||||
const confirmMsg = isMarket ?
|
||||
`确认以市价 ${type === 'buy' ? '买入' : '卖出'} ${amount} BTC?` :
|
||||
`确认限价挂单: ${type === 'buy' ? '买入' : '卖出'} ${amount} BTC @ ${price}?`;
|
||||
|
||||
showConfirm(confirmMsg, () => {
|
||||
// Deduct balance immediately (freeze)
|
||||
if(type === 'buy') SYSTEM_STATE.balance.usdt -= total;
|
||||
else SYSTEM_STATE.balance.btc -= amount;
|
||||
|
||||
updateBalanceDisplay();
|
||||
|
||||
if (isMarket) {
|
||||
// Instant Fill
|
||||
addToRecentTrades(price, amount, type);
|
||||
// In a real app we'd get assets back here (e.g. BTC for buy), for now let's just add to balance
|
||||
if(type === 'buy') SYSTEM_STATE.balance.btc += amount;
|
||||
else SYSTEM_STATE.balance.usdt += total;
|
||||
|
||||
showAlert("市价单已立即成交!");
|
||||
updateBalanceDisplay();
|
||||
} else {
|
||||
// Limit Order -> Add to Open Orders
|
||||
SYSTEM_STATE.orders.push({
|
||||
type: type,
|
||||
pair: SYSTEM_STATE.market.pair,
|
||||
price: price,
|
||||
amount: amount,
|
||||
total: total,
|
||||
time: new Date()
|
||||
});
|
||||
showAlert("限价单已提交至交易引擎。");
|
||||
|
||||
// Switch to orders tab to show user
|
||||
switchTradeTab('orders');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addToRecentTrades(price, amount, type) {
|
||||
const list = document.getElementById('trade-list');
|
||||
const li = document.createElement('li');
|
||||
const now = new Date();
|
||||
const timeStr = now.toTimeString().split(' ')[0];
|
||||
li.innerHTML = `<small>${timeStr}</small> - ${price.toFixed(2)} - ${amount.toFixed(4)}`;
|
||||
li.style.color = type === 'buy' ? '#0ecb81' : '#f6465d';
|
||||
li.style.backgroundColor = '#2b3139';
|
||||
list.prepend(li);
|
||||
if(list.children.length > 20) list.lastElementChild.remove();
|
||||
}
|
||||
|
||||
// 模拟盘口数据跳动
|
||||
function simulateOrderBook() {
|
||||
const bidList = document.querySelectorAll('.book-column:nth-child(5) ul li');
|
||||
if(bidList.length === 0) return; // safety
|
||||
const askList = document.querySelectorAll('.book-column:nth-child(2) ul li');
|
||||
|
||||
if(Math.random() > 0.5) {
|
||||
const items = Math.random() > 0.5 ? bidList : askList;
|
||||
const idx = Math.floor(Math.random() * items.length);
|
||||
const span = items[idx].querySelector('span:last-child');
|
||||
if(span) {
|
||||
span.innerText = (Math.random() * 2).toFixed(2) + " BTC";
|
||||
items[idx].style.backgroundColor = "#2b3139";
|
||||
setTimeout(() => items[idx].style.backgroundColor = "transparent", 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 聊天室逻辑
|
||||
const chatInput = document.querySelector('#chat-room input');
|
||||
const chatBtn = document.querySelector('#chat-room button');
|
||||
chatInput.disabled = false; chatInput.placeholder = "输入消息..."; chatBtn.disabled = false;
|
||||
chatBtn.style.color = "white"; chatBtn.style.cursor = "pointer";
|
||||
chatBtn.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
const text = chatInput.value;
|
||||
if(text) {
|
||||
const chatBox = document.querySelector('.chat-messages');
|
||||
const p = document.createElement('p');
|
||||
p.innerHTML = `<strong style="color:#fcd535;">Me:</strong> ${text}`;
|
||||
chatBox.appendChild(p);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
chatInput.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
// Init Timers
|
||||
updateBalanceDisplay();
|
||||
setInterval(simulateOrderBook, 1000);
|
||||
|
||||
// Price Ticker
|
||||
setInterval(() => {
|
||||
const priceEl = document.getElementById('header-price');
|
||||
let current = parseFloat(priceEl.innerText.replace(',',''));
|
||||
@@ -410,15 +1015,37 @@
|
||||
let newPrice = (current + change).toFixed(2);
|
||||
priceEl.innerText = newPrice;
|
||||
|
||||
// 同时也往成交列表加一条假数据
|
||||
const list = document.getElementById('trade-list');
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `<small>12:00:0${Math.floor(Math.random()*9)}</small> - ${newPrice} - ${(Math.random()).toFixed(4)}`;
|
||||
li.style.color = change > 0 ? '#0ecb81' : '#f6465d';
|
||||
list.prepend(li);
|
||||
if(list.children.length > 20) list.lastElementChild.remove();
|
||||
|
||||
// Also add fake trades occasionally
|
||||
if(Math.random() > 0.3) {
|
||||
const list = document.getElementById('trade-list');
|
||||
const li = document.createElement('li');
|
||||
const now = new Date();
|
||||
const timeStr = now.toTimeString().split(' ')[0];
|
||||
li.innerHTML = `<small>${timeStr}</small> - ${newPrice} - ${(Math.random()).toFixed(4)}`;
|
||||
li.style.color = change > 0 ? '#0ecb81' : '#f6465d';
|
||||
list.prepend(li);
|
||||
if(list.children.length > 20) list.lastElementChild.remove();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
// API Log
|
||||
setInterval(() => {
|
||||
const logBox = document.getElementById('api-status');
|
||||
const logs = [
|
||||
`> Receiving tick data: ${document.getElementById('header-price').innerText}`,
|
||||
`> Latency check: ${Math.floor(Math.random() * 50 + 20)}ms`,
|
||||
`> Order matching engine heartbeat...`,
|
||||
`> Updating wallet balance hash...`,
|
||||
`> Syncing trade history...`
|
||||
];
|
||||
const newLog = logs[Math.floor(Math.random() * logs.length)];
|
||||
logBox.innerHTML += newLog + "<br>";
|
||||
logBox.scrollTop = logBox.scrollHeight;
|
||||
if (logBox.innerHTML.split('<br>').length > 20) {
|
||||
logBox.innerHTML = logBox.innerHTML.split('<br>').slice(-10).join('<br>');
|
||||
}
|
||||
}, 3500);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
1393
007/007_r.html
1393
007/007_r.html
File diff suppressed because it is too large
Load Diff
1616
008/008_r.html
1616
008/008_r.html
File diff suppressed because it is too large
Load Diff
1502
009/009_r.html
1502
009/009_r.html
File diff suppressed because it is too large
Load Diff
898
010/010_r.html
898
010/010_r.html
File diff suppressed because it is too large
Load Diff
11526
zhihu/001.html
Normal file
11526
zhihu/001.html
Normal file
File diff suppressed because one or more lines are too long
12833
zhihu/002.html
Normal file
12833
zhihu/002.html
Normal file
File diff suppressed because one or more lines are too long
14880
zhihu/003.html
Normal file
14880
zhihu/003.html
Normal file
File diff suppressed because one or more lines are too long
17565
zhihu/004.html
Normal file
17565
zhihu/004.html
Normal file
File diff suppressed because one or more lines are too long
24275
zhihu/005.html
Normal file
24275
zhihu/005.html
Normal file
File diff suppressed because one or more lines are too long
25726
zhihu/006.html
Normal file
25726
zhihu/006.html
Normal file
File diff suppressed because one or more lines are too long
26708
zhihu/007.html
Normal file
26708
zhihu/007.html
Normal file
File diff suppressed because one or more lines are too long
30
zhihu/record.json
Normal file
30
zhihu/record.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"step-1": {
|
||||
"query": "我想要回答一个问题,请你先帮我看看有哪些消息",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-2": {
|
||||
"query": "请你帮我找到2026年1月份最早请我回答的问题,并跳转到该问题详情页",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-3": {
|
||||
"query": "请你帮我给最长的回答一个赞同",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-4": {
|
||||
"query": "我想要回答,请你进入回答问题界面",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-5": {
|
||||
"query": "现在可能默认开启了markdown语法,请你先找到该设置在哪里",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-6": {
|
||||
"query": "请你关闭markdown语法",
|
||||
"grounding_area": ""
|
||||
},
|
||||
"step-7": {
|
||||
"query": "帮我用纯文本格式填写一个回答该问题的内容",
|
||||
"grounding_area": ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user