更新日报相关功能
This commit is contained in:
1 parent
51fd90fc51
commit
68cdaf38fa
23 files changed
+2313
-1056
No files matched your search
+426
-203
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title>统一认证中心 - 登录</title>
|
||||
<title>{{.LoginTitle}} - 统一认证中心</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary: #3973ff;
|
||||
@@ -14,7 +14,7 @@
|
||||
--text-sub: #5b6780;
|
||||
--muted: #8a94ad;
|
||||
--border: #e3e9f5;
|
||||
--radius: 12px;
|
||||
--radius: 10px;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
@@ -23,124 +23,189 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
color: var(--text);
|
||||
background: linear-gradient(120deg, #eef4ff 0%, #f7fbff 55%, #eaf3ff 100%);
|
||||
background: #f3f6fc;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32px 20px;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.glow {
|
||||
position: fixed;
|
||||
border-radius: 50%;
|
||||
filter: blur(60px);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
.glow-1 { width: 380px; height: 380px; top: -120px; left: -100px; background: rgba(82, 168, 255, 0.28); }
|
||||
.glow-2 { width: 320px; height: 320px; bottom: -120px; right: -80px; background: rgba(57, 115, 255, 0.20); }
|
||||
|
||||
.auth-card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 940px;
|
||||
min-height: 560px;
|
||||
background: #fff;
|
||||
border-radius: 22px;
|
||||
box-shadow: 0 18px 50px 0 rgba(37, 96, 169, 0.14), 0 2px 6px 0 rgba(31, 43, 72, 0.04);
|
||||
overflow: hidden;
|
||||
}
|
||||
.login-page { display: flex; min-height: 100vh; width: 100%; }
|
||||
|
||||
/* ---------- 左侧品牌区 ---------- */
|
||||
.auth-side {
|
||||
width: 340px;
|
||||
flex: 0 0 340px;
|
||||
padding: 44px 34px 28px;
|
||||
background: linear-gradient(160deg, #1b3b8f 0%, #2f6fe4 52%, #52a8ff 100%);
|
||||
color: #fff;
|
||||
.brand-panel {
|
||||
position: relative;
|
||||
flex: 1 1 58%;
|
||||
min-height: 100vh;
|
||||
padding: 64px 72px 52px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(150deg, #1b3b8f 0%, #2f6fe4 52%, #52a8ff 100%);
|
||||
color: #fff;
|
||||
}
|
||||
.auth-side::before {
|
||||
.brand-panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 260px; height: 260px;
|
||||
top: -90px; right: -110px;
|
||||
width: 420px; height: 420px;
|
||||
top: -150px; right: -160px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.10);
|
||||
}
|
||||
.auth-side::after {
|
||||
.brand-panel::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 190px; height: 190px;
|
||||
bottom: -70px; left: -60px;
|
||||
width: 300px; height: 300px;
|
||||
bottom: -120px; left: -100px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
/* 配置了背景图:浅色底 + 深色文字,叠一层白色蒙版保证可读性 */
|
||||
.brand-panel.has-bg { background: #eaf1fb; color: var(--text); }
|
||||
.brand-panel.has-bg::before,
|
||||
.brand-panel.has-bg::after { display: none; }
|
||||
.brand-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.brand-veil {
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(100deg, rgba(255, 255, 255, 0.86) 0%, rgba(255, 255, 255, 0.46) 52%, rgba(255, 255, 255, 0.10) 100%);
|
||||
}
|
||||
|
||||
.brand { display: flex; align-items: center; gap: 12px; position: relative; z-index: 1; }
|
||||
.brand-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
max-width: 580px;
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 12px; margin-bottom: 54px; }
|
||||
.brand-logo {
|
||||
width: 40px; height: 40px;
|
||||
border-radius: 11px;
|
||||
width: 44px; height: 44px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border: 1px solid rgba(255, 255, 255, 0.30);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.brand-logo svg { width: 22px; height: 22px; }
|
||||
.brand-name { font-size: 16px; font-weight: 600; letter-spacing: .5px; }
|
||||
.brand-logo svg { width: 24px; height: 24px; }
|
||||
.brand-name { font-size: 19px; font-weight: 600; letter-spacing: .5px; }
|
||||
.brand-img { height: 44px; max-width: 240px; object-fit: contain; display: block; }
|
||||
|
||||
.side-title {
|
||||
margin-top: 44px;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
line-height: 1.45;
|
||||
position: relative; z-index: 1;
|
||||
.brand-title {
|
||||
font-size: clamp(34px, 3.6vw, 52px);
|
||||
font-weight: 700;
|
||||
line-height: 1.28;
|
||||
letter-spacing: 1px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.side-desc {
|
||||
margin-top: 12px;
|
||||
font-size: 13.5px;
|
||||
.brand-sub {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
line-height: 1.9;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
position: relative; z-index: 1;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
max-width: 520px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.brand-panel.has-bg .brand-sub { color: var(--text-sub); }
|
||||
.brand-panel.has-bg .brand-name { color: var(--text); }
|
||||
.brand-panel.has-bg .brand-logo {
|
||||
background: rgba(57, 115, 255, 0.12);
|
||||
border-color: rgba(57, 115, 255, 0.18);
|
||||
}
|
||||
.brand-panel.has-bg .brand-logo svg { stroke: var(--primary); }
|
||||
|
||||
.side-illus { margin: auto 0; padding: 22px 0; position: relative; z-index: 1; }
|
||||
.side-illus svg { width: 100%; height: auto; display: block; }
|
||||
|
||||
.side-foot {
|
||||
position: relative; z-index: 1;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.16);
|
||||
.brand-foot {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 72px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.side-foot svg { width: 13px; height: 13px; }
|
||||
.brand-panel.has-bg .brand-foot { color: var(--muted); }
|
||||
.brand-foot svg { width: 13px; height: 13px; flex: 0 0 auto; }
|
||||
|
||||
/* ---------- 右侧表单区 ---------- */
|
||||
.auth-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 52px 56px 40px;
|
||||
.form-panel {
|
||||
position: relative;
|
||||
flex: 0 0 42%;
|
||||
min-width: 460px;
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 64px 56px 88px;
|
||||
}
|
||||
.form-inner { width: 100%; max-width: 380px; }
|
||||
|
||||
.panel-head { margin-bottom: 30px; }
|
||||
.panel-title { font-size: 30px; font-weight: 700; letter-spacing: .5px; }
|
||||
.panel-sub { margin-top: 10px; font-size: 13.5px; color: var(--text-sub); line-height: 1.7; }
|
||||
|
||||
/* ---------- 登录方式 tab ---------- */
|
||||
.login-tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin: 0 0 24px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.login-tab {
|
||||
position: relative;
|
||||
flex: 1 1 0;
|
||||
padding: 11px 4px 13px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--text-sub);
|
||||
cursor: pointer;
|
||||
transition: color .2s;
|
||||
}
|
||||
.login-tab:hover { color: var(--primary); }
|
||||
.login-tab.active { color: var(--primary); font-weight: 600; }
|
||||
.login-tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 12px; right: 12px; bottom: -1px;
|
||||
height: 2px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(90deg, var(--primary) 0%, var(--primary-light) 100%);
|
||||
}
|
||||
.login-panel { display: none; }
|
||||
.login-panel.active { display: block; animation: panelIn .24s ease both; }
|
||||
@keyframes panelIn {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
|
||||
.panel-head { margin-bottom: 28px; }
|
||||
.panel-title { font-size: 27px; font-weight: 600; letter-spacing: .5px; }
|
||||
.panel-sub { margin-top: 9px; font-size: 13.5px; color: var(--text-sub); }
|
||||
/* 小屏时左侧品牌区隐藏,在表单上方展示紧凑品牌头 */
|
||||
.mobile-brand { display: none; align-items: center; gap: 12px; margin-bottom: 28px; }
|
||||
.mobile-brand .brand-img { height: 36px; max-width: 180px; }
|
||||
.mobile-brand .brand-logo {
|
||||
width: 40px; height: 40px;
|
||||
background: rgba(57, 115, 255, 0.10);
|
||||
border-color: rgba(57, 115, 255, 0.18);
|
||||
}
|
||||
.mobile-brand .brand-logo svg { stroke: var(--primary); }
|
||||
.mobile-brand-text { display: flex; flex-direction: column; gap: 2px; }
|
||||
.mobile-brand-name { font-size: 15px; font-weight: 600; }
|
||||
.mobile-brand-sub { font-size: 12px; color: var(--muted); }
|
||||
|
||||
.form-foot {
|
||||
position: absolute;
|
||||
left: 0; right: 0; bottom: 26px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #a3acbf;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: none;
|
||||
@@ -157,6 +222,8 @@
|
||||
animation: shake .32s ease;
|
||||
}
|
||||
.error.show { display: flex; }
|
||||
/* 中性的提示语气(功能未上线 / 操作引导) */
|
||||
.error.is-info { background: #f2f7ff; border-color: #d2e2ff; color: #2b5fc7; }
|
||||
.error svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; }
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
@@ -280,8 +347,8 @@
|
||||
.divider span { position: relative; background: #fff; padding: 0 12px; }
|
||||
.third-list { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
|
||||
.third-btn {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
padding: 9px 18px;
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 22px;
|
||||
background: #fff;
|
||||
@@ -296,6 +363,39 @@
|
||||
background: #f5f9ff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
/* 第三方图标色块:微信绿 / QQ 蓝 / 其余统一主色 */
|
||||
.third-icon {
|
||||
width: 22px; height: 22px;
|
||||
flex: 0 0 22px;
|
||||
border-radius: 50%;
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
font-size: 9.5px; font-weight: 700; letter-spacing: -.2px;
|
||||
}
|
||||
.third-icon svg { width: 13px; height: 13px; }
|
||||
.third-icon.is-wechat { background: rgba(7, 193, 96, .12); color: #07c160; }
|
||||
.third-icon.is-qq { background: rgba(18, 183, 245, .14); color: #12b7f5; }
|
||||
.third-icon.is-generic { background: rgba(57, 115, 255, .10); color: var(--primary); }
|
||||
|
||||
/* 短信验证码 */
|
||||
.code-row { display: flex; align-items: center; gap: 10px; }
|
||||
.code-row .input-wrap { flex: 1 1 auto; }
|
||||
.code-btn {
|
||||
flex: 0 0 auto;
|
||||
height: 46px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid rgba(57, 115, 255, .28);
|
||||
border-radius: var(--radius);
|
||||
background: rgba(57, 115, 255, .06);
|
||||
color: var(--primary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
transition: background .2s, border-color .2s, color .2s;
|
||||
}
|
||||
.code-btn:hover { background: rgba(57, 115, 255, .12); border-color: rgba(57, 115, 255, .45); }
|
||||
.code-btn:disabled { background: #f5f7fb; border-color: var(--border); color: var(--muted); cursor: not-allowed; }
|
||||
.form-hint { margin-top: 14px; font-size: 12px; color: var(--muted); line-height: 1.8; text-align: center; }
|
||||
|
||||
/* 企业选择 */
|
||||
.tenant-list { list-style: none; display: flex; flex-direction: column; gap: 10px; }
|
||||
@@ -333,27 +433,38 @@
|
||||
.tenant-arrow svg { width: 18px; height: 18px; display: block; }
|
||||
.tenant-item:hover .tenant-arrow { color: var(--primary); transform: translateX(3px); }
|
||||
|
||||
.back { text-align: center; margin-top: 22px; font-size: 13px; }
|
||||
.back { text-align: center; margin-top: 18px; font-size: 13px; color: var(--text-sub); line-height: 1.7; }
|
||||
|
||||
/* 微信扫码登录 */
|
||||
.scan-flex { display: flex; justify-content: center; }
|
||||
.scan-qr {
|
||||
width: 180px; height: 180px; flex: 0 0 180px;
|
||||
border: 1px solid var(--border); border-radius: 10px;
|
||||
/* ---------- 扫码登录 ---------- */
|
||||
.qr-panel { padding: 4px 0 2px; text-align: center; }
|
||||
.qr-box {
|
||||
position: relative;
|
||||
width: 200px; height: 200px;
|
||||
margin: 0 auto 20px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
box-shadow: 0 14px 34px rgba(31, 43, 72, 0.08);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
overflow: hidden; background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
.scan-qr .qr-img { width: 100%; height: 100%; object-fit: contain; }
|
||||
.scan-qr .qr-mask {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
||||
font-size: 12px; color: var(--muted); text-align: center; padding: 8px;
|
||||
.qr-img { width: 100%; height: 100%; object-fit: contain; }
|
||||
.qr-mask {
|
||||
position: absolute; inset: 0;
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
|
||||
padding: 12px;
|
||||
background: rgba(255, 255, 255, .96);
|
||||
font-size: 12.5px; color: var(--text-sub); line-height: 1.6; text-align: center;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.scan-btn {
|
||||
border: none; background: var(--primary); color: #fff;
|
||||
border-radius: 8px; padding: 6px 16px; font-size: 12px; cursor: pointer;
|
||||
border-radius: 8px; padding: 7px 18px; font-size: 12px; cursor: pointer;
|
||||
}
|
||||
.scan-right { display: none; }
|
||||
.qr-title { font-size: 14.5px; font-weight: 600; color: var(--text); letter-spacing: .3px; }
|
||||
.qr-desc { margin-top: 8px; font-size: 12.5px; line-height: 1.9; color: var(--text-sub); }
|
||||
.qr-desc strong { color: var(--primary); font-weight: 600; }
|
||||
.qr-note { margin-top: 12px; font-size: 12px; color: var(--muted); }
|
||||
|
||||
.foot-tip {
|
||||
margin-top: 26px;
|
||||
@@ -365,56 +476,57 @@
|
||||
}
|
||||
.foot-tip svg { width: 13px; height: 13px; flex: 0 0 auto; }
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.brand-panel { padding: 48px 44px; }
|
||||
.brand-title { font-size: 34px; }
|
||||
.form-panel { min-width: 400px; padding: 56px 40px 84px; }
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body { padding: 20px 14px; align-items: flex-start; }
|
||||
.auth-card { max-width: 520px; min-height: 0; flex-direction: column; }
|
||||
.auth-side { width: 100%; flex: none; padding: 30px 26px 24px; }
|
||||
.side-title { margin-top: 26px; font-size: 21px; }
|
||||
.side-illus { display: none; }
|
||||
.auth-main { padding: 34px 26px 30px; }
|
||||
.panel-title { font-size: 23px; }
|
||||
.login-page { flex-direction: column; }
|
||||
.brand-panel { display: none; }
|
||||
.form-panel {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
align-items: flex-start;
|
||||
padding: 40px 24px 72px;
|
||||
}
|
||||
.form-inner { max-width: 440px; margin: 0 auto; }
|
||||
.mobile-brand { display: flex; }
|
||||
.panel-title { font-size: 26px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="glow glow-1"></div>
|
||||
<div class="glow glow-2"></div>
|
||||
<div class="login-page">
|
||||
<!-- 左侧品牌区:背景图 / Logo / 主副标题由 platform「平台设置 → 登录页设置」提供 -->
|
||||
<aside class="brand-panel{{if .LoginBg}} has-bg{{end}}">
|
||||
{{if .LoginBg}}
|
||||
<img class="brand-bg" src="{{.LoginBg}}" alt="" />
|
||||
<span class="brand-veil"></span>
|
||||
{{end}}
|
||||
|
||||
<div class="auth-card">
|
||||
<!-- 左侧品牌区 -->
|
||||
<aside class="auth-side">
|
||||
<div class="brand">
|
||||
<span class="brand-logo">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/>
|
||||
<path d="M9.2 12.2l2 2 3.6-4"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="brand-name">云泽统一认证中心</span>
|
||||
<div class="brand-inner">
|
||||
<div class="brand">
|
||||
{{if .LoginLogo}}
|
||||
<img class="brand-img" src="{{.LoginLogo}}" alt="{{.LoginTitle}}" />
|
||||
{{else}}
|
||||
<span class="brand-logo">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/>
|
||||
<path d="M9.2 12.2l2 2 3.6-4"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="brand-name">云泽统一认证中心</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<h1 class="brand-title">{{.LoginTitle}}</h1>
|
||||
<p class="brand-sub">{{.LoginSubtitle}}</p>
|
||||
</div>
|
||||
|
||||
<div class="side-title">一次登录<br>全平台通行</div>
|
||||
<div class="side-desc">
|
||||
基于 OIDC / OAuth 2.0 的统一身份底座,<br>
|
||||
为所有接入应用提供安全、一致的登录体验。
|
||||
</div>
|
||||
|
||||
<div class="side-illus">
|
||||
<svg viewBox="0 0 260 170" fill="none">
|
||||
<ellipse cx="130" cy="150" rx="98" ry="11" fill="rgba(255,255,255,.13)"/>
|
||||
<rect x="26" y="60" width="56" height="38" rx="9" fill="rgba(255,255,255,.14)"/>
|
||||
<rect x="36" y="70" width="26" height="4" rx="2" fill="rgba(255,255,255,.45)"/>
|
||||
<rect x="36" y="79" width="36" height="4" rx="2" fill="rgba(255,255,255,.28)"/>
|
||||
<rect x="184" y="52" width="50" height="34" rx="9" fill="rgba(255,255,255,.10)"/>
|
||||
<rect x="193" y="62" width="22" height="4" rx="2" fill="rgba(255,255,255,.36)"/>
|
||||
<path d="M130 26l40 15v30c0 22-17 39-40 47-23-8-40-25-40-47V41l40-15z"
|
||||
fill="rgba(255,255,255,.17)" stroke="rgba(255,255,255,.55)" stroke-width="1.6"/>
|
||||
<path d="M116 82l11 11 21-23" stroke="#fff" stroke-width="5.5"
|
||||
stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="side-foot">
|
||||
<div class="brand-foot">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||||
<rect x="4" y="11" width="16" height="10" rx="2"/>
|
||||
<path d="M8 11V8a4 4 0 018 0v3"/>
|
||||
@@ -424,7 +536,24 @@
|
||||
</aside>
|
||||
|
||||
<!-- 右侧表单区 -->
|
||||
<main class="auth-main">
|
||||
<main class="form-panel">
|
||||
<div class="form-inner">
|
||||
<div class="mobile-brand">
|
||||
{{if .LoginLogo}}
|
||||
<img class="brand-img" src="{{.LoginLogo}}" alt="{{.LoginTitle}}" />
|
||||
{{else}}
|
||||
<span class="brand-logo">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/>
|
||||
<path d="M9.2 12.2l2 2 3.6-4"/>
|
||||
</svg>
|
||||
</span>
|
||||
{{end}}
|
||||
<span class="mobile-brand-text">
|
||||
<span class="mobile-brand-name">云泽统一认证中心</span>
|
||||
<span class="mobile-brand-sub">{{.LoginTitle}}</span>
|
||||
</span>
|
||||
</div>
|
||||
{{if eq .Step "tenant"}}
|
||||
<div class="panel-head">
|
||||
<h1 class="panel-title">选择企业</h1>
|
||||
@@ -462,21 +591,10 @@
|
||||
<div class="back"><a class="link" onclick="logout()">不是我的账号?切换账号</a></div>
|
||||
{{else}}
|
||||
<div class="panel-head">
|
||||
<h1 class="panel-title">欢迎登录</h1>
|
||||
<p class="panel-sub">请输入您的账号与密码以继续</p>
|
||||
<h1 class="panel-title">登录</h1>
|
||||
<p class="panel-sub">请选择登录方式,进入您的工作空间</p>
|
||||
</div>
|
||||
|
||||
{{if .Notice}}
|
||||
<div class="notice-box{{if eq .Notice "registered_warn"}} warn{{end}}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
{{if eq .Notice "registered_warn"}}<circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/>{{else}}<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/><path d="M9.2 12.2l2 2 3.6-4"/>{{end}}
|
||||
</svg>
|
||||
<span>
|
||||
{{if eq .Notice "reset"}}密码已重置,请使用新密码登录{{else if eq .Notice "registered_warn"}}{{.WarnMsg}},可先登录{{else}}注册成功,请使用新账号登录{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="error" id="error">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||||
<circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/>
|
||||
@@ -484,7 +602,27 @@
|
||||
<span id="errorText"></span>
|
||||
</div>
|
||||
|
||||
<form id="loginForm" onsubmit="return submitLogin(event)" autocomplete="on">
|
||||
<!-- 登录方式切换:默认账号密码 -->
|
||||
<div class="login-tabs" role="tablist">
|
||||
<button class="login-tab active" type="button" role="tab" data-tab="account" onclick="switchLoginTab('account')">账号密码</button>
|
||||
<button class="login-tab" type="button" role="tab" data-tab="sms" onclick="switchLoginTab('sms')">短信登录</button>
|
||||
<button class="login-tab" type="button" role="tab" data-tab="qr" onclick="switchLoginTab('qr')">扫码登录</button>
|
||||
</div>
|
||||
|
||||
<!-- 账号密码登录 -->
|
||||
<div class="login-panel active" id="panel-account">
|
||||
{{if .Notice}}
|
||||
<div class="notice-box{{if eq .Notice "registered_warn"}} warn{{end}}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
{{if eq .Notice "registered_warn"}}<circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/>{{else}}<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/><path d="M9.2 12.2l2 2 3.6-4"/>{{end}}
|
||||
</svg>
|
||||
<span>
|
||||
{{if eq .Notice "reset"}}密码已重置,请使用新密码登录{{else if eq .Notice "registered_warn"}}{{.WarnMsg}},可先登录{{else}}注册成功,请使用新账号登录{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<form id="loginForm" onsubmit="return submitLogin(event)" autocomplete="on">
|
||||
<div class="field">
|
||||
<label class="field-label" for="account">账号</label>
|
||||
<div class="input-wrap">
|
||||
@@ -524,46 +662,82 @@
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="back" style="margin-top:16px">还没有账号?<a class="link" href="/auth/register?client_id={{urlquery .ClientID}}&redirect={{urlquery .Redirect}}">立即注册</a></div>
|
||||
|
||||
<div class="third-area" id="thirdArea" style="display:none">
|
||||
<div class="divider"><span>其他登录方式</span></div>
|
||||
<div class="third-list" id="thirdList"></div>
|
||||
<div class="back">还没有账号?<a class="link" href="/auth/register?client_id={{urlquery .ClientID}}&redirect={{urlquery .Redirect}}">立即注册</a></div>
|
||||
</div>
|
||||
|
||||
<!-- 微信扫码登录(未认证公众号:服务号二维码 + 登录码,公众号内确认后自动登录) -->
|
||||
<div class="divider"><span>其他登录方式</span></div>
|
||||
<div class="third-list" style="justify-content:flex-start">
|
||||
<button class="third-btn" type="button" id="wechatScanEntry" onclick="showWechatScan()">
|
||||
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 4h16v12H8l-4 4z"/><path d="M8.5 9.5h.01M12 9.5h.01M15.5 9.5h.01"/>
|
||||
</svg>
|
||||
微信登录
|
||||
</button>
|
||||
<!-- 手机号验证码登录 -->
|
||||
<div class="login-panel" id="panel-sms">
|
||||
<form onsubmit="return submitSmsLogin(event)" autocomplete="on">
|
||||
<div class="field">
|
||||
<label class="field-label" for="smsMobile">手机号</label>
|
||||
<div class="input-wrap">
|
||||
<input id="smsMobile" type="tel" inputmode="numeric" maxlength="11" placeholder="请输入手机号" autocomplete="tel">
|
||||
<svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="6" y="2" width="12" height="20" rx="3"/><path d="M11 18h2"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label" for="smsCode">验证码</label>
|
||||
<div class="code-row">
|
||||
<div class="input-wrap">
|
||||
<input id="smsCode" type="text" inputmode="numeric" maxlength="6" placeholder="请输入短信验证码" autocomplete="one-time-code">
|
||||
<svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="4" y="5" width="16" height="14" rx="2"/><path d="M8 9h8M8 13h5"/>
|
||||
</svg>
|
||||
</div>
|
||||
<button class="code-btn" type="button" id="smsCodeBtn" onclick="sendSmsCode()">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn" type="submit" id="smsSubmitBtn">
|
||||
<span class="spinner"></span>
|
||||
<span id="smsBtnLabel">登 录</span>
|
||||
</button>
|
||||
</form>
|
||||
<p class="form-hint">未注册的手机号验证通过后将自动创建账号</p>
|
||||
</div>
|
||||
|
||||
<div id="wechatScanArea" style="display:none; margin-top:18px;">
|
||||
<div class="scan-flex">
|
||||
<div class="scan-qr">
|
||||
<!-- 扫码登录:微信扫码 → 小程序内确认 -->
|
||||
<div class="login-panel" id="panel-qr">
|
||||
<div class="qr-panel">
|
||||
<div class="qr-box">
|
||||
<img id="scanQrImg" class="qr-img" alt="微信扫码登录" style="display:none" />
|
||||
<div class="qr-mask" id="scanQrMask">
|
||||
<span id="scanQrMaskText">正在获取二维码…</span>
|
||||
<button class="scan-btn" onclick="restartWechatScan()" style="display:none" id="scanQrRefreshBtn">刷新</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="qr-title">微信扫码登录</p>
|
||||
<p class="qr-desc">使用微信「扫一扫」,扫码后在<strong>云泽小程序</strong>中点击确认<br />即可完成登录</p>
|
||||
<p class="qr-note">二维码 5 分钟内有效,过期可点击刷新</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第三方登录(未配置时点击提示即将上线) -->
|
||||
<div class="third-area" id="thirdArea">
|
||||
<div class="divider"><span>其他登录方式</span></div>
|
||||
<div class="third-list" id="thirdList">
|
||||
<button class="third-btn" type="button" data-third-provider="wechat" onclick="thirdLogin('wechat', '微信')">
|
||||
<span class="third-icon is-wechat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 5h13v9H9l-4 4z"/><path d="M9 9h.01M13 9h.01"/>
|
||||
</svg>
|
||||
</span>
|
||||
微信登录
|
||||
</button>
|
||||
<button class="third-btn" type="button" data-third-provider="qq" onclick="thirdLogin('qq', 'QQ')">
|
||||
<span class="third-icon is-qq">QQ</span>
|
||||
QQ 登录
|
||||
</button>
|
||||
</div>
|
||||
<div class="back"><a class="link" onclick="hideWechatScan()">返回账号密码登录</a></div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="foot-tip">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3l7 3v6c0 4.2-2.9 7.6-7 9-4.1-1.4-7-4.8-7-9V6l7-3z"/>
|
||||
</svg>
|
||||
<!--
|
||||
<span>统一身份认证 · 一次登录,全平台通行</span>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="form-foot">© 2026 云泽科技 版权所有</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -578,9 +752,12 @@
|
||||
var GEETEST_SDK_LOCAL = '/static/js/gt4.js';
|
||||
var geetestSDKPromise = null;
|
||||
|
||||
function showError(msg) {
|
||||
function showError(msg, tone) {
|
||||
var box = document.getElementById('error');
|
||||
document.getElementById('errorText').textContent = msg;
|
||||
var text = document.getElementById('errorText');
|
||||
if (!box || !text) return;
|
||||
box.classList.toggle('is-info', tone === 'info');
|
||||
text.textContent = msg;
|
||||
box.classList.remove('show');
|
||||
void box.offsetWidth; // 重启动画
|
||||
box.classList.add('show');
|
||||
@@ -591,6 +768,24 @@
|
||||
if (box) box.classList.remove('show');
|
||||
}
|
||||
|
||||
// ==================== 登录方式切换(账号密码 / 短信 / 扫码) ====================
|
||||
var LOGIN_PANELS = { account: 'panel-account', sms: 'panel-sms', qr: 'panel-qr' };
|
||||
|
||||
function switchLoginTab(name) {
|
||||
if (!LOGIN_PANELS[name]) return;
|
||||
var tabs = document.querySelectorAll('.login-tab');
|
||||
Array.prototype.forEach.call(tabs, function (tab) {
|
||||
tab.classList.toggle('active', tab.getAttribute('data-tab') === name);
|
||||
});
|
||||
Object.keys(LOGIN_PANELS).forEach(function (key) {
|
||||
var panel = document.getElementById(LOGIN_PANELS[key]);
|
||||
if (panel) panel.classList.toggle('active', key === name);
|
||||
});
|
||||
hideError();
|
||||
// 扫码 tab 才拉二维码,离开则停止轮询
|
||||
if (name === 'qr') restartWechatScan(); else stopWechatScan();
|
||||
}
|
||||
|
||||
function setBtnLoading(on, text) {
|
||||
var btn = document.getElementById('submitBtn');
|
||||
if (!btn) return;
|
||||
@@ -682,28 +877,50 @@
|
||||
|
||||
loadVerifyConfig();
|
||||
|
||||
// 加载已开通的第三方登录方式
|
||||
// 已开通的第三方登录方式:记录状态,供静态 QQ / 微信入口判断是否可用
|
||||
var thirdEnabled = {};
|
||||
var THIRD_STATIC = { wechat: 1, qq: 1 };
|
||||
|
||||
function loadThirdProviders() {
|
||||
var box = document.getElementById('thirdList');
|
||||
if (!box) return;
|
||||
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 && i.provider !== 'wechat'; });
|
||||
var box = document.getElementById('thirdList');
|
||||
box.innerHTML = ''; // 防止重复渲染
|
||||
if (!enabled.length) return;
|
||||
enabled.forEach(function (item) {
|
||||
thirdEnabled = {};
|
||||
// 清掉上一轮动态追加的按钮(静态 QQ / 微信入口保留)
|
||||
Array.prototype.slice.call(box.querySelectorAll('[data-dynamic="1"]')).forEach(function (n) {
|
||||
if (n.parentNode) n.parentNode.removeChild(n);
|
||||
});
|
||||
list.forEach(function (item) {
|
||||
if (!item || !item.enabled) return;
|
||||
thirdEnabled[item.provider] = true;
|
||||
if (THIRD_STATIC[item.provider]) return;
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'third-btn';
|
||||
btn.type = 'button';
|
||||
btn.textContent = item.name;
|
||||
btn.className = 'third-btn';
|
||||
btn.setAttribute('data-dynamic', '1');
|
||||
var icon = document.createElement('span');
|
||||
icon.className = 'third-icon is-generic';
|
||||
icon.textContent = (item.name || '?').slice(0, 1);
|
||||
btn.appendChild(icon);
|
||||
btn.appendChild(document.createTextNode(item.name || item.provider));
|
||||
btn.onclick = function () { startThird(item.provider); };
|
||||
box.appendChild(btn);
|
||||
});
|
||||
document.getElementById('thirdArea').style.display = 'block';
|
||||
// 未开通的入口:保留样式,悬停提示即将上线,点击给中性提示
|
||||
Array.prototype.forEach.call(box.querySelectorAll('[data-third-provider]'), function (btn) {
|
||||
var provider = btn.getAttribute('data-third-provider');
|
||||
btn.title = thirdEnabled[provider] ? '' : '即将上线';
|
||||
});
|
||||
})
|
||||
.catch(function () { /* 静默失败,不影响账号密码登录 */ });
|
||||
.catch(function () { /* 静默失败,不影响其他登录方式 */ });
|
||||
}
|
||||
|
||||
function thirdLogin(provider, label) {
|
||||
if (thirdEnabled[provider]) { startThird(provider); return; }
|
||||
showError((label || provider) + '登录即将上线,敬请期待', 'info');
|
||||
}
|
||||
|
||||
function startThird(provider) {
|
||||
@@ -772,6 +989,27 @@
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 手机号验证码登录(仅样式,接口待接入) ====================
|
||||
function sendSmsCode() {
|
||||
var input = document.getElementById('smsMobile');
|
||||
var mobile = input ? input.value.trim() : '';
|
||||
if (!/^1[3-9]\d{9}$/.test(mobile)) { showError('请输入正确的手机号'); return; }
|
||||
showError('短信验证码服务即将上线,请先使用账号密码登录', 'info');
|
||||
}
|
||||
|
||||
function submitSmsLogin(e) {
|
||||
e.preventDefault();
|
||||
hideError();
|
||||
var mobileEl = document.getElementById('smsMobile');
|
||||
var codeEl = document.getElementById('smsCode');
|
||||
var mobile = mobileEl ? mobileEl.value.trim() : '';
|
||||
var code = codeEl ? codeEl.value.trim() : '';
|
||||
if (!/^1[3-9]\d{9}$/.test(mobile)) { showError('请输入正确的手机号'); return false; }
|
||||
if (!code) { showError('请输入验证码'); return false; }
|
||||
showError('手机号验证码登录即将上线,请先使用账号密码登录', 'info');
|
||||
return false;
|
||||
}
|
||||
|
||||
function submitLogin(e) {
|
||||
e.preventDefault();
|
||||
hideError();
|
||||
@@ -867,27 +1105,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 微信扫码登录(未认证公众号:服务号二维码 + 登录码) ====================
|
||||
// ==================== 微信扫码登录(扫码 → 小程序内确认;已接 scan/start、scan/status) ====================
|
||||
var scanScene = '';
|
||||
var scanExpireAt = 0;
|
||||
var scanPollTimer = null;
|
||||
|
||||
function showWechatScan() {
|
||||
hideError();
|
||||
document.getElementById('loginForm').style.display = 'none';
|
||||
document.getElementById('thirdArea').style.display = 'none';
|
||||
document.getElementById('wechatScanEntry').parentElement.style.display = 'none';
|
||||
document.getElementById('wechatScanArea').style.display = 'block';
|
||||
restartWechatScan();
|
||||
}
|
||||
|
||||
function hideWechatScan() {
|
||||
stopWechatScan();
|
||||
document.getElementById('wechatScanArea').style.display = 'none';
|
||||
document.getElementById('loginForm').style.display = 'block';
|
||||
document.getElementById('wechatScanEntry').parentElement.style.display = 'flex';
|
||||
loadThirdProviders();
|
||||
}
|
||||
// 显隐由 switchLoginTab 控制,切换 tab 时自动启停轮询
|
||||
|
||||
function stopWechatScan() {
|
||||
if (scanPollTimer) { clearInterval(scanPollTimer); scanPollTimer = null; }
|
||||
|
||||
Reference in new issue
Block a user