Files
yunzerwebsiteallinone/go/views/auth/login.tpl
T
2026-09-20 00:19:08 +08:00

215 lines
8.3 KiB
Smarty
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="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>统一认证中心 - 登录</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh; display: flex; align-items: center; justify-content: center;
}
.card {
background: #fff; border-radius: 12px; box-shadow: 0 20px 60px rgba(0,0,0,.2);
width: 420px; max-width: 92vw; padding: 40px 36px;
}
.logo { text-align: center; margin-bottom: 28px; }
.logo h1 { font-size: 22px; color: #1a1a2e; font-weight: 600; }
.logo p { font-size: 13px; color: #8a8fa3; margin-top: 6px; }
.field { margin-bottom: 18px; }
.field label { display: block; font-size: 13px; color: #5a6072; margin-bottom: 7px; }
.field input {
width: 100%; height: 44px; padding: 0 14px; font-size: 14px;
border: 1px solid #dcdfe8; border-radius: 8px; outline: none; transition: border-color .2s;
}
.field input:focus { border-color: #667eea; }
.btn {
width: 100%; height: 44px; border: none; border-radius: 8px; cursor: pointer;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff; font-size: 15px; font-weight: 500; transition: opacity .2s;
}
.btn:hover { opacity: .9; }
.btn:disabled { opacity: .6; cursor: not-allowed; }
.error {
background: #fff2f0; border: 1px solid #ffccc7; color: #cf1322;
padding: 10px 12px; border-radius: 6px; font-size: 13px; margin-bottom: 16px; display: none;
}
.tenant-list { list-style: none; }
.tenant-item {
display: flex; align-items: center; justify-content: space-between;
padding: 14px 16px; border: 1px solid #e4e7ee; border-radius: 8px;
margin-bottom: 12px; cursor: pointer; transition: all .2s;
}
.tenant-item:hover { border-color: #667eea; background: #f7f8ff; }
.tenant-name { font-size: 15px; color: #1a1a2e; font-weight: 500; }
.tenant-meta { font-size: 12px; color: #8a8fa3; margin-top: 3px; }
.tenant-arrow { color: #c0c4d0; font-size: 18px; }
.tip { text-align: center; font-size: 12px; color: #8a8fa3; margin-top: 20px; }
.divider {
position: relative; text-align: center; margin: 24px 0 14px;
font-size: 12px; color: #a0a5b5;
}
.divider::before {
content: ''; position: absolute; top: 50%; left: 0; right: 0;
height: 1px; background: #e4e7ee;
}
.divider span { position: relative; background: #fff; padding: 0 12px; }
.third-list { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.third-btn {
padding: 8px 16px; border: 1px solid #dcdfe8; border-radius: 20px;
background: #fff; font-size: 13px; color: #5a6072; cursor: pointer;
}
.third-btn:hover { border-color: #667eea; color: #667eea; }
.back { text-align: center; margin-top: 14px; }
.back a { font-size: 13px; color: #667eea; text-decoration: none; cursor: pointer; }
</style>
</head>
<body>
<div class="card">
<div class="logo">
<h1>云泽统一认证中心</h1>
<p>{{if eq .Step "tenant"}}请选择要进入的企业{{else}}登录后即可使用全部应用{{end}}</p>
</div>
<div class="error" id="error"></div>
{{if eq .Step "tenant"}}
<!-- 企业选择步骤 -->
<ul class="tenant-list">
{{range .Tenants}}
<li class="tenant-item" onclick="chooseTenant({{.Tid}})">
<div>
<div class="tenant-name">{{.TenantName}}</div>
<div class="tenant-meta">{{if .Name}}{{.Name}} · {{end}}企业ID {{.Tid}}</div>
</div>
<span class="tenant-arrow">›</span>
</li>
{{end}}
</ul>
<div class="back"><a onclick="logout()">切换账号</a></div>
{{else}}
<!-- 账号密码登录 -->
<form id="loginForm" onsubmit="return submitLogin(event)">
<div class="field">
<label>账号</label>
<input id="account" type="text" placeholder="手机号 / 邮箱 / 企业账号" autocomplete="username" autofocus>
</div>
<div class="field">
<label>密码</label>
<input id="password" type="password" placeholder="请输入密码" autocomplete="current-password">
</div>
<button class="btn" id="submitBtn" type="submit">登 录</button>
</form>
<!-- 第三方登录 -->
<div class="third-area" id="thirdArea" style="display:none">
<div class="divider"><span>其他登录方式</span></div>
<div class="third-list" id="thirdList"></div>
</div>
{{end}}
<div class="tip">统一身份认证 · 一次登录,全平台通行</div>
</div>
<script>
var CLIENT_ID = "{{.ClientID}}";
var REDIRECT = "{{.Redirect}}";
function showError(msg) {
var el = document.getElementById('error');
el.textContent = msg;
el.style.display = 'block';
}
// 加载已开通的第三方登录方式
function loadThirdProviders() {
fetch('/auth/third/list')
.then(function (r) { return r.json(); })
.then(function (res) {
var list = (res && res.data) || [];
var enabled = list.filter(function (i) { return i.enabled; });
if (!enabled.length) return;
var box = document.getElementById('thirdList');
enabled.forEach(function (item) {
var btn = document.createElement('button');
btn.className = 'third-btn';
btn.textContent = item.name;
btn.onclick = function () { startThird(item.provider); };
box.appendChild(btn);
});
document.getElementById('thirdArea').style.display = 'block';
})
.catch(function () { /* 静默失败,不影响账号密码登录 */ });
}
function startThird(provider) {
window.location.href = '/auth/third/' + encodeURIComponent(provider) +
'/authorize?redirect=' + encodeURIComponent(REDIRECT);
}
loadThirdProviders();
function submitLogin(e) {
e.preventDefault();
var account = document.getElementById('account').value.trim();
var password = document.getElementById('password').value;
if (!account) { showError('请输入账号'); return false; }
if (!password) { showError('请输入密码'); return false; }
var btn = document.getElementById('submitBtn');
btn.disabled = true;
btn.textContent = '登录中...';
fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ account: account, password: password, client_id: CLIENT_ID, redirect: REDIRECT })
})
.then(function (r) { return r.json(); })
.then(function (res) {
if (res.code !== 200) {
showError(res.msg || '登录失败');
btn.disabled = false;
btn.textContent = '登 录';
return;
}
if (res.need_choose_tenant) {
window.location.href = '/auth/login?step=tenant&client_id=' + encodeURIComponent(CLIENT_ID) + '&redirect=' + encodeURIComponent(REDIRECT);
return;
}
if (res.redirect) { window.location.href = res.redirect; return; }
window.location.href = '/auth/login';
})
.catch(function () {
showError('网络异常,请稍后重试');
btn.disabled = false;
btn.textContent = '登 录';
});
return false;
}
function chooseTenant(tid) {
fetch('/auth/switch-tenant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tid: tid, client_id: CLIENT_ID, redirect: REDIRECT })
})
.then(function (r) { return r.json(); })
.then(function (res) {
if (res.code !== 200) { showError(res.msg || '切换失败'); return; }
if (res.redirect) { window.location.href = res.redirect; return; }
window.location.href = '/auth/login';
});
}
function logout() {
fetch('/auth/logout', { method: 'POST' }).then(function () {
window.location.href = '/auth/login?client_id=' + encodeURIComponent(CLIENT_ID) + '&redirect=' + encodeURIComponent(REDIRECT);
});
}
</script>
</body>
</html>