在阿里巴巴网站上怎么做贸易,合肥网站制作方案,什么是网站建设的建议,制作网页链接的方法概述我们在开篇的时候实现了简单的登陆功能#xff0c;也实现了一个前后端联调的登陆功能#xff0c;但是你有没有发现#xff0c;那个登陆只是一个简单的登陆#xff0c;且密码在接口返回的过程中是铭文密码#xff0c;在生产环境中使用肯定是不行的#xff0c;一般密码… 概述我们在开篇的时候实现了简单的登陆功能也实现了一个前后端联调的登陆功能但是你有没有发现那个登陆只是一个简单的登陆且密码在接口返回的过程中是铭文密码在生产环境中使用肯定是不行的一般密码都是需要加密的要么是MD5加密或者哈希加密接下来我们重构登陆接口一同连登陆页面的风格也进行重构使得风格更加现代化首先设计数据库关联用户表sys_user
CREATE TABLE sys_user (id bigint NOT NULL AUTO_INCREMENT COMMENT 用户ID,username varchar(50) NOT NULL COMMENT 用户名,password varchar(100) NOT NULL COMMENT 密码哈希,name varchar(50) NOT NULL COMMENT 姓名,email varchar(100) DEFAULT NULL COMMENT 邮箱,phone varchar(20) DEFAULT NULL COMMENT 手机号,status tinyint NOT NULL DEFAULT 1 COMMENT 状态(0-禁用,1-正常),create_by bigint NOT NULL COMMENT 创建人ID,created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间,PRIMARY KEY (id),UNIQUE KEY uk_username (username)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户;-- 默认超级管理员 (密码: admin123)
INSERT INTO sys_user (id, username, password, name, email, status, create_by)
VALUES (1, admin, $2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2, 超级管理员, adminexample.com, 1, 1);角色表sys_role
CREATE TABLE sys_role (id bigint NOT NULL AUTO_INCREMENT COMMENT 角色ID,role_name varchar(50) NOT NULL COMMENT 角色名称,role_code varchar(50) NOT NULL COMMENT 角色编码,description varchar(255) DEFAULT NULL COMMENT 角色描述,created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间,PRIMARY KEY (id),UNIQUE KEY uk_role_code (role_code)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT角色表;-- 默认角色
INSERT INTO sys_role (id, role_name, role_code, description)
VALUES (1, 超级管理员, SUPER_ADMIN, 拥有系统所有权限),(2, 普通用户, NORMAL_USER, 拥有基础操作权限);用户角色关联表sys_user_role
CREATE TABLE sys_user_role (id bigint NOT NULL AUTO_INCREMENT COMMENT ID,user_id bigint NOT NULL COMMENT 用户ID,role_id bigint NOT NULL COMMENT 角色ID,created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,PRIMARY KEY (id),UNIQUE KEY uk_user_role (user_id,role_id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户角色关联表;-- 超级管理员关联超级管理员角色
INSERT INTO sys_user_role (user_id, role_id) VALUES (1, 1);菜单表sys_menu
CREATE TABLE sys_menu (id bigint NOT NULL AUTO_INCREMENT COMMENT 菜单ID,parent_id bigint NOT NULL DEFAULT 0 COMMENT 父菜单ID,menu_name varchar(50) NOT NULL COMMENT 菜单名称,path varchar(255) DEFAULT NULL COMMENT 路由路径,component varchar(255) DEFAULT NULL COMMENT 前端组件,icon varchar(50) DEFAULT NULL COMMENT 图标,sort int NOT NULL DEFAULT 0 COMMENT 排序,menu_type tinyint NOT NULL COMMENT 菜单类型(1-目录,2-菜单,3-按钮),permission varchar(100) DEFAULT NULL COMMENT 权限标识,is_show tinyint NOT NULL DEFAULT 1 COMMENT 是否显示(0-隐藏,1-显示),created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间,PRIMARY KEY (id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT菜单表;-- 默认菜单示例
INSERT INTO sys_menu (menu_name, parent_id, path, component, icon, sort, menu_type, permission)
VALUES
(系统管理, 0, /system, Layout, el-icon-setting, 1, 1, NULL),
(用户管理, 1, user, system/user/index, NULL, 1, 2, system:user:list),
(角色管理, 1, role, system/role/index, NULL, 2, 2, system:role:list),
(菜单管理, 1, menu, system/menu/index, NULL, 3, 2, system:menu:list),
(用户查询, 2, NULL, NULL, NULL, 1, 3, system:user:query),
(用户新增, 2, NULL, NULL, NULL, 2, 3, system:user:add),
(用户编辑, 2, NULL, NULL, NULL, 3, 3, system:user:edit),
(用户删除, 2, NULL, NULL, NULL, 4, 3, system:user:delete);角色权限关联表sys_role_menu
CREATE TABLE sys_role_menu (id bigint NOT NULL AUTO_INCREMENT COMMENT ID,role_id bigint NOT NULL COMMENT 角色ID,menu_id bigint NOT NULL COMMENT 菜单ID,created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,PRIMARY KEY (id),UNIQUE KEY uk_role_menu (role_id,menu_id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT角色菜单关联表;-- 超级管理员拥有所有权限
INSERT INTO sys_role_menu (role_id, menu_id) SELECT 1, id FROM sys_menu;我们的密码现在是使用的bcrypt加密所以需要在utils工具中编写JTW用户解密与数据库中的密码进行比对符合账号正确密码正确才能登陆系统
# apis/utils/jwt.py
from functools import wraps
import jwt
from datetime import datetime, timedelta
from flask import current_app, g, request, jsonify
from sqlalchemy import select
from extensions import dbdef generate_token(user_id):生成JWT Tokenexpire datetime.utcnow() timedelta(secondscurrent_app.config[JWT_ACCESS_TOKEN_EXPIRES])payload {exp: expire, sub: user_id}return jwt.encode(payload,current_app.config[JWT_SECRET_KEY],algorithmHS256)def verify_token(token):验证Tokentry:payload jwt.decode(token,current_app.config[JWT_SECRET_KEY],algorithms[HS256])return payload[sub] # 返回用户IDexcept (jwt.ExpiredSignatureError, jwt.InvalidTokenError):return Nonedef login_required(f):登录认证装饰器wraps(f)def decorated_function(*args, **kwargs):# 1. 检查白名单如果有配置whitelist current_app.config.get(PERMISSION_WHITELIST, [])if request.path in whitelist:return f(*args, **kwargs)# 2. 获取Tokentoken request.headers.get(Authorization)if not token or not token.startswith(Bearer ):return jsonify(code401, message未授权访问), 401# 3. 验证Tokenuser_id verify_token(token[7:])if not user_id:return jsonify(code401, messageToken已过期或无效), 401# 4. 检查用户状态sys_user db.metadata.tables[sys_user]user db.session.execute(select(sys_user).where(sys_user.c.id user_id)).first()if not user or user.status ! 1:return jsonify(code401, message用户不存在或已被禁用), 401# 5. 保存用户信息到请求上下文g.user_id user_idg.user dict(user) # 将行转换为字典# 6. 设置到request对象中供admin_required使用request.current_user_id user_idreturn f(*args, **kwargs)return decorated_functiondef admin_required(f):管理员权限装饰器wraps(f)def decorated_function(*args, **kwargs):# 确保先经过login_required认证if not hasattr(request, current_user_id):return jsonify(code401, message请先登录), 401user_id request.current_user_id# 检查用户是否为超级管理员sys_user_role db.metadata.tables[sys_user_role]sys_role db.metadata.tables[sys_role]# 查询用户是否有超级管理员角色is_admin db.session.execute(select(1).select_from(sys_user_role).join(sys_role, sys_user_role.c.role_id sys_role.c.id).where((sys_user_role.c.user_id user_id) (sys_role.c.role_code SUPER_ADMIN) # 使用role_code而不是roleName)).scalar()if not is_admin:return jsonify(code403, message需要管理员权限), 403return f(*args, **kwargs)return decorated_functiondef permission_required(permission):权限校验装饰器def decorator(f):wraps(f)def decorated_function(*args, **kwargs):if not hasattr(g, user_id):return jsonify(code401, message未授权访问), 401# 这里需要根据您的权限系统实现具体的权限检查逻辑# 暂时先返回成功等权限系统完善后再实现return f(*args, **kwargs)return decorated_functionreturn decorator
建立好数据模型menu.py
# models/menu.py
from extensions import db # 从 extensions.py 导入 db而非 from . import dbclass Menu(db.Model):__tablename__ sys_menu # 对应数据库中的 sys_menu 表# __table__ db.metadata.tables[sys_menu] # 直接关联反射表id db.Column(db.BigInteger, primary_keyTrue)parent_id db.Column(db.BigInteger, default0, nullableFalse) # 父菜单IDmenu_name db.Column(db.String(50), nullableFalse) # 菜单名称path db.Column(db.String(255)) # 路由路径component db.Column(db.String(255)) # 前端组件menu_type db.Column(db.SmallInteger, nullableFalse) # 1-目录 2-菜单 3-按钮permission db.Column(db.String(100)) # 权限标识如 system:user:listsort db.Column(db.Integer, default0) # 排序is_show db.Column(db.SmallInteger, default1) # 是否显示relationship.py
# models/relationship.py
from sqlalchemy import Table, Column, BigInteger, ForeignKey
from . import db # 导入你的 db 实例SQLAlchemy# 显式定义 sys_user_role 关联表数据库中已存在的表
sys_user_role Table(sys_user_role, # 数据库表名必须与手动创建的表名一致db.metadata,Column(id, BigInteger, primary_keyTrue),Column(user_id, BigInteger, ForeignKey(sys_user.id), nullableFalse), # 关联 sys_user.idColumn(role_id, BigInteger, ForeignKey(sys_role.id), nullableFalse) # 关联 sys_role.id
)# 显式定义 sys_role_menu 关联表
sys_role_menu Table(sys_role_menu, # 数据库表名必须与手动创建的表名一致db.metadata,Column(id, BigInteger, primary_keyTrue),Column(role_id, BigInteger, ForeignKey(sys_role.id), nullableFalse),Column(menu_id, BigInteger, ForeignKey(sys_menu.id), nullableFalse)
)
role.py
# models/role.py
from extensions import db # 从 extensions.py 导入 db
from .menu import Menu # 导入 Menu 模型此时 Menu 模型已能正确导入 db
from .relationship import sys_role_menu # 导入关联表 Table 对象class Role(db.Model):__tablename__ sys_role# _table__ db.metadata.tables[sys_role] # 直接关联反射表id db.Column(db.BigInteger, primary_keyTrue)role_name db.Column(db.String(50), nullableFalse)role_code db.Column(db.String(50), uniqueTrue, nullableFalse)description db.Column(db.String(255))menus db.relationship(Menu, secondarysys_role_menu, backrefroles) # 直接使用 Menu 类user.py
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from extensions import db # 从 extensions.py 导入 db
from .role import Role # 导入 Role 模型
from .relationship import sys_user_roleclass User(db.Model):__tablename__ sys_user # 使用已设计的用户表id db.Column(db.BigInteger, primary_keyTrue)username db.Column(db.String(50), uniqueTrue, nullableFalse)password db.Column(db.String(100), nullableFalse)name db.Column(db.String(50), nullableFalse)status db.Column(db.SmallInteger, default1, nullableFalse)create_by db.Column(db.BigInteger, nullableFalse)created_at db.Column(db.DateTime, defaultdatetime.utcnow)# 修复多对多关系使用导入的 sys_user_role Table 对象roles db.relationship(Role, secondarysys_user_role, backrefusers) # 直接使用 Role 类def set_password(self, password):self.password generate_password_hash(password)def check_password(self, password):return check_password_hash(self.password, password)重构登陆接口
# -*- coding:utf-8 -*-
import jsonfrom flask import Blueprint
from flask import Blueprint, request, jsonify, g
from models import db
from models.role import Role
from models.user import User
# from utils.jwt import generate_token,login_required
from extensions import db # 导入 db 实例
from utils.jwt import login_requiredapp_user Blueprint(app_user, __name__)# 原有登录接口改造
from sqlalchemy import select
import bcrypt # 导入 bcrypt 库app_user.route(/api/user/login, methods[POST])
def login():data request.get_json()username data.get(username)password data.get(password, ).encode(utf-8) # 前端密码转为 bytes# 1. 反射 sys_user 表并查询用户sys_user db.metadata.tables[sys_user]query select(sys_user).where(sys_user.c.username username)user db.session.execute(query).fetchone()# 2. 基础验证用户存在 状态正常if not user:return jsonify(code40000, message用户不存在), 401 # 用户不存在if user.status ! 1: # 假设 1正常0禁用return jsonify(code40000, message用户禁用), 403 # 用户禁用# 3. bcrypt 密码验证核心修复db_password user.password.encode(utf-8) # 数据库密文转为 bytesif not bcrypt.checkpw(password, db_password): # 验证明文密码与密文是否匹配return jsonify(code40000, message密码错误), 401 # 密码错误# 4. 登录成功生成 Token 等后续逻辑return jsonify(code20000, messagesuccess, data{token: your_token})# 新增用户信息接口
# apis/user.py假设 info 接口代码
app_user.route(/api/user/info, methods[GET])
def get_user_info():token request.args.get(token)# 1. 验证 token省略假设已验证通过# 2. 查询用户信息使用之前反射表的方式sys_user db.metadata.tables[sys_user]user db.session.execute(select(sys_user).where(sys_user.c.username admin)).fetchone()# 3. 构造符合前端预期的响应格式return jsonify({code: 20000, # 成功状态码必须为前端约定的值message: success, # 成功消息data: {name: user.name, # 用户名从数据库获取roles: [admin], # 用户角色根据实际权限获取avatar: https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif # 头像可选}})# 新增用户管理接口管理员创建子账号
app_user.route(/api/system/user, methods[POST])
login_required
def create_user():current_user g.user# 1. 校验管理员权限if not any(role.role_code SUPER_ADMIN for role in current_user.roles):return jsonify(code403, message无权限创建用户), 403# 2. 处理请求数据data request.get_json()new_user User(usernamedata[username],namedata[name],create_bycurrent_user.id)new_user.set_password(data[password]) # 密码加密# 3. 关联角色role_ids data.get(role_ids, [])roles Role.query.filter(Role.id.in_(role_ids)).all()new_user.roles rolesdb.session.add(new_user)db.session.commit()return jsonify(code20000, message用户创建成功)配置文件中需要做如下配置在config中增加配置
# 权限相关配置
JWT_SECRET_KEY your-jwt-secret-key # 已有的 JWT 密钥
JWT_ACCESS_TOKEN_EXPIRES 3600 # Token 有效期 1 小时已有的配置# 添加权限白名单路径无需认证即可访问的接口
PERMISSION_WHITELIST [/api/user/login, # 登录接口必须添加否则无法登录/api/user/register, # 注册接口如果有/api/common/captcha, # 验证码接口如果有# 前端静态资源路径如果需要如 /login.html, /favicon.ico/, /login.html, /favicon.ico
]重启服务后重新登陆系统此时可以成功登录重构登陆页面之前的登陆页面效果如下看着不是很直观我们现在重构下风格--重构前重构后源码如下
templatediv classlogin-container!-- 左侧背景区域 --div classlogin-leftdiv classleft-contentdiv classlogosvg-icon icon-classlogo /img src/assets/logo.gif altR-B平台LOGO classplatform-logospan classlogo-text/span/divh1 classwelcome-text欢迎回来/h1p classwelcome-subtext高效、安全、稳定的RB业务测试平台 简称REBORT/pdiv classfeaturesdiv classfeature-itemsvg-icon icon-classshield classfeature-icon /divh3安全可靠/h3p需求统计管理/p/div/divdiv classfeature-itemsvg-icon icon-classrocket classfeature-icon /divh3高效稳定/h3p99.9%的可用性工具集成自动化/p/div/divdiv classfeature-itemsvg-icon icon-classcustomize classfeature-icon /divh3灵活跳转/h3p环境地址快速跳转/p/div/div/div/divdiv classcopyright© 2025 REBORT平台 版权所有 一切皆有可能/div/div!-- 右侧登录表单区域 --div classlogin-rightdiv classlogin-form-containerdiv classform-headerh2RB-TEST 平台/h2p使用您的账号密码登录系统/p/divel-formrefloginForm:modelloginForm:rulesloginRulesclasslogin-formauto-completeonlabel-positionleftel-form-item propusername classform-itemspan classsvg-containersvg-icon icon-classuser //spanel-inputrefusernamev-modelloginForm.usernameplaceholder请输入用户名nameusernametypetexttabindex1auto-completeon//el-form-itemel-form-item proppassword classform-itemspan classsvg-containersvg-icon icon-classpassword //spanel-input:keypasswordTyperefpasswordv-modelloginForm.password:typepasswordTypeplaceholder请输入密码namepasswordtabindex2auto-completeonkeyup.enter.nativehandleLogin/span classshow-pwd clickshowPwdsvg-icon :icon-classpasswordType password ? eye : eye-open //span/el-form-itemdiv classform-optionsel-checkbox v-modelrememberMe记住我/el-checkboxrouter-link to/forgot-password classforgot-password忘记密码?/router-link/divel-button:loadingloadingtypeprimaryclasslogin-btnclick.native.preventhandleLoginspan v-if!loading登 录/spanspan v-else登录中.../span/el-buttondiv classother-loginp classdividerspan其他登录方式/span/pdiv classsocial-loginel-tooltip content微信登录 placementtopdiv classsocial-icon wechatsvg-icon icon-classwechat //div/el-tooltipel-tooltip content企业微信 placementtopdiv classsocial-icon QYwxsvg-icon icon-classQYwx //div/el-tooltipel-tooltip contentQQ登录 placementtopdiv classsocial-icon QQsvg-icon icon-classQQ //div/el-tooltip/div/divdiv classregister-tip还没有账号? router-link to/register立即注册/router-link/div/el-form/div/div/div
/templatescript
import { validUsername } from /utils/validateexport default {name: Login,data() {const validateUsername (rule, value, callback) {if (!validUsername(value)) {callback(new Error(请输入正确的用户名))} else {callback()}}const validatePassword (rule, value, callback) {if (value.length 6) {callback(new Error(密码长度不能少于6位))} else {callback()}}return {loginForm: {username: ,password: },loginRules: {username: [{ required: true, trigger: blur, validator: validateUsername }],password: [{ required: true, trigger: blur, validator: validatePassword }]},loading: false,passwordType: password,redirect: undefined,rememberMe: false}},watch: {$route: {handler: function(route) {this.redirect route.query route.query.redirect},immediate: true}},methods: {showPwd() {if (this.passwordType password) {this.passwordType } else {this.passwordType password}this.$nextTick(() {this.$refs.password.focus()})},handleLogin() {this.$refs.loginForm.validate(valid {if (valid) {this.loading truethis.$store.dispatch(user/login, this.loginForm).then(() {this.$router.push({ path: this.redirect || / })this.loading false}).catch(() {this.loading false})} else {console.log(error submit!!)return false}})}}
}
/scriptstyle langscss scoped
// 颜色变量 - 统一紫色背景色
$primary-color: #4361ee;
$primary-hover: #3a56d4;
$white: #ffffff;
$light-bg: #f8fafc;
$text-color: #2d3748;
$light-text: #718096;
$border-color: #e2e8f0;
$error-color: #ef4444;
$purple-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); // 统一的紫色渐变
$purple-dark: #5a4ca8; // 深紫色用于装饰元素.login-container {display: flex;min-height: 100vh;width: 100%;background: $purple-gradient; // 容器应用统一渐变背景// 左侧内容区域.login-left {flex: 1;color: $white;padding: 2rem;display: flex;flex-direction: column;justify-content: space-between;position: relative;overflow: hidden;// 装饰元素 - 统一风格::before {content: ;position: absolute;top: 10%;left: 15%;width: 60px;height: 60px;background: rgba(255, 255, 255, 0.1);border-radius: 50%;}::after {content: ;position: absolute;bottom: 15%;right: 20%;width: 120px;height: 120px;background: rgba(255, 255, 255, 0.05);border-radius: 50%;}/* 大LOGO样式 */.platform-logo {width: 300px;height: 300px;object-fit: contain;}.left-content {position: relative;z-index: 2;max-width: 500px;margin: 0 auto;padding: 2rem;.logo {display: flex;align-items: center;margin-bottom: 3rem;.svg-icon {width: 40px;height: 40px;}.logo-text {font-size: 1.5rem;font-weight: bold;margin-left: 0.75rem;}}.welcome-text {font-size: 2.5rem;font-weight: 600;margin-bottom: 1rem;}.welcome-subtext {font-size: 1.125rem;opacity: 0.9;margin-bottom: 3rem;}.features {.feature-item {display: flex;align-items: center;margin-bottom: 1.5rem;.feature-icon {width: 40px;height: 40px;margin-right: 1rem;background: rgba(255, 255, 255, 0.1);border-radius: 8px;padding: 8px;}h3 {font-size: 1.125rem;margin: 0 0 0.25rem;}p {margin: 0;opacity: 0.8;font-size: 0.875rem;}}}}.copyright {position: relative;z-index: 2;text-align: center;font-size: 0.875rem;opacity: 0.7;padding: 1rem;}}// 右侧登录表单区域 - 关键修改移除独立背景色使用容器统一背景.login-right {width: 590px;display: flex;align-items: center;padding: 2rem 1rem;position: relative; // 用于定位装饰元素// 添加与左侧风格一致的装饰元素::before {content: ;position: absolute;top: 20%;right: 30%;width: 60px;height: 60px;background: rgba(255, 255, 255, 0.1);border-radius: 50%;}::after {content: ;position: absolute;bottom: 25%;right: 25%;width: 30px;height: 30px;background: rgba(255, 255, 255, 0.2);border-radius: 50%;}.login-form-container {width: 300%;max-width: 350px; // 表单调整margin: 0 auto;background: $white;padding: 2.5rem 1.5rem;border-radius: 12px;box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);animation: fadeIn 0.5s ease;position: relative;z-index: 2; // 确保表单在装饰元素之上.form-header {margin-bottom: 1.5rem;text-align: center;h2 {font-size: 1.5rem;color: $text-color;margin: 0 0 0.5rem;}p {color: $light-text;margin: 0;font-size: 0.875rem;}}.login-form {.form-item {margin-bottom: 1rem;.el-input {width: 100%;::v-deep .el-input__inner {height: 42px;padding-left: 40px;border-radius: 6px;border: 1px solid $border-color;transition: all 0.3s;:focus {border-color: $primary-color;box-shadow: 0 0 0 2px rgba(67, 97, 238, 0.2);}}}.svg-container {position: absolute;left: 12px;top: 50%;transform: translateY(-50%);color: $light-text;z-index: 2;}.show-pwd {position: absolute;right: 12px;top: 50%;transform: translateY(-50%);color: $light-text;cursor: pointer;z-index: 2;:hover {color: $primary-color;}}}.form-options {display: flex;justify-content: space-between;align-items: center;margin-bottom: 1rem;font-size: 0.8rem;::v-deep .el-checkbox {color: $light-text;}.forgot-password {color: $light-text;font-size: 0.8rem;text-decoration: none;:hover {color: $primary-color;text-decoration: underline;}}}.login-btn {width: 100%;height: 42px;background: $primary-color;border: none;border-radius: 6px;font-size: 0.9rem;font-weight: 500;color: $white;margin-bottom: 1rem;transition: all 0.3s;:hover {background: $primary-hover;}:active {transform: scale(0.98);}}.other-login {margin: 1rem 0;.divider {display: flex;align-items: center;color: $light-text;font-size: 0.7rem;margin: 0.5rem 0;::before, ::after {content: ;flex: 1;height: 1px;background: $border-color;margin: 0 0.5rem;}}.social-login {display: flex;justify-content: center;gap: 1rem;.social-icon {width: 36px;height: 36px;border-radius: 50%;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: all 0.3s;background: $light-bg;.svg-icon {width: 18px;height: 18px;}.wechat {color: #07c160;:hover {background: rgba(7, 193, 96, 0.1);}}.QYwx {color: #2AAB7F;:hover {background: rgba(42, 171, 127, 0.1);}}.QQ {color: $primary-color;:hover {background: rgba(67, 97, 238, 0.1);}}}}}.register-tip {text-align: center;color: $light-text;font-size: 0.8rem;margin-top: 1rem;a {color: $primary-color;text-decoration: none;font-weight: 500;:hover {text-decoration: underline;}}}}}}
}// 动画效果
keyframes fadeIn {from {opacity: 0;transform: translateY(10px);}to {opacity: 1;transform: translateY(0);}
}// 响应式调整
media (max-width: 992px) {.login-container {flex-direction: column;.login-left {display: none;}.login-right {width: 100%;padding: 2rem 1rem;}}
}// 错误状态样式
::v-deep .el-form-item.is-error {.el-input__inner {border-color: $error-color !important;}.svg-container {color: $error-color !important;}
}
/style看看重构后的效果整体效果是不是看上去更加直观好了登陆重构到这里结束