313 lines
14 KiB
HTML
313 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Team-API - 系统初始化</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
extend: {
|
|
fontFamily: {
|
|
sans: ['DM Sans', 'system-ui', 'sans-serif'],
|
|
mono: ['JetBrains Mono', 'monospace'],
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
body { font-family: 'DM Sans', system-ui, sans-serif; }
|
|
|
|
.setup-card {
|
|
box-shadow:
|
|
0 0 0 1px rgba(0, 0, 0, 0.03),
|
|
0 2px 4px rgba(0, 0, 0, 0.03),
|
|
0 12px 24px rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.input-field {
|
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
}
|
|
.input-field:focus {
|
|
border-color: #2563eb;
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
}
|
|
|
|
.btn-primary {
|
|
background-color: #2563eb;
|
|
transition: background-color 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
|
|
}
|
|
.btn-primary:hover:not(:disabled) {
|
|
background-color: #1d4ed8;
|
|
box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
|
|
}
|
|
.btn-primary:active:not(:disabled) {
|
|
transform: translateY(0.5px);
|
|
}
|
|
.btn-primary:disabled {
|
|
opacity: 0.65;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.currency-option.selected {
|
|
border-color: #2563eb;
|
|
background-color: rgba(37, 99, 235, 0.04);
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
|
|
}
|
|
|
|
@keyframes fadeUp {
|
|
from { opacity: 0; transform: translateY(12px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.animate-fade-up {
|
|
animation: fadeUp 0.4s ease-out both;
|
|
}
|
|
.delay-1 { animation-delay: 0.05s; }
|
|
.delay-2 { animation-delay: 0.1s; }
|
|
.delay-3 { animation-delay: 0.15s; }
|
|
.delay-4 { animation-delay: 0.2s; }
|
|
.delay-5 { animation-delay: 0.25s; }
|
|
.delay-6 { animation-delay: 0.3s; }
|
|
.delay-7 { animation-delay: 0.35s; }
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
.spinner {
|
|
display: inline-block;
|
|
width: 16px; height: 16px;
|
|
border: 2px solid rgba(255,255,255,0.3);
|
|
border-top-color: #fff;
|
|
border-radius: 50%;
|
|
animation: spin 0.6s linear infinite;
|
|
vertical-align: middle;
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.error-box {
|
|
transition: opacity 0.2s ease, max-height 0.2s ease;
|
|
max-height: 0;
|
|
opacity: 0;
|
|
overflow: hidden;
|
|
}
|
|
.error-box.visible {
|
|
max-height: 80px;
|
|
opacity: 1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="min-h-screen flex items-center justify-center p-4" style="background: linear-gradient(160deg, #f0f4f8 0%, #e8edf5 50%, #f5f3ff 100%);">
|
|
|
|
<div class="w-full max-w-md">
|
|
<div class="setup-card bg-white rounded-2xl p-8 sm:p-10">
|
|
|
|
<!-- Branding -->
|
|
<div class="text-center mb-8 animate-fade-up">
|
|
<div class="inline-flex items-center justify-center w-12 h-12 rounded-xl mb-4" style="background: linear-gradient(135deg, #2563eb, #1d4ed8);">
|
|
<svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z"/>
|
|
</svg>
|
|
</div>
|
|
<h1 class="text-2xl font-semibold text-gray-900 tracking-tight">Team-API</h1>
|
|
<p class="text-sm text-gray-500 mt-1.5">系统初始化设置</p>
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<p class="text-sm text-gray-400 mb-7 animate-fade-up delay-1">
|
|
首次使用,请创建管理员账号以开始配置系统
|
|
</p>
|
|
|
|
<!-- Form -->
|
|
<form id="setupForm" class="space-y-4.5" autocomplete="off">
|
|
<div class="space-y-4">
|
|
<!-- Username -->
|
|
<div class="animate-fade-up delay-2">
|
|
<label for="username" class="block text-sm font-medium text-gray-700 mb-1.5">用户名</label>
|
|
<input
|
|
type="text" id="username" name="username" required autofocus
|
|
class="input-field w-full px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-900 placeholder-gray-400 outline-none"
|
|
placeholder="3-20位,字母/数字/下划线" autocomplete="off" spellcheck="false">
|
|
</div>
|
|
|
|
<!-- Display Name -->
|
|
<div class="animate-fade-up delay-3">
|
|
<label for="displayName" class="block text-sm font-medium text-gray-700 mb-1.5">
|
|
显示名称 <span class="text-gray-400 font-normal">(可选)</span>
|
|
</label>
|
|
<input
|
|
type="text" id="displayName" name="displayName"
|
|
class="input-field w-full px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-900 placeholder-gray-400 outline-none"
|
|
placeholder="管理员显示名称" autocomplete="off">
|
|
</div>
|
|
|
|
<!-- Password -->
|
|
<div class="animate-fade-up delay-4">
|
|
<label for="password" class="block text-sm font-medium text-gray-700 mb-1.5">密码</label>
|
|
<input
|
|
type="password" id="password" name="password" required
|
|
class="input-field w-full px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-900 placeholder-gray-400 outline-none font-mono"
|
|
placeholder="至少8位,含字母和数字" autocomplete="new-password">
|
|
</div>
|
|
|
|
<!-- Confirm Password -->
|
|
<div class="animate-fade-up delay-5">
|
|
<label for="confirmPassword" class="block text-sm font-medium text-gray-700 mb-1.5">确认密码</label>
|
|
<input
|
|
type="password" id="confirmPassword" name="confirmPassword" required
|
|
class="input-field w-full px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-900 placeholder-gray-400 outline-none font-mono"
|
|
placeholder="再次输入密码" autocomplete="new-password">
|
|
</div>
|
|
|
|
<!-- Base Currency -->
|
|
<div class="animate-fade-up delay-6">
|
|
<label class="block text-sm font-medium text-gray-700 mb-1.5">
|
|
本位币
|
|
<span class="text-amber-600 font-normal text-xs ml-1">初始化后不可更改</span>
|
|
</label>
|
|
<div class="grid grid-cols-2 gap-2.5" id="currencyGroup">
|
|
<label class="currency-option cursor-pointer flex items-start gap-2.5 px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg transition-colors" data-value="USD">
|
|
<input type="radio" name="currency" value="USD" checked class="mt-0.5 accent-[#2563eb]">
|
|
<span>
|
|
<span class="block text-sm font-medium text-gray-900">USD(美元)</span>
|
|
<span class="block text-xs text-gray-400 mt-0.5">与上游模型报价对齐</span>
|
|
</span>
|
|
</label>
|
|
<label class="currency-option cursor-pointer flex items-start gap-2.5 px-3.5 py-2.5 bg-gray-50 border border-gray-200 rounded-lg transition-colors" data-value="CNY">
|
|
<input type="radio" name="currency" value="CNY" class="mt-0.5 accent-[#2563eb]">
|
|
<span>
|
|
<span class="block text-sm font-medium text-gray-900">CNY(人民币)</span>
|
|
<span class="block text-xs text-gray-400 mt-0.5">面向国内运营</span>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<p class="text-xs text-gray-400 mt-1.5">决定系统内部记账与全站显示货币,模型定价按本位币配置</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error -->
|
|
<div id="errorArea" class="error-box">
|
|
<div class="flex items-start gap-2 text-sm text-red-700 bg-red-50 border border-red-100 px-3.5 py-2.5 rounded-lg">
|
|
<svg class="w-4 h-4 mt-0.5 flex-shrink-0 text-red-500" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"/>
|
|
</svg>
|
|
<span id="errorText"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit -->
|
|
<div class="pt-1.5 animate-fade-up delay-7">
|
|
<button
|
|
type="submit" id="submitBtn"
|
|
class="btn-primary w-full text-white py-2.5 rounded-lg text-sm font-medium">
|
|
初始化系统
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<p class="text-center text-xs text-gray-400 mt-6">
|
|
初始化完成后将自动跳转至登录页面
|
|
</p>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
var form = document.getElementById('setupForm');
|
|
var errorArea = document.getElementById('errorArea');
|
|
var errorText = document.getElementById('errorText');
|
|
var submitBtn = document.getElementById('submitBtn');
|
|
|
|
function showError(msg) {
|
|
errorText.textContent = msg;
|
|
errorArea.classList.add('visible');
|
|
}
|
|
|
|
function hideError() {
|
|
errorArea.classList.remove('visible');
|
|
}
|
|
|
|
function setLoading(loading) {
|
|
submitBtn.disabled = loading;
|
|
if (loading) {
|
|
submitBtn.innerHTML = '<span class="spinner"></span>正在初始化...';
|
|
} else {
|
|
submitBtn.textContent = '初始化系统';
|
|
}
|
|
}
|
|
|
|
// 本位币选择卡片高亮联动
|
|
var currencyOptions = document.querySelectorAll('.currency-option');
|
|
function syncCurrencyHighlight() {
|
|
var selected = document.querySelector('input[name="currency"]:checked');
|
|
currencyOptions.forEach(function(opt) {
|
|
opt.classList.toggle('selected', opt.querySelector('input').value === selected.value);
|
|
});
|
|
}
|
|
currencyOptions.forEach(function(opt) {
|
|
opt.querySelector('input').addEventListener('change', syncCurrencyHighlight);
|
|
});
|
|
syncCurrencyHighlight();
|
|
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
hideError();
|
|
|
|
var username = document.getElementById('username').value.trim();
|
|
var displayName = document.getElementById('displayName').value.trim();
|
|
var password = document.getElementById('password').value;
|
|
var confirmPassword = document.getElementById('confirmPassword').value;
|
|
var currency = document.querySelector('input[name="currency"]:checked').value;
|
|
|
|
if (!username) {
|
|
showError('请输入用户名');
|
|
document.getElementById('username').focus();
|
|
return;
|
|
}
|
|
if (!password) {
|
|
showError('请输入密码');
|
|
document.getElementById('password').focus();
|
|
return;
|
|
}
|
|
if (password !== confirmPassword) {
|
|
showError('两次输入的密码不一致');
|
|
document.getElementById('confirmPassword').focus();
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
|
|
fetch('/api/setup/initialize', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
username: username,
|
|
displayName: displayName,
|
|
password: password,
|
|
confirmPassword: confirmPassword,
|
|
currency: currency
|
|
})
|
|
})
|
|
.then(function(res) { return res.json(); })
|
|
.then(function(data) {
|
|
if (data.code === 0) {
|
|
window.location.href = '/admin/#/admin/login';
|
|
} else {
|
|
showError(data.message || '初始化失败,请重试');
|
|
setLoading(false);
|
|
}
|
|
})
|
|
.catch(function() {
|
|
showError('网络错误,请检查连接后重试');
|
|
setLoading(false);
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|