Files
grepo-remote/templates/farm.html
2026-04-23 18:45:54 +03:00

388 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="el">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Farm Manager — Grepolis Remote</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #0f0f1a;
font-family: 'Inter', 'Segoe UI', sans-serif;
color: #e0e0e0;
min-height: 100vh;
padding: 1.5rem;
}
/* ---- Top bar ---- */
.topbar {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
}
.topbar a {
color: #666;
text-decoration: none;
font-size: 0.85rem;
transition: color 0.2s;
}
.topbar a:hover { color: #c8a44a; }
.topbar h1 {
font-size: 1.5rem;
font-weight: 800;
color: #4acc64;
}
.online-dot {
width: 9px; height: 9px;
border-radius: 50%;
background: #cc7b7b;
box-shadow: 0 0 6px #cc7b7b;
display: inline-block;
margin-left: auto;
}
.online-dot.live { background: #7bcc7b; box-shadow: 0 0 6px #7bcc7b; }
/* ---- Control Panel ---- */
.panel {
background: #1a1a28;
border: 1px solid #2a2a40;
border-radius: 16px;
padding: 1.75rem;
margin-bottom: 1.5rem;
}
.panel h2 {
font-size: 1rem;
font-weight: 700;
color: #aaa;
text-transform: uppercase;
letter-spacing: 0.07em;
margin-bottom: 1.25rem;
}
/* Toggle switch */
.toggle-row {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1.5rem;
}
.toggle-label { font-size: 1rem; font-weight: 600; }
.toggle {
position: relative;
width: 56px;
height: 30px;
cursor: pointer;
}
.toggle input { opacity: 0; width: 0; height: 0; }
.slider {
position: absolute;
inset: 0;
background: #2a2a3a;
border-radius: 30px;
transition: background 0.3s;
border: 1px solid #3a3a50;
}
.slider::before {
content: '';
position: absolute;
width: 22px; height: 22px;
left: 4px; top: 3px;
background: #666;
border-radius: 50%;
transition: transform 0.3s, background 0.3s;
}
input:checked + .slider { background: rgba(74,204,100,0.25); border-color: #4acc64; }
input:checked + .slider::before { transform: translateX(26px); background: #4acc64; }
/* Loot option selector */
.option-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.option-btn {
background: #12121e;
border: 2px solid #2a2a40;
border-radius: 10px;
padding: 0.75rem 0.5rem;
cursor: pointer;
text-align: center;
transition: border-color 0.2s, background 0.2s;
color: #888;
font-family: inherit;
font-size: 0.9rem;
}
.option-btn .opt-time { font-size: 1.1rem; font-weight: 700; color: #ccc; display: block; }
.option-btn .opt-name { font-size: 0.72rem; color: #666; margin-top: 2px; display: block; }
.option-btn:hover { border-color: #4acc64; background: rgba(74,204,100,0.05); }
.option-btn.selected { border-color: #4acc64; background: rgba(74,204,100,0.12); color: #4acc64; }
.option-btn.selected .opt-time { color: #4acc64; }
.option-btn.selected .opt-name { color: #4acc64bb; }
.save-btn {
background: linear-gradient(135deg, #2a7a3a, #4acc64);
color: #fff;
border: none;
border-radius: 10px;
padding: 0.7rem 2rem;
font-family: inherit;
font-size: 0.95rem;
font-weight: 700;
cursor: pointer;
transition: opacity 0.2s, transform 0.1s;
}
.save-btn:hover { opacity: 0.9; transform: translateY(-1px); }
.save-btn:active { transform: translateY(0); }
.save-status {
margin-left: 1rem;
font-size: 0.85rem;
color: #4acc64;
opacity: 0;
transition: opacity 0.3s;
}
.save-status.visible { opacity: 1; }
/* ---- Farm Table ---- */
.farm-table-wrap { overflow-x: auto; }
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
thead th {
text-align: left;
padding: 0.6rem 1rem;
color: #666;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.06em;
border-bottom: 1px solid #2a2a40;
}
tbody tr { border-bottom: 1px solid #1e1e2e; transition: background 0.15s; }
tbody tr:hover { background: rgba(255,255,255,0.03); }
tbody td { padding: 0.75rem 1rem; }
.badge {
display: inline-block;
padding: 2px 10px;
border-radius: 20px;
font-size: 0.78rem;
font-weight: 600;
}
.badge.ready { background: rgba(74,204,100,0.2); color: #4acc64; border: 1px solid rgba(74,204,100,0.35); }
.badge.waiting { background: rgba(150,150,200,0.1); color: #888; border: 1px solid #2a2a40; }
.countdown { font-size: 0.82rem; color: #6fcfcf; }
/* Status bar */
.status-bar {
background: rgba(74,204,100,0.08);
border: 1px solid rgba(74,204,100,0.2);
border-radius: 10px;
padding: 0.75rem 1.25rem;
font-size: 0.875rem;
color: #4acc64;
margin-bottom: 1.5rem;
display: none;
}
.status-bar.visible { display: block; }
.status-bar.off {
background: rgba(200,100,100,0.08);
border-color: rgba(200,100,100,0.2);
color: #cc7b7b;
}
/* Empty state */
.empty-state { text-align: center; padding: 3rem 1rem; color: #555; }
.empty-state p { margin-top: 0.5rem; font-size: 0.9rem; }
</style>
</head>
<body>
<div class="topbar">
<a href="/player/{{ player_id }}">← Πίσω</a>
<h1>🌾 Farm Manager</h1>
<span class="online-dot" id="online-dot" title="Κατάσταση Script"></span>
</div>
<!-- Status banner -->
<div class="status-bar" id="status-bar"></div>
<!-- Control Panel -->
<div class="panel">
<h2>⚙️ Ρυθμίσεις</h2>
<div class="toggle-row">
<span class="toggle-label">Αυτόματη Λεηλασία</span>
<label class="toggle">
<input type="checkbox" id="farm-enabled">
<span class="slider"></span>
</label>
<span style="color:#888; font-size:0.85rem;" id="toggle-hint">Ανενεργό</span>
</div>
<div style="margin-bottom: 0.75rem; font-size: 0.85rem; color: #888;">Επίπεδο Λεηλασίας:</div>
<div class="option-grid">
<button class="option-btn selected" data-option="1">
<span class="opt-time">5'</span>
<span class="opt-name">Γρήγορο</span>
</button>
<button class="option-btn" data-option="2">
<span class="opt-time">20'</span>
<span class="opt-name">Κανονικό</span>
</button>
<button class="option-btn" data-option="3">
<span class="opt-time">90'</span>
<span class="opt-name">Αργό</span>
</button>
<button class="option-btn" data-option="4">
<span class="opt-time">4h</span>
<span class="opt-name">Ύπνος</span>
</button>
</div>
<button class="save-btn" id="save-btn" onclick="saveSettings()">💾 Αποθήκευση</button>
<span class="save-status" id="save-status">✓ Αποθηκεύτηκε</span>
</div>
<!-- Farm Status Table -->
<div class="panel">
<h2>🏘️ Κατάσταση Χωριών</h2>
<div class="farm-table-wrap">
<table>
<thead>
<tr>
<th>Πόλη</th>
<th>Έτοιμα</th>
<th>Σύνολο</th>
<th>Επόμενο</th>
</tr>
</thead>
<tbody id="farm-table-body">
<tr><td colspan="4"><div class="empty-state"><p>Φόρτωση δεδομένων...</p></div></td></tr>
</tbody>
</table>
</div>
</div>
<script>
const PLAYER_ID = '{{ player_id }}';
let selectedOption = 1;
// -- Loot option buttons --
document.querySelectorAll('.option-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.option-btn').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
selectedOption = parseInt(btn.dataset.option);
});
});
// -- Toggle hint text --
document.getElementById('farm-enabled').addEventListener('change', function () {
document.getElementById('toggle-hint').textContent = this.checked ? '🟢 Ενεργό' : 'Ανενεργό';
updateStatusBar(this.checked);
});
function updateStatusBar(enabled) {
const bar = document.getElementById('status-bar');
if (enabled) {
bar.className = 'status-bar visible';
bar.textContent = '🤖 Ο αυτόματος farmer είναι ενεργός. Το script θα λεηλατεί χωριά με τυχαίες καθυστερήσεις.';
} else {
bar.className = 'status-bar visible off';
bar.textContent = '⏸ Η αυτόματη λεηλασία είναι ανενεργή.';
}
}
// -- Save settings --
function saveSettings() {
const enabled = document.getElementById('farm-enabled').checked;
fetch('/dashboard/farm-settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ player_id: PLAYER_ID, enabled, loot_option: selectedOption })
})
.then(r => r.json())
.then(() => {
const s = document.getElementById('save-status');
s.classList.add('visible');
setTimeout(() => s.classList.remove('visible'), 2500);
});
}
// -- Load current settings --
function loadSettings() {
fetch(`/dashboard/farm-settings?player_id=${PLAYER_ID}`)
.then(r => r.json())
.then(cfg => {
document.getElementById('farm-enabled').checked = cfg.enabled;
document.getElementById('toggle-hint').textContent = cfg.enabled ? '🟢 Ενεργό' : 'Ανενεργό';
if (cfg.enabled) updateStatusBar(true);
selectedOption = cfg.loot_option || 1;
document.querySelectorAll('.option-btn').forEach(b => {
b.classList.toggle('selected', parseInt(b.dataset.option) === selectedOption);
});
});
}
// -- Load farm data table --
function loadFarmData() {
fetch(`/dashboard/farm-data?player_id=${PLAYER_ID}`)
.then(r => r.json())
.then(data => {
const tbody = document.getElementById('farm-table-body');
if (!data || data.length === 0) {
tbody.innerHTML = '<tr><td colspan="4"><div class="empty-state">🌱 <p>Δεν υπάρχουν δεδομένα χωριών ακόμη.<br>Βεβαιώσου ότι το script v3.3+ τρέχει στο παιχνίδι.</p></div></td></tr>';
return;
}
const now = Math.floor(Date.now() / 1000);
tbody.innerHTML = data.map(t => {
const readyBadge = t.ready_farms > 0
? `<span class="badge ready">✓ ${t.ready_farms} Έτοιμα</span>`
: `<span class="badge waiting">Αναμονή</span>`;
let nextStr = '—';
if (t.next_ready_at) {
const diff = t.next_ready_at - now;
if (diff > 0) {
const m = Math.floor(diff / 60);
const s = diff % 60;
nextStr = `<span class="countdown">${m}λ ${s}δ</span>`;
} else {
nextStr = '<span class="countdown">Τώρα</span>';
}
}
return `<tr>
<td><strong>${t.town_name}</strong></td>
<td>${readyBadge}</td>
<td><span style="color:#888">${t.total_farms}</span></td>
<td>${nextStr}</td>
</tr>`;
}).join('');
});
}
// -- Online status check --
function checkOnline() {
fetch(`/dashboard/client-status?player_id=${PLAYER_ID}`)
.then(r => r.json())
.then(d => {
const dot = document.getElementById('online-dot');
dot.className = 'online-dot' + (d.online ? ' live' : '');
dot.title = d.online ? 'Script Online' : 'Script Offline';
});
}
// -- Boot --
loadSettings();
loadFarmData();
checkOnline();
setInterval(loadFarmData, 15000);
setInterval(checkOnline, 20000);
</script>
</body>
</html>