diff --git a/internal/server/server.go b/internal/server/server.go
index 44b11f1..182c26e 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -849,46 +849,207 @@ var loginTemplate = template.Must(template.New("login").Parse(`
+
湛卢代理登录
-
+
+
Zhanlu Proxy
湛卢代理登录
输入手机号获取验证码,按插件默认的移动云登录接口换取凭据和模型 API Key。服务会保存凭据,后续 OpenAI 兼容接口自动使用。
- 保存位置:
{{.CredentialsPath}}
+
+ 凭据保存位置
+ {{.CredentialsPath}}
+
-
+
{{if not .AdminMode}}
管理登录
请输入服务环境变量 ZHANLU_LOGIN_PASSWORD 配置的管理密码。
- 需要登录后才能管理湛卢凭据。
+ 需要登录后才能管理湛卢凭据。
{{else}}
手机号验证码登录
手机号和一次性 secret 会按插件逻辑用 RSA 加密后提交到移动云公网接口。
@@ -897,13 +1058,13 @@ var loginTemplate = template.Must(template.New("login").Parse(`
-
+
- 正在检查登录状态...
- 凭据保存到 JSON;验证码本身不会保存。{{if .PasswordEnabled}} {{end}}
+ 正在检查登录状态...
+ 凭据保存到 JSON;验证码本身不会保存。{{if .PasswordEnabled}} {{end}}
{{end}}
@@ -917,8 +1078,9 @@ var loginTemplate = template.Must(template.New("login").Parse(`
let countdown = 0;
let countdownTimer = null;
- function setStatus(text) {
+ function setStatus(text, state) {
statusEl.textContent = text;
+ statusEl.dataset.state = state || '';
}
function startCountdown() {
@@ -942,10 +1104,10 @@ var loginTemplate = template.Must(template.New("login").Parse(`
event.preventDefault();
const password = passwordForm.password.value;
if (!password) {
- setStatus('请输入登录密码');
+ setStatus('请输入登录密码', 'err');
return;
}
- setStatus('正在登录...');
+ setStatus('正在登录...', 'busy');
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -953,7 +1115,7 @@ var loginTemplate = template.Must(template.New("login").Parse(`
});
const data = await res.json();
if (!res.ok || !data.ok) {
- setStatus(data.error || '登录失败');
+ setStatus(data.error || '登录失败', 'err');
return;
}
window.location.href = '/admin/login';
@@ -970,17 +1132,18 @@ var loginTemplate = template.Must(template.New("login").Parse(`
if (form) {
fetch('/api/credentials').then(r => r.json()).then(data => {
statusEl.textContent = data.configured ? ('已登录:' + (data.access_key || '')) : '当前未登录';
+ statusEl.dataset.state = data.configured ? 'ok' : '';
});
}
codeButton && codeButton.addEventListener('click', async () => {
const telephone = form.telephone.value.trim();
if (!/^1[3-9]\d{9}$/.test(telephone)) {
- setStatus('请输入有效的 11 位手机号');
+ setStatus('请输入有效的 11 位手机号', 'err');
return;
}
codeButton.disabled = true;
- setStatus('正在发送验证码...');
+ setStatus('正在发送验证码...', 'busy');
const res = await fetch('/api/auth/code', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -989,11 +1152,11 @@ var loginTemplate = template.Must(template.New("login").Parse(`
const data = await res.json();
if (!res.ok || !data.ok) {
codeButton.disabled = false;
- setStatus(data.error || '验证码发送失败');
+ setStatus(data.error || '验证码发送失败', 'err');
return;
}
secret = data.secret;
- setStatus('验证码已发送');
+ setStatus('验证码已发送', 'ok');
startCountdown();
});
@@ -1002,10 +1165,10 @@ var loginTemplate = template.Must(template.New("login").Parse(`
const telephone = form.telephone.value.trim();
const code = form.code.value.trim();
if (!secret) {
- setStatus('请先获取验证码');
+ setStatus('请先获取验证码', 'err');
return;
}
- setStatus('正在登录并保存凭据...');
+ setStatus('正在登录并保存凭据...', 'busy');
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -1013,10 +1176,10 @@ var loginTemplate = template.Must(template.New("login").Parse(`
});
const data = await res.json();
if (!res.ok || !data.ok) {
- setStatus(data.error || '登录失败');
+ setStatus(data.error || '登录失败', 'err');
return;
}
- setStatus('登录成功,已保存凭据:' + (data.access_key || '') + ';JSON:' + (data.path || ''));
+ setStatus('登录成功,已保存凭据:' + (data.access_key || '') + ';JSON:' + (data.path || ''), 'ok');
});
@@ -1024,5 +1187,34 @@ var loginTemplate = template.Must(template.New("login").Parse(`
var loginResultTemplate = template.Must(template.New("login-result").Parse(`
-湛卢登录结果
-{{if .Success}}登录成功
{{else}}登录失败
{{end}}{{.Message}}
返回登录页`))
+
+湛卢登录结果
+
+
+{{if .Success}}
{{else}}
{{end}}
+
+{{if .Success}}登录成功
{{else}}登录失败
{{end}}
+{{.Message}}
+返回登录页
+