refactor: 合并 biz_support_unit/biz_execution_unit/biz_service_org 为 biz_org, 删除 2 张孤儿表, 改 biz_person.work_unit → org_id FK
主要改动: - SQL: biz_support_unit → biz_org, 加 org_type, 加 business_nature; 删 biz_execution_unit, biz_service_org - SQL: biz_project.support_unit_id/name + service_org_id/name → org_id/name/type - SQL: biz_meeting.support_unit_name → org_name - SQL: biz_person.work_unit → org_id (FK) - 后端: 新 BizOrg entity/mapper/service/controller - 后端: BizProject/BizMeeting 字段重命名 - 后端: 删 12 个 BizSupportUnit/BizExecutionUnit/BizServiceOrg Java 文件 - 后端: BizPersonImportVO.workUnit → orgName (导入时查 biz_org 取 org_id) - 后端: BizAuthController.registerExecutor 完整实现 (原 registerSupplier stub) - 前端: 新 admin/Orgs.vue + manager/Orgs.vue (原 SupportUnits) - 前端: RegisterExecutor.vue (原 RegisterSupplier, 单页 2 步) - 前端: sponsor/executor/manager 多个文件 workUnit → orgId/orgName 重命名 - 前端: 统一 supplier → executor, 业务命名 sponsor(赞助方) / executor(执行方=供应商) - 前端: 全工程 execution → executor (company type / role / person unit_type)
This commit is contained in:
@@ -0,0 +1,689 @@
|
||||
<template>
|
||||
<div class="login-page">
|
||||
<!-- 顶部导航 -->
|
||||
<header class="header">
|
||||
<a class="logo" @click.prevent="$router.push('/portal/home')">
|
||||
<div class="logo-icon">医</div>
|
||||
<div class="logo-text">
|
||||
<span class="logo-title">北京整合医学学会</span>
|
||||
<span class="logo-subtitle">Beijing Association of Holistic Integrative Medicine</span>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<!-- 主体 -->
|
||||
<main class="main-content">
|
||||
<!-- 左侧 banner -->
|
||||
<div class="banner-section">
|
||||
<div class="banner-inner">
|
||||
<span class="banner-tag">2025-2030</span>
|
||||
<h2 class="banner-title">协同创新 共建共享<br>整合医学发展新格局</h2>
|
||||
<div class="banner-divider"></div>
|
||||
<p class="banner-desc">
|
||||
聚焦医学整合创新,系统推进七大专项计划,<br>
|
||||
全面构建覆盖诊疗、科研、人才、管理、公益、<br>
|
||||
政学协作与组织建设的协同发展体系。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧登录卡片 -->
|
||||
<section class="login-section">
|
||||
<div class="login-card">
|
||||
<h1 class="login-title">账号登录</h1>
|
||||
<p class="login-subtitle">请输入您的账号信息</p>
|
||||
|
||||
<form id="loginForm" @submit.prevent="onSubmit">
|
||||
<div class="form-group">
|
||||
<svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="12" cy="7" r="4"/>
|
||||
</svg>
|
||||
<input v-model="form.username" type="text" id="username" class="form-input" placeholder="用户名 / 手机号" autocomplete="username">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<svg class="input-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
<input v-model="form.password" type="password" id="password" class="form-input" placeholder="密码" autocomplete="current-password">
|
||||
</div>
|
||||
|
||||
<div v-if="captchaEnabled" class="captcha-group">
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<input v-model="form.code" type="text" id="captcha" class="form-input captcha-input" placeholder="验证码" maxlength="6">
|
||||
</div>
|
||||
<img v-if="captchaImg" :src="captchaImg" class="captcha-image" @click="loadCaptcha" title="点击刷新" alt="验证码">
|
||||
<div v-else class="captcha-image" @click="loadCaptcha" title="点击刷新">加载中</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="login-btn" :disabled="loading">{{ loading ? '登录中...' : '登 录' }}</button>
|
||||
|
||||
<div class="form-bottom-links">
|
||||
<a class="bottom-link" @click="onRegister">新用户注册</a>
|
||||
<a class="bottom-link" @click="onForgot">忘记密码</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 底部 -->
|
||||
<footer class="footer">
|
||||
<p>© 北京整合医学学会 BAHIM</p>
|
||||
<p>京ICP备2020035479号-1 京公网安备11010802034820</p>
|
||||
</footer>
|
||||
|
||||
<!-- 注册弹窗 (原型: 选择用户类别) -->
|
||||
<div class="modal-overlay" :class="{ active: showRoleModal }" @click.self="closeModal">
|
||||
<div class="modal">
|
||||
<h2 class="modal-title">选择用户类别</h2>
|
||||
<div class="user-type-list">
|
||||
<label v-for="t in registerTypes" :key="t.value" class="user-type-item">
|
||||
<input type="radio" name="registerUserType" :value="t.value" v-model="registerUserType">
|
||||
<div class="info">
|
||||
<div class="name">{{ t.name }}</div>
|
||||
<div class="desc">{{ t.desc }}</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="modal-btn secondary" type="button" @click="closeModal">取消</button>
|
||||
<button class="modal-btn primary" type="button" @click="confirmRegister">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { login, getInfo, getCaptcha } from '@/api/auth'
|
||||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const form = reactive({ username: '', password: '', code: '', uuid: '', role: 'leader' })
|
||||
const captchaImg = ref('')
|
||||
const captchaEnabled = ref(true)
|
||||
const loading = ref(false)
|
||||
const showRoleModal = ref(false)
|
||||
const registerUserType = ref('')
|
||||
|
||||
const registerTypes = [
|
||||
{ value: 'expert', name: '项目参与专家', desc: '负责项目方案设计与评审' },
|
||||
{ value: 'executor', name: '项目执行单位(供应商)', desc: '承担项目执行,需走入库流程' },
|
||||
{ value: 'sponsor', name: '项目支持单位', desc: '注册后默认为监察员角色' }
|
||||
]
|
||||
|
||||
const userTypes = [
|
||||
{ value: 'admin', name: '系统管理员', desc: '系统配置、用户管理、权限控制' },
|
||||
{ value: 'leader', name: '学会领导', desc: '查看全局数据、审批重要事项' },
|
||||
{ value: 'manager', name: '项目经理', desc: '项目管理、方案审核、过程监督' },
|
||||
{ value: 'doctor', name: '评审专家', desc: '项目评审、评分反馈、查看任务' },
|
||||
{ value: 'executor', name: '执行单位', desc: '会议组织、人员安排、劳务结算' },
|
||||
{ value: 'sponsor', name: '支持单位 / 赞助方', desc: '支持函管理、人员管理、合作记录' },
|
||||
]
|
||||
|
||||
async function loadCaptcha() {
|
||||
try {
|
||||
const res = await getCaptcha()
|
||||
captchaEnabled.value = res?.captchaEnabled !== false
|
||||
if (res?.uuid) {
|
||||
form.uuid = res.uuid
|
||||
captchaImg.value = 'data:image/png;base64,' + (res.img || '')
|
||||
}
|
||||
} catch (e) {
|
||||
captchaImg.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!form.username || !form.password) {
|
||||
ElMessage.warning('请输入用户名和密码')
|
||||
return
|
||||
}
|
||||
if (captchaEnabled.value && !form.code) {
|
||||
ElMessage.warning('请输入验证码')
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await login({ username: form.username, password: form.password, code: form.code || '', uuid: form.uuid || '' })
|
||||
const role = autoRole(form.username)
|
||||
userStore.setToken(res.token)
|
||||
// /login 接口只返回 token; 调 /getInfo 拿完整 user (含 accountType/parentUserId, 让 isMain/isSub 判断正确)
|
||||
try {
|
||||
const info = await getInfo()
|
||||
const u = info.user || {}
|
||||
userStore.setUser({
|
||||
userId: u.userId,
|
||||
userName: u.userName || form.username,
|
||||
nickName: u.nickName || form.username,
|
||||
accountType: u.accountType || 'MAIN',
|
||||
parentUserId: u.parentUserId || null,
|
||||
role
|
||||
})
|
||||
} catch {
|
||||
// /getInfo 失败时回退: 只存基本信息
|
||||
userStore.setUser({
|
||||
userId: res.userId,
|
||||
userName: form.username,
|
||||
nickName: form.username,
|
||||
accountType: 'MAIN',
|
||||
parentUserId: null,
|
||||
role
|
||||
})
|
||||
}
|
||||
ElMessage.success(`欢迎,${form.username}(${userTypes.find(u => u.value === role)?.name || role})`)
|
||||
router.replace(roleHome[role] || '/leader/home')
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || '登录失败')
|
||||
loadCaptcha()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function autoRole(username) {
|
||||
const u = (username || '').toLowerCase()
|
||||
if (u === 'admin' || u === 'ry') return 'admin'
|
||||
if (u.startsWith('leader')) return 'leader'
|
||||
if (u.startsWith('manager')) return 'manager'
|
||||
if (u.startsWith('doctor')) return 'doctor'
|
||||
if (u.startsWith('executor')) return 'executor'
|
||||
if (u.startsWith('sponsor')) return 'sponsor'
|
||||
return 'leader'
|
||||
}
|
||||
|
||||
const roleHome = {
|
||||
admin: '/admin/workbench',
|
||||
leader: '/leader/home',
|
||||
manager: '/manager/workbench',
|
||||
doctor: '/doctor/home',
|
||||
executor: '/executor/meetings',
|
||||
sponsor: '/sponsor/home',
|
||||
}
|
||||
|
||||
function onRegister() {
|
||||
showRoleModal.value = true
|
||||
registerUserType.value = ''
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
showRoleModal.value = false
|
||||
}
|
||||
|
||||
function confirmRegister() {
|
||||
if (!registerUserType.value) {
|
||||
ElMessage.warning('请选择用户类别')
|
||||
return
|
||||
}
|
||||
const routeMap = {
|
||||
expert: '/register-expert',
|
||||
executor: '/register-executor',
|
||||
sponsor: '/register-sponsor'
|
||||
}
|
||||
const target = routeMap[registerUserType.value]
|
||||
if (!target) {
|
||||
ElMessage.warning('该类别暂未开放注册')
|
||||
return
|
||||
}
|
||||
showRoleModal.value = false
|
||||
router.push(target)
|
||||
}
|
||||
|
||||
function onForgot() {
|
||||
ElMessage.info('请联系系统管理员重置密码')
|
||||
}
|
||||
|
||||
onMounted(() => { loadCaptcha() })
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* === 原型 CSS 1:1 复制自 /home/john/ry8080/proto/html/登录.html === */
|
||||
|
||||
.login-page *{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.login-page{
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #333;
|
||||
background: #f5f6f8;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 顶部导航 */
|
||||
.login-page .header{
|
||||
height: 64px;
|
||||
padding: 0 60px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-page .logo{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.login-page .logo-icon{
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #1e3a8a;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.login-page .logo-text{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.login-page .logo-title{
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.login-page .logo-subtitle{
|
||||
font-size: 11px;
|
||||
color: #6b7280;
|
||||
margin-top: 2px;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
/* 主体 */
|
||||
.login-page .main-content{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 60px;
|
||||
gap: 60px;
|
||||
}
|
||||
|
||||
.login-page .banner-section{
|
||||
flex: 1;
|
||||
max-width: 560px;
|
||||
}
|
||||
|
||||
.login-page .banner-inner{
|
||||
background: #1e3a8a;
|
||||
color: #fff;
|
||||
padding: 56px 56px;
|
||||
height: 440px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.login-page .banner-tag{
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
font-size: 12px;
|
||||
letter-spacing: 2px;
|
||||
margin-bottom: 24px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.login-page .banner-title{
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 20px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.login-page .banner-divider{
|
||||
width: 48px;
|
||||
height: 2px;
|
||||
background: #fff;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.login-page .banner-desc{
|
||||
font-size: 14px;
|
||||
line-height: 1.9;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* 登录卡片 */
|
||||
.login-page .login-section{
|
||||
width: 400px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.login-page .login-card{
|
||||
background: #ffffff;
|
||||
padding: 40px 40px;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.login-page .login-title{
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.login-page .login-subtitle{
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.login-page .form-group{
|
||||
margin-bottom: 18px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-page .form-input{
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
padding: 0 14px 0 42px;
|
||||
border: 1px solid #d1d5db;
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: #1f2937;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.login-page .form-input:focus{
|
||||
border-color: #1e3a8a;
|
||||
}
|
||||
|
||||
.login-page .form-input::placeholder{
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.login-page .input-icon{
|
||||
position: absolute;
|
||||
left: 14px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #9ca3af;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.login-page .captcha-group{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.login-page .captcha-group .form-group{
|
||||
flex: 1;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.login-page .captcha-input{
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.login-page .captcha-input + .input-icon{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.login-page .captcha-image{
|
||||
width: 110px;
|
||||
height: 44px;
|
||||
border: 1px solid #d1d5db;
|
||||
background: #f3f4f6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 4px;
|
||||
color: #1e3a8a;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.login-page .form-bottom-links{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 14px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.login-page .form-bottom-links .bottom-link{
|
||||
color: #1e3a8a;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login-page .form-bottom-links .bottom-link:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.login-page .login-btn{
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background: #1e3a8a;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 8px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.login-page .login-btn:hover{
|
||||
background: #1e40af;
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.login-page .footer{
|
||||
padding: 20px 60px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.login-page .footer p{ margin-bottom: 2px; }
|
||||
|
||||
/* 弹窗 */
|
||||
.login-page .modal-overlay{
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.login-page .modal-overlay.active{ display: flex; }
|
||||
|
||||
.login-page .modal{
|
||||
background: #fff;
|
||||
padding: 32px 36px;
|
||||
width: 440px;
|
||||
max-width: 90vw;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.login-page .modal-title{
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.login-page .user-type-list{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.login-page .user-type-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 14px 18px;
|
||||
border: 1px solid #e5e7eb;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.login-page .user-type-item:hover{
|
||||
border-color: #1e3a8a;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.login-page .user-type-item input[type="radio"]{
|
||||
margin-right: 12px;
|
||||
cursor: pointer;
|
||||
accent-color: #1e3a8a;
|
||||
}
|
||||
|
||||
.login-page .user-type-item .info{ flex: 1; }
|
||||
|
||||
.login-page .user-type-item .name{
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #1f2937;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.login-page .user-type-item .desc{
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.login-page .modal-actions{
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.login-page .modal-btn{
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.login-page .modal-btn.primary{
|
||||
background: #1e3a8a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.login-page .modal-btn.primary:hover{ background: #1e40af; }
|
||||
|
||||
.login-page .modal-btn.secondary{
|
||||
background: #fff;
|
||||
color: #4b5563;
|
||||
border: 1px solid #d1d5db;
|
||||
}
|
||||
|
||||
.login-page .modal-btn.secondary:hover{
|
||||
border-color: #1e3a8a;
|
||||
color: #1e3a8a;
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 1024px) {
|
||||
.main-content {
|
||||
flex-direction: column;
|
||||
padding: 30px 30px;
|
||||
gap: 30px;
|
||||
}
|
||||
.banner-section { width: 100%; max-width: 100%; }
|
||||
.banner-inner { height: auto; padding: 40px 30px; }
|
||||
.login-section { width: 100%; max-width: 400px; }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.header { padding: 0 20px; }
|
||||
.main-content { padding: 20px; }
|
||||
.login-card { padding: 30px 24px; }
|
||||
.footer { padding: 16px 20px; }
|
||||
}
|
||||
|
||||
/* === 用户要求: 左侧保持 440px 不动, 右侧登录卡片高度追平左侧, 两栏在 main-content 中居中 === */
|
||||
.login-page .main-content { align-items: center; }
|
||||
.login-page .login-card { height: 440px; display: flex; flex-direction: column; justify-content: center; }
|
||||
|
||||
/* === 注册选择类别弹窗 (原型 1:1 抄 /home/john/ry8080/proto/html/登录.html) === */
|
||||
.modal-overlay {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 1000;
|
||||
opacity: 0; visibility: hidden;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
}
|
||||
.modal-overlay.active { opacity: 1; visibility: visible; }
|
||||
|
||||
.modal {
|
||||
background: #fff;
|
||||
padding: 32px 36px;
|
||||
width: 440px;
|
||||
max-width: 90vw;
|
||||
border: 1px solid #e5e7eb;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.modal-title { font-size: 18px; font-weight: 600; color: #1a1a1a; margin-bottom: 20px; text-align: center; }
|
||||
.user-type-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 24px; }
|
||||
.user-type-item {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 14px 18px;
|
||||
border: 1px solid #e5e7eb;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.user-type-item:hover { border-color: var(--brand-primary, #1890ff); background: #f7faff; }
|
||||
.user-type-item input[type="radio"] {
|
||||
width: 18px; height: 18px;
|
||||
accent-color: var(--brand-primary, #1890ff);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.user-type-item .info { flex: 1; }
|
||||
.user-type-item .name { font-size: 15px; color: #1a1a1a; font-weight: 500; margin-bottom: 2px; }
|
||||
.user-type-item .desc { font-size: 12px; color: #909399; }
|
||||
|
||||
.modal-actions { display: flex; gap: 12px; }
|
||||
.modal-btn {
|
||||
flex: 1; height: 40px;
|
||||
border: none; cursor: pointer;
|
||||
font-size: 14px; font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.modal-btn.secondary { background: #f5f7fa; color: #606266; }
|
||||
.modal-btn.secondary:hover { background: #ebeef5; }
|
||||
.modal-btn.primary { background: var(--brand-primary, #1890ff); color: #fff; }
|
||||
.modal-btn.primary:hover { background: var(--brand-primary-deep, #096dd9); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user