引言:如果要实现一个ai人工助手,我们可以简单参考一下DeepSeek,KiMi,看看里面比较重要的功能有那些:

        登录,注册是使用每一个ai助手必不可少的功能!当然登录,注册里面的功能也不少,比如说:”忘记密码,重置密码“,”用户名和密码的要求设置(用户名不能少于6个字符,密码需要数字加英文字母,而且不能太过简单,并且要输入两遍密码,进行判断)“。

        注册也可以分为用户名注册和邮箱注册,当然你也可以使用(电话号码注册,和微信,QQ扫码登录),但是这些部分需要一些¥,所以在本次零成本的项目中,咱就先不配置。

        Ai的多功能的对话:当用户完成了登录后,就可以使用我们的Ai对话了,里面也会有一些细节的功能,比如说:对于每个用户的历史会话进行保存,可以新建对话,删除对话,当然也可以修改对话的名称(默认是以用户第一次输入的问题,做为对话的名称),对于Ai呢,我们也可以添加联网搜索,深度思考,直接发送文件,语音输入等。

        好~,大概项目的框架我们理清除了,接下来我们就开始将这个项目一步步的写出来。

        最后会附赠源码哟

        写代码项目之前,要把我们的目录先创建好:        

 后端里面主要是一个.env目录和main.py的主文件:

前端里面主要是html,css,还有js:         

最后建好了之后就是这样: 

注册与邮箱登录

注册页面:register.html

前端页面我们先写一个最普通的注册界面:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>注册 - DeepSeek</title>
</head>
<body>
  <div class="header">
    <a class="logo" href="#">
      Ai助手
    </a>
  </div>
  <div class="container">
    <div class="card">
      <div class="card-title">用户注册</div>
      <div class="form-container">
          <label for="username">用户名</label>
          <input class="input-style" type="text" id="username" name="username" placeholder="请输入用户名" required>
          <label for="password">密码</label>
          <input class="input-style" type="password" id="password" name="password" placeholder="请输入密码" required>
          <label for="confirm">确认密码</label>
          <input class="input-style" type="password" id="confirm" name="confirm" placeholder="请再次输入密码" required>
          <button class="btn-style" type="submit" id="zc">注册</button>
      </div>
      <div class="reg-link">
        已有账号?<a href="login.html">返回登录</a>
      </div>
    </div>
  </div>

</body>
</html>

这是一个最普通的注册界面,运行之后:

十分的简陋,所以我们需要给他加样式

注册页面css样式

因为我嫌麻烦所以将html和css写在了一起,并没有将样式写在scc目录下面

 <style>
    :root {
      --primary: #2563eb;
      --background: #f8fafc;
      --input-bg: #f1f5f9;
      --border: #e2e8f0;
      --shadow: 0 4px 24px 0 rgba(0,0,0,0.07);
    }
    body {
      margin: 0;
      font-family: "Inter", "微软雅黑", Arial, sans-serif;
      background: var(--background);
      color: #1e293b;
    }
    .header {
      height: 60px;
      display: flex;
      align-items: center;
      padding: 0 40px;
      background: #ffffffcc;
      box-shadow: 0 1px 6px 0 rgba(0,0,0,0.02);
      position: sticky;
      top: 0;
      backdrop-filter: blur(12px);
    }
    .logo {
      display: flex;
      align-items: center;
      font-weight: 700;
      font-size: 1.3rem;
      color: var(--primary);
      letter-spacing: 1px;
      text-decoration: none;
    }
    .logo svg {
      width: 32px;
      height: 32px;
      margin-right: 8px;
    }
    .container {
      min-height: 85vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 40px 16px 0 16px;
    }
    .card {
      background: #fff;
      border-radius: 18px;
      box-shadow: var(--shadow);
      border: 1px solid var(--border);
      width: 380px;
      max-width: 97vw;
      padding: 36px;
      margin-top: 34px;
      display: flex;
      flex-direction: column;
      gap: 14px;
    }
    .card-title {
      font-size: 1.32rem;
      font-weight: 700;
      margin-bottom: 20px;
      text-align: center;
    }
    form label {
      font-size: 1rem;
      margin-bottom: 6px;
      font-weight: 500;
      display: block;
    }
    .input-style {
      width: 92%;
      padding: 12px 14px;
      border-radius: 11px;
      border: 1.2px solid var(--border);
      background: var(--input-bg);
      font-size: 1.02rem;
      margin-bottom: 16px;
      outline: none;
      transition: border 0.2s;
    }
    .input-style:focus {
      border: 1.5px solid var(--primary);
    }
    .btn-style {
      width: 100%;
      background: var(--primary);
      color: #fff;
      font-size: 1.06rem;
      font-weight: 700;
      border: none;
      border-radius: 11px;
      padding: 13px 0;
      margin-top: 10px;
      cursor: pointer;
      letter-spacing: 1px;
    }
    .btn-style:active {
      background: #1a45b6;
    }
    .reg-link {
      text-align: center;
      font-size: 0.97rem;
      margin-top: 20px;
      color: #64748b;
    }
    .reg-link a {
      color: var(--primary);
      text-decoration: none;
      font-weight: 600;
    }
    @media (max-width: 480px) {
      .card { padding: 16px 6vw; }
    }
  </style>

添加了样式之后我们的注册界面就变的好看多了:

邮箱注册

前面我们不是说还要进行邮箱注册吗?但是这里只有用户注册!

所以我们加一个<div>

<style>
   
 .form-container {
      display: flex;
      flex-direction: column;
      gap: 14px;
    }
    .input-style {
      width: 92%;
      padding: 12px 14px;
      border-radius: 11px;
      border: 1.2px solid var(--border);
      background: var(--input-bg);
      font-size: 1.02rem;
      margin-bottom: 16px;
      outline: none;
      transition: border 0.2s;
    }
    .input-style:focus {
      border: 1.5px solid var(--primary);
    }
    .btn-style {
      width: 100%;
      background: var(--primary);
      color: #fff;
      font-size: 1.06rem;
      font-weight: 700;
      border: none;
      border-radius: 11px;
      padding: 13px 0;
      margin-top: 10px;
      cursor: pointer;
      letter-spacing: 1px;
    }
    .btn-style:active {
      background: #1a45b6;
    }
  </style>
将邮箱注册隐藏 
<!-- 邮箱验证码登录表单 -->
      <div id="login-form" class="form-container" style="display:none;">
          <label for="email-login">邮箱</label>
          <input class="input-style" type="email" id="email-login" name="email-login" placeholder="请输入邮箱">
          <button class="btn-style" type="button" id="get_code_btn">获取验证码</button>
          <label for="code">验证码</label>
          <input class="input-style" type="text" id="code" name="code" placeholder="请输入验证码">
          <button class="btn-style" type="button" id="login_btn">登录</button>
      </div>

提醒:你把这部分代码加上的时候,可不会显示哟!

style="display:none;"

当然这是故意这样设置的,因为我们到时候需要的样式:

这部分的样式是隐藏的,只有你点击邮箱验证码登录时,才会出现,随之注册的<div>就会被隐藏

进行这一步就需要用到js了

通过JavaScript动态显示
document.getElementById('register-tab').addEventListener('click', function() {
  // 显示注册表单
  document.getElementById('register-form').style.display = 'block';
  // 隐藏登录表单
  document.getElementById('login-form').style.display = 'none';
  // 给注册标签添加激活样式
  document.getElementById('register-tab').classList.add('active-tab');
  // 移除登录标签的激活样式
  document.getElementById('login-tab').classList.remove('active-tab');
});
document.getElementById('login-tab').addEventListener('click', function() {
  // 隐藏注册表单
  document.getElementById('register-form').style.display = 'none';
  // 显示登录表单
  document.getElementById('login-form').style.display = 'block';
  // 给登录标签添加激活样式
  document.getElementById('login-tab').classList.add('active-tab');
  // 移除注册标签的激活样式
  document.getElementById('register-tab').classList.remove('active-tab');
});

这是关键性代码 可以进行切换。

细节代码:

注意:有一些细节要注意:

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

    <script src="../js/register.js"></script>

 这是针对移动端网页设计的标签,用于控制视口的行为。确保网页在不同设备上能够正确缩放,使网页宽度等于设备宽度(width=device-width),并且初始缩放比例为1.0(initial-scale=1.0),避免移动端浏览器默认的缩放行为导致页面过小。

引入了axios库,它是一个基于Promise的HTTP客户端,用于浏览器和node.js中。通常用于发送AJAX请求。

在html里面导入js,不然html是无法响应的

到此恭喜你已经完成前端页面,只差js里面的功能了

当然现在你点击是无效的,因为这部分代码我们还没有实现,要在js里面进行功能实现

注册页面js代码

document.addEventListener("DOMContentLoaded", function () {
    let username = document.getElementById("username");
    let password = document.getElementById("password");
    let email = document.getElementById("email");
    let confirm = document.getElementById("confirm");
    let zc = document.getElementById("zc");
}

监听页面加载完成

首先我们将HTML里面的标签id全部拿到,并用变量装起来。
分别对应:用户名输入框、密码输入框、确认密码输入框、注册按钮。

zc.addEventListener("click", function (e) {
        e.preventDefault();
        // 阻止按钮默认提交表单行为

        if(password.value !== confirm.value) {
            alert("两次输入的密码不一致");
            return;
        }

        axios.post("http://127.0.0.1:8000/register", {
            username: username.value,
            password: password.value
        }).then(res => {
            if(res.data.code === 200){
                alert("注册成功");
                window.location.href = "login.html";
            }else{
                alert(res.data.message || "注册失败");
            }
        }).catch(err => {
            alert(err.message);
            console.log(err);
        });
    });
教你一步步学会ai人工智能助手对话(超级详解)
preventDefault(){code: 200, message: "xxx"}

现在我们是完成了最简答的注册,当然我们也可以添加一些限制要求用户名不能少于6个字符,密码需要数字加英文字母且不少于8个,而且不能太过简单

    /* 1. 用户名长度 ≥ 6 */
    if (u.length < 6) {
        alert("用户名不能少于 6 个字符");
        return;
    }

    /* 2. 密码长度 ≥ 8,且必须同时包含数字和英文字母 */
    if (!/^(?=.*[0-9])(?=.*[a-zA-Z]).{8,}$/.test(p)) {
        alert("密码必须包含数字和英文字母,且不少于 8 位");
        return;
    }

    /* 3. 不能过于简单:这里给一个示例黑名单 */
    const weakPwd = ["12345678", "password", "abcdefg", "00000000"];
    if (weakPwd.includes(p.toLowerCase())) {
        alert("密码过于简单,请更换");
        return;
    }

    /* 4. 两次密码一致 */
    if (p !== c) {
        alert("两次输入的密码不一致");
        return;
    }

 邮箱登录js代码

// 邮箱格式验证
        let emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!emailPattern.test(email.value)) {
            alert("请输入有效的邮箱地址");
            return;
        }

// 获取验证码逻辑
    document.getElementById("get_code_btn").addEventListener("click", function() {
        let emailLogin = document.getElementById("email-login").value;

        if (!emailLogin) {
            alert("请输入邮箱!");
            return;
        }

// 发送获取验证码请求
        axios.post("http://127.0.0.1:8000/send_email_code", { email: emailLogin }).then(res => {
            alert(res.data.message);
        }).catch(err => {
            alert("获取验证码失败:" + err.message);
        });
/^[^\s@]+@[^\s@]+\.[^\s@]+$/email.value@.get_code_btnemail-login{ email: emailLogin }http://127.0.0.1:8000/send_email_code

邮箱验证码登录逻辑:

document.getElementById("login_btn").addEventListener("click", function() {
        let emailLogin = document.getElementById("email-login").value;
        let code = document.getElementById("code").value;

        if (!emailLogin || !code) {
            alert("请填写完整信息!");
            return;
        }

        // 发送登录请求
        axios.post("http://127.0.0.1:8000/login_by_code", { email: emailLogin, code: code }).then(res => {
            if(res.data.code === 200) {
                alert("登录成功");
                // 可以存储token或者用户信息,然后跳转
                window.location.href = "../html/chat.html"; // 假设登录成功后跳转到首页
            } else {
                alert(res.data.message || "登录失败");
            }
        }).catch(err => {
            alert("登录请求失败:" + err.message);
            console.log(err);
        });
    });
});
login_btnemailLogincode/login_by_code{ email, code }{ code: 200, message: "ok", token: "..." }{ code: 4xx/5xx, message: "验证码错误" }

好!到此注册页面的前端代码我们已经完成了 接下来我们要开始完成后端的代码了!

后端main.py:

不要忘记,我们是这些用户,密码,邮箱都是用数据库来存储的,所以我们的第一步是创建数据库。

先导入模块:

import os
import sqlite3
from fastapi import FastAPI

初始化 FastAPI 应用:

app = FastAPI()

创建跨域:

给应用添加一个 跨域资源共享中间件,让浏览器不再拦截前端

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有HTTP方法
    allow_headers=["*"],  # 允许所有HTTP头部
)

然后可以开始创建数据库:

连接(不存在则自动创建 users.db)
② 获取游标
③ 建 users 表

④ 建 conversations 表
⑤ 建 messages 表
⑥ 提交事务
⑦ 关闭连接

def init():
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            username TEXT UNIQUE NOT NULL,
            password TEXT NOT NULL,
            email TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS conversations (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER NOT NULL,
            title TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY(user_id) REFERENCES users(id)
        )
    ''')
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS messages (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            conversation_id INTEGER NOT NULL,
            role TEXT,
            content TEXT,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY(conversation_id) REFERENCES conversations(id)
        )
    ''')
    conn.commit()
    conn.close()
init()

 到此我们的数据库已经建好了,接下来就是,开始写后端逻辑代码了

注册页面的后端代码:

class User(BaseModel):
    username: str
    password: str
    email: EmailStr
@app.post('/register')
async def register(user: User):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    try:
        hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())
        cursor.execute('INSERT INTO users (username,password,email) VALUES (?, ? ,?)',
                       (user.username,hashed_password.decode('utf-8'),user.email))
        user_id = cursor.lastrowid
        conn.commit()
        return {
            "code":200,
            "message":"注册成功",
            "data":{
                "id":user_id,
                "username":user.username,
                "email":user.email
            }
        }
    except Exception as e:
        conn.rollback()
        error_msg = str(e)
        if "UNIQUE constraint failed: users.username" in error_msg:
            return {
                "code": 400,
                "message": "用户名已注册,请更换其他用户名",
                "data": {}
            }
        return {
            "code":500,
            "message":"插入数据失败",
            "data":{
                "error":str(e)
            }
        }
    finally:
        conn.close()

根据这个代码,我详细解释一下,FastAPI接口

首先定义根路径 / 的路由操作:
@app.post('/register')
async def register(user: User):
POST /registeruser: UserUserusernamepasswordemail
 连接数据库
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
密码加密(哈希加密)
hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())
bcrypt.decode()
插入用户
cursor.execute(
    'INSERT INTO users (username, password, email) VALUES (?, ?, ?)',
    (user.username, hashed_password.decode(), user.email)
)
user_id = cursor.lastrowid
conn.commit()
?cursor.lastrowididcommit()
return {
    "code": 200,
    "message": "注册成功",
    "data": {
        "id": user_id,
        "username": user.username,
        "email": user.email
    }
}

 接下来,进行一些异常处理的情况

用户名重复
if "UNIQUE constraint failed: users.username" in str(e):
    return {
        "code": 400,
        "message": "用户名已注册,请更换其他用户名",
        "data": {}
    }
其他错误
return {
    "code": 500,
    "message": "插入数据失败",
    "data": { "error": str(e) }
}
对于这段代码的总结:

用户提交 JSON → 密码加盐哈希 → 插入 SQLite → 成功返回 200 & 用户信息,失败返回 400/500 并回滚。

接下来是难点,邮箱的后端代码!

邮箱登录的后端代码

/send_email_code
@app.post("/send_email_code")
async def send_email_code_api(data: EmailCodeRequest):
    email = data.email
    code = generate_code()
    expire = int(time.time()) + 300  # 5分钟有效
    try:
        send_email_code(email, code)
        email_code_cache[email] = (code, expire)
        return {"code": 200, "message": "验证码已发送"}
    except Exception as e:
        print(f"邮件发送失败: {str(e)}")
        return {"code": 500, "message": "邮件发送失败", "detail": str(e)}
创建发送验证码的后端接口,随机生成6位数字/字母,设置5分钟过期时间,调用(一段函数)发送邮件出去,将验证码等放入一个字典,让前端提示:验证码已发送
@app.post("/send_email_code")data: EmailCodeRequestemailcode = generate_code()expire = int(time.time()) + 300send_email_code(email, code)email_code_cache[email] = (code, expire)return {"code": 200, ...}except Exception as e
/login_by_code ——「用验证码登录」 
@app.post("/login_by_code")
async def login_by_code_api(data: EmailCodeLoginRequest):
    email = data.email
    code = data.code
    now = int(time.time())
    if email not in email_code_cache:
        return {"code": 400, "message": "请先获取验证码"}
    right_code, expire = email_code_cache[email]
    if now > expire:
        return {"code": 400, "message": "验证码已过期"}
    if code != right_code:
        return {"code": 400, "message": "验证码错误"}
    # 查找用户,不存在则注册
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    cursor.execute("SELECT id FROM users WHERE email=?", (email,))
    row = cursor.fetchone()
    if not row:
        username = email.split('@')[0]
        cursor.execute('INSERT INTO users (username, password, email) VALUES (?, ?, ?)', (username, '', email))
        user_id = cursor.lastrowid
        conn.commit()

    else:
        user_id = row[0]
    conn.close()
    # 清除验证码
    email_code_cache.pop(email, None)
    return {"code": 200, "message": "登录成功", "data": {"user_id": user_id, "email": email}}

 校验验证码 → 过期/错误直接 400;正确则「找到用户 or 自动注册」→ 返回 200 和用户信息。

@app.post("/login_by_code")data: EmailCodeLoginRequestemailcodenow = int(time.time())if email not in email_code_cachenow > expirecode != right_codeSELECT id FROM users WHERE email=?if not row:username = email.split('@')[0]INSERT INTO users ...email_code_cache.pop(email, None)return {"code": 200, "user_id": ..., "email": ...}
 用 SMTP 协议发送纯文本验证码邮件的函数
def send_email_code(to_email, code):
    smtp_server = "######.com"  # 换成你实际用的
    smtp_port = 465
    from_addr = "#######.com" #换成你的邮箱
    password = "########"  # 注意不是邮箱密码,是SMTP授权码
    msg = MIMEText(f"你的验证码是:{code},5分钟内有效。", "plain", "utf-8")
    msg["Subject"] = "验证码登录"
    msg["From"] = from_addr
    msg["To"] = to_email
    s = smtplib.SMTP_SSL(smtp_server, smtp_port)
    s.login(from_addr, password)
    s.sendmail(from_addr, [to_email], msg.as_string())
    s.quit()
def send_email_code(to_email, code):smtp_server = "######.com"smtp.qq.comsmtpdm.aliyun.comsmtp.163.comsmtp_port = 465from_addr = "#######.com"password = "########"msg = MIMEText(...)"plain"{code}utf-8msg["Subject"] = "验证码登录"msg["From"] / msg["To"]s = smtplib.SMTP_SSL(...)s.login(from_addr, password)s.sendmail(...)s.quit()

到此我们的注册与邮箱登录都已完成!展示! 

注册以后会跳转登录页面

接下来我们开始完成登录界面

登录界面

登录界面:login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>注册 - DeepSeek</title>
</head>
<body>
<div class="header">
      <a class="logo" href="#">
        <svg viewBox="0 0 40 40" fill="none">
          <circle cx="20" cy="20" r="18" fill="#2563eb" opacity="0.15"/>
          <circle cx="20" cy="20" r="12.5" fill="#2563eb" opacity="0.28"/>
          <circle cx="20" cy="20" r="7.5" fill="#2563eb"/>
        </svg>
        Hazelight
      </a>
    </div>
    <div class="container">
      <div class="card">
          <div class="card-title">账号登录</div>
          <div class="form-container" autocomplete="off">
            <label for="username">用户名</label>
            <input class="input-style" type="text" id="username" name="username" placeholder="请输入用户名" required>
            <label for="password">密码</label>
            <input class="input-style" type="password" id="password" name="password" placeholder="请输入密码" required>
            <button class="btn-style" type="button" id="dl">登录</button>
          </div>
          <div class="reg-link">
            没有账号?<a href="register.html">立即注册</a>
          </div>
        </div>
    </div>
</body>
</html>

这是简单的登录界面

 登录界面:login.css

接下来我们给他加上css样式渲染


      :root {
        --primary: #2563eb;
        --background: #f8fafc;
        --input-bg: #f1f5f9;
        --border: #e2e8f0;
        --shadow: 0 4px 24px 0 rgba(0,0,0,0.07);
      }
      body {
        margin: 0;
        font-family: "Inter", "微软雅黑", Arial, sans-serif;
        background: var(--background);
        color: #1e293b;
      }
      .header {
        height: 60px;
        display: flex;
        align-items: center;
        padding: 0 40px;
        background: #ffffffcc;
        box-shadow: 0 1px 6px 0 rgba(0,0,0,0.02);
        position: sticky;
        top: 0;
        backdrop-filter: blur(12px);
      }
      .logo {
        display: flex;
        align-items: center;
        font-weight: 700;
        font-size: 1.3rem;
        color: var(--primary);
        letter-spacing: 1px;
        text-decoration: none;
      }
      .logo svg {
        width: 32px;
        height: 32px;
        margin-right: 8px;
      }
      .container {
        min-height: 85vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 40px 16px 0 16px;
      }
      .card {
        background: #fff;
        border-radius: 18px;
        box-shadow: var(--shadow);
        border: 1px solid var(--border);
        width: 360px;
        max-width: 97vw;
        padding: 36px;
        margin-top: 34px;
        display: flex;
        flex-direction: column;
        gap: 14px;
      }
      .card-title {
        font-size: 1.35rem;
        font-weight: 700;
        margin-bottom: 20px;
        text-align: center;
      }
      form label {
        font-size: 1rem;
        margin-bottom: 6px;
        font-weight: 500;
        display: block;
      }
      .input-style {
        width: 92%;
        padding: 12px 14px;
        border-radius: 11px;
        border: 1.2px solid var(--border);
        background: var(--input-bg);
        font-size: 1.02rem;
        margin-bottom: 16px;
        outline: none;
        transition: border 0.2s;
      }
      .input-style:focus {
        border: 1.5px solid var(--primary);
      }
      .btn-style {
        width: 100%;
        background: var(--primary);
        color: #fff;
        font-size: 1.06rem;
        font-weight: 700;
        border: none;
        border-radius: 11px;
        padding: 13px 0;
        margin-top: 10px;
        cursor: pointer;
        letter-spacing: 1px;
      }
      .btn-style:active {
        background: #1a45b6;
      }
      .reg-link {
        text-align: center;
        font-size: 0.98rem;
        margin-top: 20px;
        color: #64748b;
      }
      .reg-link a {
        color: var(--primary);
        text-decoration: none;
        font-weight: 600;
      }
      @media (max-width: 480px) {
        .card { padding: 16px 6vw; }
      }

经过css渲染之后

界面就变的好看了

 接下来就是让前端的一些功能

登录界面:login.js

document.addEventListener('DOMContentLoaded', function() {
    const username = document.getElementById('username');
    const password = document.getElementById('password');
    const dl = document.getElementById('dl');
    dl.addEventListener('click', function() {
        if(!username.value || !password.value) {
            alert('请输入用户名和密码');
            return;
        }
        axios.post('http://127.0.0.1:8000/login', {
            username: username.value,
            password: password.value
        }).then(res => {
            if(res.data.code === 200){
                alert("登录成功");
                window.location.href = "chat.html";
            }else{
                alert(res.data.message || "登录失败");
            }
        }).catch(err => {
            alert("登录请求失败");
            console.log(err);
        });
    });
});

登录界面的js非常简单,并没有特别难点,将用户密码,传入后端,后端接受后进行判断,成功后就登录成功,失败后就输出登录失败 

登录界面:后端main.py 

接下来进行前后端的交互,后端也是非常的简单

@app.post('/login')
async def login(user: User):
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    try:
        cursor.execute(
            'SELECT id, username, password FROM users WHERE username = ?',
            (user.username,)
        )
        result = cursor.fetchone()
        if result:
            stored_hash = result[2]
            if bcrypt.checkpw(user.password.encode('utf-8'), stored_hash.encode('utf-8')):
                return {
                    "code": 200,
                    "message": "登录成功",
                    "data": {
                        "id": result[0],
                        "username": result[1]
                    }
                }
        return {
            "code": 400,
            "message": "用户名或密码错误",
            "data": {}
        }
    except Exception as e:
        return {
            "code": 500,
            "message": "登录异常",
            "data": {"error": str(e)}
        }
    finally:
        conn.close()

根据用户名查库 → 用 bcrypt 比对密码 → 正确返回 200 + 用户信息,错误返回 400/500,始终关闭数据库连接。

先到这里,我们到时候接着补充