代码推送

This commit is contained in:
2026-09-09 02:39:57 +08:00
parent a112893947
commit 5e47757c73
24 changed files with 1156 additions and 226 deletions

View File

@@ -216,19 +216,38 @@ tbody tr:last-child td{border-bottom:none}
<!-- Login Overlay -->
<div class="login-overlay" id="loginOverlay">
<div class="login-card">
<h1>🔐 管理后台</h1>
<p class="subtitle">Gotest Admin Dashboard</p>
<div class="form-group">
<label>用户名</label>
<input type="text" id="loginUsername" placeholder="请输入用户名" value="admin">
<h1 id="loginTitle">🔐 管理后台</h1>
<p class="subtitle" id="loginSubtitle">Gotest Admin Dashboard</p>
<!-- 登录表单 -->
<div id="loginForm">
<div class="form-group">
<label>用户名</label>
<input type="text" id="loginUsername" placeholder="请输入用户名">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" id="loginPassword" placeholder="请输入密码">
</div>
<button class="login-btn" id="loginBtn" onclick="doLogin()">登 录</button>
<div class="login-error" id="loginError"></div>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" id="loginPassword" placeholder="请输入密码" value="admin123">
<!-- 初始化表单(无管理员时显示) -->
<div id="initForm" style="display:none">
<div class="form-group">
<label>管理员用户名</label>
<input type="text" id="initUsername" placeholder="请设置管理员用户名">
</div>
<div class="form-group">
<label>管理员密码</label>
<input type="password" id="initPassword" placeholder="请设置密码(至少6位)">
</div>
<div class="form-group">
<label>确认密码</label>
<input type="password" id="initPasswordConfirm" placeholder="请再次输入密码">
</div>
<button class="login-btn" id="initBtn" onclick="doInitAdmin()">初始化管理员</button>
<div class="login-error" id="initError"></div>
</div>
<button class="login-btn" id="loginBtn" onclick="doLogin()">登 录</button>
<div class="login-error" id="loginError"></div>
<div class="login-hint">默认账号: admin / admin123</div>
</div>
</div>
@@ -248,6 +267,12 @@ tbody tr:last-child td{border-bottom:none}
<span class="icon">📦</span> 内容管理
</a>
<div class="sidebar-section">系统</div>
<a class="sidebar-link" onclick="navigate('accesslog')" data-page="accesslog">
<span class="icon">📊</span> 访问日志
</a>
<a class="sidebar-link" onclick="navigate('webhook')" data-page="webhook">
<span class="icon">🔔</span> Webhook配置
</a>
<a class="sidebar-link" onclick="navigate('settings')" data-page="settings">
<span class="icon">⚙️</span> 系统设置
</a>
@@ -343,6 +368,45 @@ function toast(msg, type = 'info') {
}
// ===== 登录/登出 =====
async function checkAdminExists() {
try {
const resp = await fetch(API_BASE + '/admin/check');
const data = await resp.json();
return data.data && data.data.initialized;
} catch (e) {
return false;
}
}
async function doInitAdmin() {
const btn = document.getElementById('initBtn');
const username = document.getElementById('initUsername').value.trim();
const password = document.getElementById('initPassword').value;
const confirm = document.getElementById('initPasswordConfirm').value;
const errEl = document.getElementById('initError');
if (!username || !password) { errEl.textContent = '请输入用户名和密码'; return; }
if (password.length < 6) { errEl.textContent = '密码至少6位'; return; }
if (password !== confirm) { errEl.textContent = '两次密码不一致'; return; }
btn.disabled = true; btn.textContent = '初始化中...'; errEl.textContent = '';
try {
const resp = await fetch(API_BASE + '/admin/init', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await resp.json();
if (data.code !== 0) { errEl.textContent = data.message || '初始化失败'; return; }
toast('初始化成功,请登录', 'success');
document.getElementById('initForm').style.display = 'none';
document.getElementById('loginForm').style.display = 'block';
document.getElementById('loginSubtitle').textContent = '请输入刚创建的管理员账号';
} catch (e) {
errEl.textContent = '网络错误,请重试';
} finally {
btn.disabled = false; btn.textContent = '初始化管理员';
}
}
async function doLogin() {
const btn = document.getElementById('loginBtn');
const username = document.getElementById('loginUsername').value.trim();
@@ -391,12 +455,14 @@ function navigate(page, params = {}) {
document.querySelectorAll('.sidebar-link').forEach(el => el.classList.remove('active'));
const link = document.querySelector(`[data-page="${page}"]`);
if (link) link.classList.add('active');
const titles = { users: '用户管理', content: '内容管理', settings: '系统设置', sites: '站点导航' };
const titles = { users: '用户管理', content: '内容管理', settings: '系统设置', sites: '站点导航', accesslog: '访问日志', webhook: 'Webhook配置' };
document.getElementById('pageTitle').textContent = titles[page] || page;
if (page === 'users') renderUsers();
else if (page === 'content') renderContent(params.table);
else if (page === 'settings') renderSettings();
else if (page === 'sites') renderSites();
else if (page === 'accesslog') renderAccessLogs();
else if (page === 'webhook') renderWebhook();
if (window.innerWidth <= 768) document.getElementById('sidebar').classList.remove('open');
}
@@ -1050,6 +1116,175 @@ function renderSites() {
el.innerHTML = html;
}
// ===== 访问日志 =====
let accessLogPage = 1, accessLogPageSize = 20;
async function renderAccessLogs(page) {
if (page) accessLogPage = page;
const el = document.getElementById('content');
el.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
try {
const [statsData, logsData] = await Promise.all([
api('/admin/access-logs/stats'),
api(`/admin/access-logs?page=${accessLogPage}&page_size=${accessLogPageSize}`)
]);
const stats = statsData.data;
const logs = logsData.data;
let hourlyChart = '';
if (stats.hourly && stats.hourly.length > 0) {
const maxCount = Math.max(...stats.hourly.map(h => h.count));
hourlyChart = stats.hourly.map(h => {
const pct = maxCount > 0 ? (h.count / maxCount * 100) : 0;
const hour = h.hour ? h.hour.split(' ')[1] || h.hour : '';
return `<div style="display:flex;align-items:end;gap:4px;flex-direction:column;align-items:center;flex:1">
<div style="font-size:11px;color:var(--text-muted)">${h.count}</div>
<div style="width:100%;max-width:32px;background:var(--primary);border-radius:4px 4px 0 0;height:${Math.max(4, pct)}%;min-height:4px;transition:height .3s"></div>
<div style="font-size:10px;color:var(--text-muted)">${hour}</div>
</div>`;
}).join('');
}
el.innerHTML = `
<div class="stats-grid" style="margin-bottom:24px">
<div class="stat-card">
<div class="stat-icon bg-blue">📈</div>
<div class="stat-value">${stats.total_visits || 0}</div>
<div class="stat-label">总访问量</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-green">📅</div>
<div class="stat-value">${stats.today_visits || 0}</div>
<div class="stat-label">今日访问</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-purple">🌐</div>
<div class="stat-value">${stats.unique_ips || 0}</div>
<div class="stat-label">独立IP</div>
</div>
</div>
${hourlyChart ? `<div class="table-card" style="margin-bottom:24px">
<div class="section-header" style="padding:16px"><h4>📊 最近24小时访问趋势</h4></div>
<div style="padding:16px;display:flex;align-items:end;gap:6px;height:180px">${hourlyChart}</div>
</div>` : ''}
<div class="table-card">
<div class="table-toolbar">
<h4 style="font-size:14px;font-weight:600">📋 访问记录</h4>
<button class="btn btn-danger btn-sm" onclick="clearAccessLogs()">清空日志</button>
</div>
<div class="table-wrap">
<table>
<thead><tr><th>时间</th><th>IP</th><th>归属地</th><th>路径</th><th>方法</th><th>状态</th><th>耗时</th></tr></thead>
<tbody>
${logs.list.length === 0 ? '<tr class="empty-row"><td colspan="7">暂无访问记录</td></tr>' : logs.list.map(l => `
<tr>
<td>${formatDate(l.created_at)}</td>
<td><code style="background:#f1f5f9;padding:2px 6px;border-radius:4px;font-size:12px">${l.ip}</code></td>
<td style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${l.location||''}">${l.location || '-'}</td>
<td style="max-width:250px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${l.path}">${l.path}</td>
<td><span class="badge-status ${l.method==='GET'?'badge-active':'badge-inactive'}">${l.method}</span></td>
<td><span class="badge-status ${l.status<400?'badge-active':'badge-inactive'}">${l.status}</span></td>
<td>${l.cost}ms</td>
</tr>`).join('')}
</tbody>
</table>
</div>
${renderPagination(logs, 'renderAccessLogs')}
</div>`;
} catch (e) { el.innerHTML = '<div class="loading">加载失败</div>'; }
}
async function clearAccessLogs() {
if (!confirm('确定清空所有访问日志?')) return;
try {
await api('/admin/access-logs', { method: 'DELETE' });
toast('清空成功', 'success');
renderAccessLogs(1);
} catch (e) {}
}
// ===== Webhook 配置 =====
async function renderWebhook() {
const el = document.getElementById('content');
el.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
try {
const data = await api('/admin/config/wechat_webhook_url');
const url = data.data ? data.data.value : '';
el.innerHTML = `
<div class="table-card">
<div class="section-header" style="padding:16px"><h4>🔔 企业微信 Webhook 配置</h4></div>
<div style="padding:24px;max-width:700px">
<div class="form-group">
<label>Webhook URL</label>
<input type="text" id="webhookUrl" value="${url || ''}" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" style="width:100%">
<div style="font-size:12px;color:var(--text-muted);margin-top:6px">
企业微信群机器人的 Webhook 地址,用于接收客户咨询通知和系统告警
</div>
</div>
<div style="display:flex;gap:8px;margin-top:20px">
<button class="btn btn-primary" onclick="saveWebhook()">保存配置</button>
<button class="btn btn-outline" onclick="testWebhook()">测试发送</button>
</div>
<div id="webhookTestResult" style="margin-top:12px;display:none"></div>
</div>
</div>
<div class="table-card" style="margin-top:16px">
<div class="section-header" style="padding:16px"><h4>📖 使用说明</h4></div>
<div style="padding:0 24px 24px">
<ol style="line-height:2;color:var(--text-muted);font-size:13px">
<li>在企业微信群中添加一个<strong>群机器人</strong></li>
<li>点击机器人头像,复制 <strong>Webhook 地址</strong></li>
<li>将地址粘贴到上方输入框并保存</li>
<li>点击「测试发送」验证配置是否正确</li>
<li>配置成功后,客户咨询通知将自动推送到该群</li>
</ol>
</div>
</div>`;
} catch (e) { el.innerHTML = '<div class="loading">加载失败</div>'; }
}
async function saveWebhook() {
const url = document.getElementById('webhookUrl').value.trim();
try {
await api('/admin/config/wechat_webhook_url', {
method: 'PUT',
body: JSON.stringify({ value: url, remark: '企业微信群机器人Webhook地址' })
});
toast('保存成功', 'success');
} catch (e) {}
}
async function testWebhook() {
const resultEl = document.getElementById('webhookTestResult');
resultEl.style.display = 'block';
resultEl.innerHTML = '<div style="color:var(--text-muted)">发送中...</div>';
try {
await api('/admin/config/wechat_webhook_url', {
method: 'PUT',
body: JSON.stringify({ value: document.getElementById('webhookUrl').value.trim(), remark: '企业微信群机器人Webhook地址' })
});
// 通过客户咨询接口发送测试消息
const resp = await fetch(API_BASE + '/customer/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: '测试用户',
phone: '13800000000',
company: '测试公司',
email: 'test@example.com',
needs: '这是一条测试消息,用于验证 Webhook 配置是否正确'
})
});
const data = await resp.json();
if (data.code === 0) {
resultEl.innerHTML = '<div style="color:var(--success);font-weight:600">✅ 测试消息已发送,请检查企业微信群</div>';
} else {
resultEl.innerHTML = `<div style="color:var(--danger)">❌ 发送失败: ${data.message}</div>`;
}
} catch (e) {
resultEl.innerHTML = '<div style="color:var(--danger)">❌ 网络错误</div>';
}
}
// ===== 通用工具 =====
function formatDate(d) {
if (!d) return '-';
@@ -1126,6 +1361,20 @@ document.getElementById('modalOverlay').addEventListener('click', (e) => {
document.getElementById('loginPassword').addEventListener('keydown', (e) => {
if (e.key === 'Enter') doLogin();
});
document.getElementById('initPasswordConfirm')?.addEventListener('keydown', (e) => {
if (e.key === 'Enter') doInitAdmin();
});
// 检查管理员是否存在,决定显示登录还是初始化
(async function() {
const hasAdmin = await checkAdminExists();
if (!hasAdmin) {
document.getElementById('loginForm').style.display = 'none';
document.getElementById('initForm').style.display = 'block';
document.getElementById('loginTitle').textContent = '🚀 初始化系统';
document.getElementById('loginSubtitle').textContent = '首次使用,请创建管理员账号';
}
})();
// 检查登录状态
if (token) {

192
web/dist/index.html vendored
View File

@@ -4,11 +4,19 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gotest · 模板导航</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='22' fill='%23000'/><text x='50' y='70' font-size='58' font-weight='bold' fill='white' text-anchor='middle' font-family='Arial'>G</text></svg>">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='22' fill='%23000'/><text x='50' y='70' font-size='58' font-weight='bold' fill='white' text-anchor='middle' font-family='Arial'>G</text></svg)">
<script>
// Prevent FOUC: apply theme before render
(function(){
var t = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-theme', t);
})();
</script>
<style>
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#f5f5f7;--text:#1d1d1f;--text-sub:#86868b;--card:#fff;--border:rgba(0,0,0,.06);--radius:20px;--shadow:0 4px 24px rgba(0,0,0,.06);--shadow-hover:0 12px 40px rgba(0,0,0,.12)}
body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Roboto,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;-webkit-font-smoothing:antialiased}
:root{--bg:#f5f5f7;--text:#1d1d1f;--text-sub:#86868b;--card:#fff;--border:rgba(0,0,0,.06);--radius:20px;--shadow:0 4px 24px rgba(0,0,0,.06);--shadow-hover:0 12px 40px rgba(0,0,0,.12);--form-bg:rgba(255,255,255,0.95);--input-bg:#f9f9f9;--input-border:#e5e5e5;--admin-btn-bg:#1d1d1f;--admin-btn-hover:#000}
[data-theme="dark"]{--bg:#0f0f12;--text:#f5f5f7;--text-sub:#a1a1aa;--card:#1c1c22;--border:rgba(255,255,255,.08);--shadow:0 4px 24px rgba(0,0,0,.3);--shadow-hover:0 12px 40px rgba(0,0,0,.5);--form-bg:rgba(28,28,34,0.95);--input-bg:#27272a;--input-border:#3f3f46;--admin-btn-bg:#f5f5f7;--admin-btn-hover:#fff}
body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Roboto,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;-webkit-font-smoothing:antialiased;transition:background .3s,color .3s}
.wrap{max-width:1120px;margin:0 auto;padding:48px 24px 64px}
/* Hero */
.hero{text-align:center;padding:48px 0 56px}
@@ -17,6 +25,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
.hero p{font-size:19px;color:var(--text-sub);max-width:580px;margin:0 auto;line-height:1.5}
.hero-pills{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:28px}
.pill{padding:6px 16px;border-radius:100px;background:#fff;border:1px solid var(--border);font-size:13px;color:var(--text-sub);font-weight:500}
[data-theme="dark"] .pill{background:#27272a}
.pill b{color:var(--text)}
/* Section */
.sec{margin-bottom:56px}
@@ -46,9 +55,17 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
.g-music .glow{background:linear-gradient(135deg,#312e81 0%,#7c3aed 40%,#f472b6 100%)}
/* Admin */
.admin-row{display:flex;justify-content:center;margin-top:56px}
.admin-btn{display:inline-flex;align-items:center;gap:8px;padding:14px 32px;border-radius:100px;background:#1d1d1f;color:#fff;text-decoration:none;font-size:15px;font-weight:600;transition:all .25s}
.admin-btn:hover{background:#000;transform:scale(1.03)}
.admin-btn{display:inline-flex;align-items:center;gap:8px;padding:14px 32px;border-radius:100px;background:var(--admin-btn-bg);color:var(--text);text-decoration:none;font-size:15px;font-weight:600;transition:all .25s}
.admin-btn:hover{background:var(--admin-btn-hover);transform:scale(1.03)}
.admin-btn svg{width:18px;height:18px}
/* Theme Toggle */
.theme-toggle{position:fixed;top:24px;right:24px;z-index:100;width:48px;height:48px;border-radius:50%;border:2px solid var(--border);background:var(--card);box-shadow:var(--shadow);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s}
.theme-toggle:hover{transform:scale(1.1);box-shadow:var(--shadow-hover)}
.theme-toggle .icon-sun,.theme-toggle .icon-moon{position:absolute;transition:all .3s;font-size:20px}
.theme-toggle .icon-sun{opacity:0;transform:rotate(-90deg) scale(.5)}
.theme-toggle .icon-moon{opacity:1;transform:rotate(0) scale(1)}
[data-theme="dark"] .theme-toggle .icon-sun{opacity:1;transform:rotate(0) scale(1)}
[data-theme="dark"] .theme-toggle .icon-moon{opacity:0;transform:rotate(90deg) scale(.5)}
/* Footer */
.foot{text-align:center;padding:32px 0 0;color:var(--text-sub);font-size:12px}
/* Responsive */
@@ -58,9 +75,34 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
.item{animation:up .6s ease both}
.item:nth-child(1){animation-delay:.05s}.item:nth-child(2){animation-delay:.12s}.item:nth-child(3){animation-delay:.19s}
@keyframes up{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:translateY(0)}}
/* Consult Section */
.consult-section{max-width:680px;margin:64px auto 0;padding:40px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:24px;box-shadow:0 20px 60px rgba(102,126,234,0.3)}
.consult-header{text-align:center;margin-bottom:32px}
.consult-header h2{font-size:32px;font-weight:700;color:#fff;margin-bottom:8px}
.consult-header p{font-size:16px;color:rgba(255,255,255,0.9)}
.consult-form{background:var(--form-bg);padding:32px;border-radius:16px;backdrop-filter:blur(10px);transition:background .3s}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
.form-group{margin-bottom:16px}
.form-group label{display:block;font-size:14px;font-weight:600;color:var(--text);margin-bottom:6px}
.form-group input,.form-group textarea{width:100%;padding:12px 16px;border:2px solid var(--input-border);border-radius:12px;font-size:15px;transition:all .3s;background:var(--input-bg);color:var(--text)}
.form-group input::placeholder,.form-group textarea::placeholder{color:var(--text-sub)}
.form-group input:focus,.form-group textarea:focus{outline:none;border-color:#667eea;background:var(--card);box-shadow:0 0 0 4px rgba(102,126,234,0.1)}
.form-group textarea{resize:vertical;min-height:100px}
.submit-btn{width:100%;padding:16px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:12px;font-size:18px;font-weight:700;cursor:pointer;transition:all .3s;margin-top:8px}
.submit-btn:hover{transform:translateY(-2px);box-shadow:0 8px 25px rgba(102,126,234,0.4)}
.submit-btn:active{transform:translateY(0)}
.consult-success{text-align:center;padding:40px;background:var(--form-bg);border-radius:16px;transition:background .3s}
.success-icon{width:64px;height:64px;background:linear-gradient(135deg,#10b981 0%,#059669 100%);border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 16px;font-size:32px;color:#fff}
.consult-success h3{font-size:24px;font-weight:700;color:var(--text);margin-bottom:8px}
.consult-success p{font-size:16px;color:var(--text-sub)}
@media(max-width:600px){.form-row{grid-template-columns:1fr}.consult-section{padding:24px;margin:48px 16px}}
</style>
</head>
<body>
<button class="theme-toggle" id="themeToggle" aria-label="切换主题">
<span class="icon-sun">☀️</span>
<span class="icon-moon">🌙</span>
</button>
<div class="wrap">
<div class="hero">
<h1>Gotest <span>模板导航</span></h1>
@@ -77,9 +119,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>企业官网</h2><span class="sub">3 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/site1"><div class="item-banner g-enterprise"><div class="glow"></div><div class="pattern"></div><span class="item-tag">科技蓝</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">科技企业 · site1</div><div class="item-desc">现代科技公司风格,蓝色主调</div></div></a>
<a class="item" href="/site2"><div class="item-banner g-enterprise"><div class="glow" style="background:linear-gradient(135deg,#1c1917 0%,#b45309 40%,#fbbf24 100%)"></div><div class="pattern"></div><span class="item-tag">制造金</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">制造企业 · site2</div><div class="item-desc">工业制造风格,深色金调</div></div></a>
<a class="item" href="/site3"><div class="item-banner g-enterprise"><div class="glow" style="background:linear-gradient(135deg,#064e3b 0%,#10b981 40%,#6ee7b7 100%)"></div><div class="pattern"></div><span class="item-tag">咨询绿</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">咨询服务 · site3</div><div class="item-desc">专业咨询风格,绿色清新</div></div></a>
<a class="item" href="/site1" target="_blank"><div class="item-banner g-enterprise"><div class="glow"></div><div class="pattern"></div><span class="item-tag">科技蓝</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">科技企业 · site1</div><div class="item-desc">现代科技公司风格,蓝色主调</div></div></a>
<a class="item" href="/site2" target="_blank"><div class="item-banner g-enterprise"><div class="glow" style="background:linear-gradient(135deg,#1c1917 0%,#b45309 40%,#fbbf24 100%)"></div><div class="pattern"></div><span class="item-tag">制造金</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">制造企业 · site2</div><div class="item-desc">工业制造风格,深色金调</div></div></a>
<a class="item" href="/site3" target="_blank"><div class="item-banner g-enterprise"><div class="glow" style="background:linear-gradient(135deg,#064e3b 0%,#10b981 40%,#6ee7b7 100%)"></div><div class="pattern"></div><span class="item-tag">咨询绿</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">咨询服务 · site3</div><div class="item-desc">专业咨询风格,绿色清新</div></div></a>
</div>
</div>
@@ -87,10 +129,10 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>跨境电商</h2><span class="sub">4 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/shop"><div class="item-banner g-shop"><div class="glow"></div><div class="pattern"></div><span class="item-tag">红色经典</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">经典电商 · shop</div><div class="item-desc">经典电商红,大促风格</div></div></a>
<a class="item" href="/shop2"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#18181b 0%,#3f3f46 40%,#71717a 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">暗黑电商 · shop2</div><div class="item-desc">黑色高端,极简暗色</div></div></a>
<a class="item" href="/shop3"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#f5f5f0 0%,#d6d3d1 40%,#a8a29e 100%)"></div><div class="pattern" style="opacity:.08"></div><span class="item-tag" style="background:rgba(0,0,0,.1);color:#1c1917;border-color:rgba(0,0,0,.1)">北欧极简</span><div class="item-go" style="color:#1c1917">→</div></div><div class="item-body"><div class="item-title">北欧极简 · shop3</div><div class="item-desc">NORDI 风格,自然柔和</div></div></a>
<a class="item" href="/shop4"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#0f172a 0%,#1a3a2a 50%,#2d5a1f 100%)"></div><div class="pattern" style="opacity:.06"></div><span class="item-tag">古树生机</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">古树商城 · shop4</div><div class="item-desc">古树壁纸,光追生命力</div></div></a>
<a class="item" href="/shop" target="_blank"><div class="item-banner g-shop"><div class="glow"></div><div class="pattern"></div><span class="item-tag">红色经典</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">经典电商 · shop</div><div class="item-desc">经典电商红,大促风格</div></div></a>
<a class="item" href="/shop2" target="_blank"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#18181b 0%,#3f3f46 40%,#71717a 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">暗黑电商 · shop2</div><div class="item-desc">黑色高端,极简暗色</div></div></a>
<a class="item" href="/shop3" target="_blank"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#f5f5f0 0%,#d6d3d1 40%,#a8a29e 100%)"></div><div class="pattern" style="opacity:.08"></div><span class="item-tag" style="background:rgba(0,0,0,.1);color:#1c1917;border-color:rgba(0,0,0,.1)">北欧极简</span><div class="item-go" style="color:#1c1917">→</div></div><div class="item-body"><div class="item-title">北欧极简 · shop3</div><div class="item-desc">NORDI 风格,自然柔和</div></div></a>
<a class="item" href="/shop4" target="_blank"><div class="item-banner g-shop"><div class="glow" style="background:linear-gradient(135deg,#0f172a 0%,#1a3a2a 50%,#2d5a1f 100%)"></div><div class="pattern" style="opacity:.06"></div><span class="item-tag">古树生机</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">古树商城 · shop4</div><div class="item-desc">古树壁纸,光追生命力</div></div></a>
</div>
</div>
@@ -98,9 +140,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>外卖平台</h2><span class="sub">3 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/food1"><div class="item-banner g-food"><div class="glow"></div><div class="pattern"></div><span class="item-tag">橙黄活力</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">美味达 · food1</div><div class="item-desc">暖橙食欲风格,活力满满</div></div></a>
<a class="item" href="/food2"><div class="item-banner g-food"><div class="glow" style="background:linear-gradient(135deg,#18181b 0%,#44403c 40%,#78716c 100%)"></div><div class="pattern"></div><span class="item-tag">深色模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">GOURMET · food2</div><div class="item-desc">暗色高端外卖平台</div></div></a>
<a class="item" href="/food3"><div class="item-banner g-food"><div class="glow" style="background:linear-gradient(135deg,#14532d 0%,#22c55e 40%,#86efac 100%)"></div><div class="pattern"></div><span class="item-tag">清新自然</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">绿野鲜送 · food3</div><div class="item-desc">绿色健康,清新自然</div></div></a>
<a class="item" href="/food1" target="_blank"><div class="item-banner g-food"><div class="glow"></div><div class="pattern"></div><span class="item-tag">橙黄活力</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">美味达 · food1</div><div class="item-desc">暖橙食欲风格,活力满满</div></div></a>
<a class="item" href="/food2" target="_blank"><div class="item-banner g-food"><div class="glow" style="background:linear-gradient(135deg,#18181b 0%,#44403c 40%,#78716c 100%)"></div><div class="pattern"></div><span class="item-tag">深色模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">GOURMET · food2</div><div class="item-desc">暗色高端外卖平台</div></div></a>
<a class="item" href="/food3" target="_blank"><div class="item-banner g-food"><div class="glow" style="background:linear-gradient(135deg,#14532d 0%,#22c55e 40%,#86efac 100%)"></div><div class="pattern"></div><span class="item-tag">清新自然</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">绿野鲜送 · food3</div><div class="item-desc">绿色健康,清新自然</div></div></a>
</div>
</div>
@@ -108,9 +150,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>游戏平台</h2><span class="sub">3 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/game1"><div class="item-banner g-game"><div class="glow"></div><div class="pattern"></div><span class="item-tag">赛博朋克</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">NEON ARCADE · game1</div><div class="item-desc">霓虹未来,赛博朋克风格</div></div></a>
<a class="item" href="/game2"><div class="item-banner g-game"><div class="glow" style="background:linear-gradient(135deg,#052e16 0%,#16a34a 40%,#4ade80 100%)"></div><div class="pattern"></div><span class="item-tag">像素复古</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">PIXEL GAMES · game2</div><div class="item-desc">8-bit 像素复古游戏风</div></div></a>
<a class="item" href="/game3"><div class="item-banner g-game"><div class="glow" style="background:linear-gradient(135deg,#083344 0%,#06b6d4 40%,#67e8f9 100%)"></div><div class="pattern"></div><span class="item-tag">云游戏</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">云游平台 · game3</div><div class="item-desc">流线科技,云游戏风格</div></div></a>
<a class="item" href="/game1" target="_blank"><div class="item-banner g-game"><div class="glow"></div><div class="pattern"></div><span class="item-tag">赛博朋克</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">NEON ARCADE · game1</div><div class="item-desc">霓虹未来,赛博朋克风格</div></div></a>
<a class="item" href="/game2" target="_blank"><div class="item-banner g-game"><div class="glow" style="background:linear-gradient(135deg,#052e16 0%,#16a34a 40%,#4ade80 100%)"></div><div class="pattern"></div><span class="item-tag">像素复古</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">PIXEL GAMES · game2</div><div class="item-desc">8-bit 像素复古游戏风</div></div></a>
<a class="item" href="/game3" target="_blank"><div class="item-banner g-game"><div class="glow" style="background:linear-gradient(135deg,#083344 0%,#06b6d4 40%,#67e8f9 100%)"></div><div class="pattern"></div><span class="item-tag">云游戏</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">云游平台 · game3</div><div class="item-desc">流线科技,云游戏风格</div></div></a>
</div>
</div>
@@ -118,9 +160,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>应用商店</h2><span class="sub">3 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/app1"><div class="item-banner g-app"><div class="glow" style="background:linear-gradient(135deg,#f8fafc 0%,#e2e8f0 40%,#cbd5e1 100%)"></div><div class="pattern" style="opacity:.06"></div><span class="item-tag" style="background:rgba(0,0,0,.08);color:#1e293b;border-color:rgba(0,0,0,.08)">极简白</span><div class="item-go" style="color:#1e293b">→</div></div><div class="item-body"><div class="item-title">极简白 · app1</div><div class="item-desc">Apple 风格,简洁清爽</div></div></a>
<a class="item" href="/app2"><div class="item-banner g-app"><div class="glow" style="background:linear-gradient(135deg,#052e16 0%,#10b981 40%,#34d399 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">暗黑应用 · app2</div><div class="item-desc">霓虹绿暗色,科技感十足</div></div></a>
<a class="item" href="/app3"><div class="item-banner g-app"><div class="glow"></div><div class="pattern"></div><span class="item-tag">清新蓝</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">清新蓝 · app3</div><div class="item-desc">明亮配色,活泼现代</div></div></a>
<a class="item" href="/app1" target="_blank"><div class="item-banner g-app"><div class="glow" style="background:linear-gradient(135deg,#f8fafc 0%,#e2e8f0 40%,#cbd5e1 100%)"></div><div class="pattern" style="opacity:.06"></div><span class="item-tag" style="background:rgba(0,0,0,.08);color:#1e293b;border-color:rgba(0,0,0,.08)">极简白</span><div class="item-go" style="color:#1e293b">→</div></div><div class="item-body"><div class="item-title">极简白 · app1</div><div class="item-desc">Apple 风格,简洁清爽</div></div></a>
<a class="item" href="/app2" target="_blank"><div class="item-banner g-app"><div class="glow" style="background:linear-gradient(135deg,#052e16 0%,#10b981 40%,#34d399 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑模式</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">暗黑应用 · app2</div><div class="item-desc">霓虹绿暗色,科技感十足</div></div></a>
<a class="item" href="/app3" target="_blank"><div class="item-banner g-app"><div class="glow"></div><div class="pattern"></div><span class="item-tag">清新蓝</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">清新蓝 · app3</div><div class="item-desc">明亮配色,活泼现代</div></div></a>
</div>
</div>
@@ -128,9 +170,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
<div class="sec">
<div class="sec-head"><h2>音乐平台</h2><span class="sub">3 套风格</span><div class="sec-line"></div></div>
<div class="grid">
<a class="item" href="/music1"><div class="item-banner g-music"><div class="glow" style="background:linear-gradient(135deg,#1e1b4b 0%,#4f46e5 40%,#818cf8 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑播放器</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">云音 Music · music1</div><div class="item-desc">暗夜沉浸式音乐播放器</div></div></a>
<a class="item" href="/music2"><div class="item-banner g-music"><div class="glow" style="background:linear-gradient(135deg,#451a03 0%,#92400e 40%,#d97706 100%)"></div><div class="pattern"></div><span class="item-tag">黑胶复古</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">Vinyl · music2</div><div class="item-desc">黑胶唱片复古风格</div></div></a>
<a class="item" href="/music3"><div class="item-banner g-music"><div class="glow"></div><div class="pattern"></div><span class="item-tag">渐变流媒体</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">流媒体 · music3</div><div class="item-desc">紫粉渐变,现代流媒体</div></div></a>
<a class="item" href="/music1" target="_blank"><div class="item-banner g-music"><div class="glow" style="background:linear-gradient(135deg,#1e1b4b 0%,#4f46e5 40%,#818cf8 100%)"></div><div class="pattern"></div><span class="item-tag">暗黑播放器</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">云音 Music · music1</div><div class="item-desc">暗夜沉浸式音乐播放器</div></div></a>
<a class="item" href="/music2" target="_blank"><div class="item-banner g-music"><div class="glow" style="background:linear-gradient(135deg,#451a03 0%,#92400e 40%,#d97706 100%)"></div><div class="pattern"></div><span class="item-tag">黑胶复古</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">Vinyl · music2</div><div class="item-desc">黑胶唱片复古风格</div></div></a>
<a class="item" href="/music3" target="_blank"><div class="item-banner g-music"><div class="glow"></div><div class="pattern"></div><span class="item-tag">渐变流媒体</span><div class="item-go">→</div></div><div class="item-body"><div class="item-title">流媒体 · music3</div><div class="item-desc">紫粉渐变,现代流媒体</div></div></a>
</div>
</div>
@@ -142,7 +184,109 @@ body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Segoe UI',Ro
</a>
</div>
<!-- 客户咨询表单 -->
<div class="consult-section">
<div class="consult-header">
<h2>需要定制网站?</h2>
<p>只需几百块,即可拥有同款精美站点!留下您的信息,我们尽快联系您</p>
</div>
<form class="consult-form" id="consultForm">
<div class="form-row">
<div class="form-group">
<label for="name">姓名 *</label>
<input type="text" id="name" name="name" placeholder="请输入您的姓名" required>
</div>
<div class="form-group">
<label for="phone">联系电话 *</label>
<input type="tel" id="phone" name="phone" placeholder="请输入您的手机号" required>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="company">公司名称</label>
<input type="text" id="company" name="company" placeholder="请输入公司名称(选填)">
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" placeholder="请输入邮箱(选填)">
</div>
</div>
<div class="form-group">
<label for="needs">需求描述 *</label>
<textarea id="needs" name="needs" rows="4" placeholder="请描述您的需求,比如:想要一个企业官网,类似科技风格..." required></textarea>
</div>
<button type="submit" class="submit-btn" id="submitBtn">
<span class="btn-text">立即咨询</span>
<span class="btn-loading" style="display:none">提交中...</span>
</button>
</form>
<div class="consult-success" id="consultSuccess" style="display:none">
<div class="success-icon">✓</div>
<h3>提交成功!</h3>
<p>我们会尽快联系您,请保持电话畅通</p>
</div>
</div>
<div class="foot">Gotest · 多行业网站模板集合 · 点击卡片进入对应模板</div>
</div>
<script>
// Theme toggle
(function(){
var toggle = document.getElementById('themeToggle');
toggle.addEventListener('click', function(){
var current = document.documentElement.getAttribute('data-theme');
var next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
});
})();
document.getElementById('consultForm').addEventListener('submit', async function(e) {
e.preventDefault();
const submitBtn = document.getElementById('submitBtn');
const btnText = submitBtn.querySelector('.btn-text');
const btnLoading = submitBtn.querySelector('.btn-loading');
btnText.style.display = 'none';
btnLoading.style.display = 'inline';
submitBtn.disabled = true;
const formData = {
name: document.getElementById('name').value,
phone: document.getElementById('phone').value,
company: document.getElementById('company').value,
email: document.getElementById('email').value,
needs: document.getElementById('needs').value
};
try {
const response = await fetch('/api/v1/customer/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
const result = await response.json();
if (result.code === 0) {
document.getElementById('consultForm').style.display = 'none';
document.getElementById('consultSuccess').style.display = 'block';
} else {
alert(result.message || '提交失败,请稍后重试');
btnText.style.display = 'inline';
btnLoading.style.display = 'none';
submitBtn.disabled = false;
}
} catch (error) {
console.error('提交失败:', error);
alert('网络错误,请稍后重试');
btnText.style.display = 'inline';
btnLoading.style.display = 'none';
submitBtn.disabled = false;
}
});
</script>
</body>
</html>