306 lines
10 KiB
HTML
306 lines
10 KiB
HTML
<script src="/assets/gerp/GERPThemeSync.js"></script>
|
|
<link rel="stylesheet" href="/assets/css/GERP.css">
|
|
<style>
|
|
.sv-container {
|
|
padding: 24px;
|
|
max-width: 1100px;
|
|
margin: 0 auto;
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
color: var(--TextPrimary, #1e293b);
|
|
}
|
|
|
|
.sv-section {
|
|
background: var(--CardBackground, #fff);
|
|
border: 1px solid var(--BorderColor, #e2e8f0);
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.sv-section-header {
|
|
background: var(--PrimaryColor, #2563eb);
|
|
color: #fff;
|
|
padding: 14px 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.sv-section-header h2 {
|
|
margin: 0;
|
|
font-size: 17px;
|
|
font-weight: 600;
|
|
color: #fff;
|
|
}
|
|
|
|
.sv-section-body { padding: 20px; }
|
|
|
|
.sv-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.sv-table th,
|
|
.sv-table td {
|
|
border: 1px solid var(--BorderColor, #e2e8f0);
|
|
padding: 8px 10px;
|
|
text-align: left;
|
|
}
|
|
|
|
.sv-table th {
|
|
background: var(--BackgroundColor, #f5f5f5);
|
|
font-weight: 600;
|
|
color: var(--TextSecondary, #64748b);
|
|
}
|
|
|
|
.sv-table tr:hover td { background: var(--HoverBackground, rgba(0,0,0,0.03)); }
|
|
|
|
/* td.sv-empty 选择器优先级高于 .sv-table td,确保空状态居中 */
|
|
.sv-table td.sv-empty {
|
|
text-align: center;
|
|
padding: 28px;
|
|
color: var(--TextSecondary, #64748b);
|
|
}
|
|
|
|
.sv-table td.sv-empty i {
|
|
font-size: 28px;
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
opacity: 0.4;
|
|
}
|
|
|
|
.sv-cash-btn {
|
|
padding: 5px 12px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
background: var(--DangerColor, #ef4444);
|
|
color: #fff;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.sv-cash-btn:hover { opacity: 0.9; }
|
|
.sv-cash-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
|
|
.sv-loading {
|
|
display: inline-block;
|
|
animation: sv-spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes sv-spin { to { transform: rotate(360deg); } }
|
|
|
|
.sv-btn-ghost {
|
|
background: rgba(255,255,255,0.2);
|
|
color: #fff;
|
|
border: none;
|
|
padding: 6px 14px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.sv-btn-ghost:hover { opacity: 0.9; }
|
|
|
|
/* Toast */
|
|
.sv-toast-wrap {
|
|
position: fixed;
|
|
bottom: 16px;
|
|
right: 16px;
|
|
z-index: 9999;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.sv-toast {
|
|
padding: 10px 14px;
|
|
border-radius: 6px;
|
|
color: #fff;
|
|
font-size: 13px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
animation: sv-toast-in 0.25s ease-out;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.sv-toast.out { animation: sv-toast-out 0.25s ease-in forwards; }
|
|
|
|
@keyframes sv-toast-in {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes sv-toast-out {
|
|
from { opacity: 1; }
|
|
to { opacity: 0; transform: translateY(-8px); }
|
|
}
|
|
</style>
|
|
|
|
<div class="sv-container">
|
|
<div class="sv-section">
|
|
<div class="sv-section-header">
|
|
<h2>已购买储值项目</h2>
|
|
<button id="refresh-btn" class="sv-btn-ghost">刷新</button>
|
|
</div>
|
|
<div class="sv-section-body">
|
|
<div style="overflow-x:auto;">
|
|
<table class="sv-table">
|
|
<thead>
|
|
<tr>
|
|
<th>玩家名称</th>
|
|
<th>储值类型</th>
|
|
<th>创建时间</th>
|
|
<th>最短取出时间</th>
|
|
<th>已存日期</th>
|
|
<th>日利率</th>
|
|
<th>储值金额</th>
|
|
<th>累计利息</th>
|
|
<th>生效长度</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="storage-table-body">
|
|
<tr><td colspan="10" class="sv-empty"><i class="fas fa-spinner sv-loading"></i><p>加载中...</p></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sv-toast-wrap" id="toast-wrap"></div>
|
|
|
|
<script>
|
|
(function () {
|
|
'use strict';
|
|
|
|
function showToast(message, type) {
|
|
const wrap = document.getElementById('toast-wrap');
|
|
const t = document.createElement('div');
|
|
t.className = 'sv-toast';
|
|
const colors = {
|
|
success: '#10b981', danger: '#ef4444',
|
|
warning: '#f59e0b', info: '#3b82f6'
|
|
};
|
|
t.style.background = colors[type || 'info'] || colors.info;
|
|
const icons = {
|
|
success: 'fa-check-circle', danger: 'fa-exclamation-circle',
|
|
warning: 'fa-exclamation-triangle', info: 'fa-info-circle'
|
|
};
|
|
t.innerHTML = '<i class="fas ' + (icons[type || 'info'] || icons.info) + '"></i><span>' + message + '</span>';
|
|
wrap.appendChild(t);
|
|
setTimeout(function () {
|
|
t.classList.add('out');
|
|
setTimeout(function () { t.remove(); }, 260);
|
|
}, 3000);
|
|
}
|
|
|
|
function formatNum(n) {
|
|
if (n === null || n === undefined || isNaN(n)) return '0';
|
|
return Number(n).toLocaleString();
|
|
}
|
|
|
|
function fetchStorageData() {
|
|
const tbody = document.getElementById('storage-table-body');
|
|
tbody.innerHTML = '<tr><td colspan="10" class="sv-empty"><i class="fas fa-spinner sv-loading"></i><p>加载中...</p></td></tr>';
|
|
fetch('/API/StoredValue/GetStoreValue', { credentials: 'include' })
|
|
.then(function (r) {
|
|
if (!r.ok) throw new Error('Network error');
|
|
return r.json();
|
|
})
|
|
.then(function (data) {
|
|
if (data.status === 0 && Array.isArray(data.data)) {
|
|
if (data.data.length > 0) {
|
|
tbody.innerHTML = data.data.map(function (item) {
|
|
return '<tr>' +
|
|
'<td>' + (item.PlayerName || '') + '</td>' +
|
|
'<td>' + (item.StoreValueType || '') + '</td>' +
|
|
'<td>' + (item.StoreValueCreateDateTime || '') + '</td>' +
|
|
'<td>' + (item.StoreValueMin || '') + '</td>' +
|
|
'<td>' + formatNum(item.GameDays) + ' 游戏日 / ' + formatNum(item.Days) + ' 现实日</td>' +
|
|
'<td>' + (item.StoreValueDayInterestRate || 0) + '</td>' +
|
|
'<td>' + formatNum(item.StoreValueAmount) + ' GC</td>' +
|
|
'<td>' + formatNum(item.AccruedInterest) + ' GC</td>' +
|
|
'<td>' + (item.StoreValueExpirationGameDate || '') + ' 游戏日</td>' +
|
|
'<td><button class="sv-cash-btn" data-uuid="' + item.StoreValueUUID + '">兑现</button></td>' +
|
|
'</tr>';
|
|
}).join('');
|
|
document.querySelectorAll('.sv-cash-btn').forEach(function (btn) {
|
|
btn.addEventListener('click', function () { handleCash(btn); });
|
|
});
|
|
} else {
|
|
tbody.innerHTML = '<tr><td colspan="10" class="sv-empty"><i class="fas fa-inbox"></i><p>暂无储值数据</p></td></tr>';
|
|
}
|
|
} else {
|
|
tbody.innerHTML = '<tr><td colspan="10" class="sv-empty"><i class="fas fa-exclamation-circle"></i><p>' + (data.msg || '加载失败') + '</p></td></tr>';
|
|
}
|
|
})
|
|
.catch(function (err) {
|
|
console.error('fetchStorageData error:', err);
|
|
tbody.innerHTML = '<tr><td colspan="10" class="sv-empty"><i class="fas fa-exclamation-circle"></i><p>加载失败,请重试</p></td></tr>';
|
|
});
|
|
}
|
|
|
|
function handleCash(btn) {
|
|
const uuid = btn.getAttribute('data-uuid');
|
|
btn.disabled = true;
|
|
btn.textContent = '处理中...';
|
|
fetch('/API/StoredValue/Cash', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify({ StoreValueUUID: uuid })
|
|
})
|
|
.then(function (r) { return r.json(); })
|
|
.then(function (data) {
|
|
if (data.status === 0) {
|
|
showToast('兑现成功', 'success');
|
|
fetchStorageData();
|
|
} else {
|
|
showToast(data.msg || '兑现失败', 'danger');
|
|
btn.disabled = false;
|
|
btn.textContent = '兑现';
|
|
}
|
|
})
|
|
.catch(function (err) {
|
|
console.error('handleCash error:', err);
|
|
showToast('网络错误,兑现失败', 'danger');
|
|
btn.disabled = false;
|
|
btn.textContent = '兑现';
|
|
});
|
|
}
|
|
|
|
document.getElementById('refresh-btn').addEventListener('click', fetchStorageData);
|
|
|
|
fetchStorageData();
|
|
})();
|
|
|
|
// ==================== GERP 主题同步 ====================
|
|
window.addEventListener('load', function () {
|
|
const CheckAndInit = () => {
|
|
if (window.GERPThemeSync) {
|
|
window.GERPThemeSync.init();
|
|
return;
|
|
}
|
|
setTimeout(CheckAndInit, 100);
|
|
};
|
|
CheckAndInit();
|
|
if (window.parent !== window) {
|
|
window.parent.postMessage({ type: 'GET_THEME' }, '*');
|
|
}
|
|
});
|
|
window.addEventListener('message', function (e) {
|
|
if (e.data && e.data.type === 'THEME_CHANGE') {
|
|
const colors = e.data.colors || (e.data.data && e.data.data.colors);
|
|
if (colors) {
|
|
const root = document.documentElement;
|
|
Object.entries(colors).forEach(([key, value]) => {
|
|
root.style.setProperty('--' + key, value);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
</script>
|