AI助手协助实现Flask网页开发

#『AI先锋杯·14天征文挑战第5期』#

1 Python Flask 框架简介

        Flask 是一个轻量级的 Python Web 框架,基于 Werkzeug WSGI 工具包和 Jinja2 模板引擎。它被设计为简单易用,同时具备高度可扩展性,适合快速开发小型到中型 Web 应用。

1.1 核心特性

  • 轻量级与模块化

        Flask 核心功能简洁,仅包含路由、请求处理和模板渲染等基础功能。其他功能(如数据库支持、表单验证)通过扩展实现,开发者可以按需选择。

  • 内置开发服务器与调试器

        Flask 提供本地开发服务器和交互式调试器,方便快速测试和问题排查。

  • RESTful 请求支持

        默认支持 HTTP 方法(GET/POST/PUT/DELETE),适合构建 RESTful API。

  • Jinja2 模板引擎

        支持模板继承、变量替换和逻辑控制,便于动态生成 HTML。

1.2 基本代码示例

        以下是一个简单的 Flask 应用代码:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return "Hello, Flask!"

if __name__ == '__main__':
    app.run(debug=True)

运行后访问 http://localhost:5000 将显示 "Hello, Flask!"。

1.3 适用场景

  • 原型开发与小规模应用
  • 微服务架构中的独立服务
  • 需要高度自定义的中型项目

        Flask 的灵活性和简洁性使其成为 Python Web 开发的热门选择,尤其适合初学者和需要快速迭代的项目。

2. AI助手协助实现Flask框架开发及代码优化

2.1 AI助手在Flask网页开发中的核心作用

        现代Flask开发中,AI助手能显著提升效率。通过代码生成、调试辅助和自动化测试,开发者可以更专注于业务逻辑而非重复性工作。AI助手能快速生成Flask路由模板、表单验证代码或数据库模型,减少基础代码的编写时间。例如创建用户登录系统时,AI可自动生成基于Flask-Login的完整实现代码。

        AI助手还能解析错误信息并提供修复方案。当出现"404 Not Found"或"500 Internal Server Error"时,它能分析日志并定位问题根源。对于常见错误如循环导入或模板渲染失败,AI能提供针对性解决建议,大幅缩短调试时间。

2.2 关键功能实现方法

        利用AI生成Flask项目基础结构只需明确需求描述。输入"创建包含用户认证和REST API的Flask项目",AI会输出包含蓝本结构、配置文件和依赖列表的完整项目框架。典型输出包括app/init.py的工厂函数、auth/routes.py的登录逻辑以及api/resources.py的端点定义。

        数据库集成方面,AI能生成SQLAlchemy模型定义。描述数据关系如"用户拥有多个博客文章",AI将输出包含外键关系的模型类代码。它还能自动生成迁移脚本,确保数据库模式与模型保持同步。对于复杂查询,AI可优化SQL语句并建议合适的索引策略。

2.3 前端与后端协同开发

                AI助手在模板渲染环节表现突出。给定页面结构和数据需求,它能生成Jinja2模板代码。需要显示用户仪表盘时,AI会创建包含循环语句、条件判断和过滤器链的HTML文件。对Bootstrap集成,AI能建议响应式布局方案并生成对应的CSS类组合。

        异步任务处理中,AI可配置Celery工作队列。描述"需要后台处理图片上传"的任务,AI将生成包含任务定义、队列设置和结果存储的完整实现。对于WebSocket通信,它能快速搭建Flask-SocketIO环境并处理实时事件。

2.4 性能优化与安全加固

        AI工具能分析路由性能瓶颈。输入"/api/data端点响应缓慢",AI会建议添加缓存机制或数据库查询优化。它能识别N+1查询问题并推荐加载策略调整方案。对于高并发场景,AI可指导Gunicorn配置调优和负载均衡设置。

        安全防护方面,AI自动检查常见漏洞。它会标记未过滤的用户输入、缺少CSRF保护的表单以及明文密码存储等问题。AI能生成符合OWASP标准的防护代码,包括参数化查询、内容安全策略和速率限制实现。对于身份验证流程,AI会建议多因素认证集成方案。

2.5 测试与部署自动化

        AI可生成单元测试和集成测试套件。描述"测试用户注册流程",AI将输出包含边界值测试、异常情况处理的测试用例。它能模拟各种HTTP请求并验证响应状态和数据完整性。对于持续集成,AI可配置GitHub Actions工作流实现自动测试和代码质量检查。

        部署环节中,AI能生成Dockerfile和docker-compose.yml文件。根据"部署到AWS ECS"的需求,AI会提供包含健康检查、日志收集和自动扩展的云架构方案。它能指导配置Nginx反向代理和SSL证书安装,确保生产环境的最佳实践。

2.5 实际开发场景应用

        构建电商网站时,AI可快速实现核心功能模块。产品目录页面需要分页显示和搜索过滤,AI会生成包含Flask-SQLAlchemy查询对象的视图函数。购物车功能涉及会话管理,AI将创建安全的cookie处理方案。支付集成方面,AI能建议合适的SDK并处理webhook验证。

        内容管理系统开发中,AI协助实现富文本编辑和媒体上传。它推荐使用Flask-CKEditor扩展并配置云存储后端。对于权限管理,AI生成基于角色的访问控制代码,精确控制不同用户组的操作权限。缓存策略上,AI会按内容类型设计不同的失效机制。

3. 实际案例

        在自动化测试中,通常会用到tkinter, tkinter 是 Python 的标准 GUI(图形用户界面)库,基于 Tk GUI 工具包开发。它提供跨平台支持(Windows/macOS/Linux),通过简单直观的接口实现窗口、按钮、文本框等组件的创建。

        在开发用户界面时,选择Flask(配合HTML/CSS/JavaScript作为前端)替代Tkinter作为GUI解决方案,能带来显著优势:

  1. 跨平台性和可访问性:Tkinter应用通常需要用户在本地安装Python环境和相关依赖,限制了使用场景。而基于Flask的Web应用,通过浏览器访问,可在任何设备(如Windows、macOS、Linux或移动端)上运行,无需额外安装。用户只需输入URL即可访问,大大提升了便捷性和覆盖范围。

  2. 用户界面丰富度和交互性:Tkinter的UI组件相对基础,开发复杂界面(如动态图表或响应式布局)较困难。Flask结合现代Web技术(如HTML5、CSS3和JavaScript框架),允许创建高度定制化、美观的界面,支持动画、实时数据更新和高级交互(如拖拽操作),提升用户体验。

  3. 可扩展性和并发支持:Tkinter应用多为单机版,难以处理多用户并发请求。Flask作为后端框架,可轻松集成数据库(如SQLite或MySQL)和API,支持多用户同时访问,适用于需要分布式部署的场景(如在线工具或企业系统)。此外,Web应用可通过负载均衡扩展,处理高流量。

  4. 维护和部署便捷性:Tkinter应用更新时需重新分发安装包,增加维护成本。Flask应用部署到Web服务器(如Nginx或Apache)后,更新只需修改服务器端代码,用户端自动获取最新版本,简化了迭代和bug修复。

  5. 生态系统和社区支持:Flask拥有庞大的开源社区和丰富插件(如Flask-SQLAlchemy或Flask-WTF),加速开发进程。相比之下,Tkinter的扩展性较弱,新功能实现受限。Web技术也更符合现代开发趋势,便于集成云服务或第三方API。

以下提供一个实际自动化代码生成前端界面开发案例:包括用户登录,账号注册,功能界面:

3.1 app.py

import hashlib
import json
import os
import time
import re

from flask import Flask, render_template, redirect, url_for, flash, session, request, jsonify
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo, ValidationError

# 模拟用户数据库
users_db = {"User":
    {
        'username': "User",
        'password': hashlib.sha256("123".encode()).hexdigest(),
        'phone': ""
    },
}


class RegistrationForm(FlaskForm):
    username = StringField('用户名', validators=[
        DataRequired('用户名不能为空'),
        Length(min=3, max=20, message='用户名长度应在3-20个字符之间')
    ])

    password = PasswordField('密码', validators=[
        DataRequired('密码不能为空'),
        Length(min=8, message='密码至少需要8个字符')
    ])

    confirm_password = PasswordField('确认密码', validators=[
        DataRequired('请确认密码'),
        EqualTo('password', '两次输入的密码不一致')
    ])

    phone = StringField('手机号码')

    agree_terms = BooleanField('同意条款', validators=[DataRequired('您必须同意服务条款才能注册')])

    submit = SubmitField('注册')

    @staticmethod
    def validate_username(username):
        # 检查用户名是否已存在
        if username.data in users_db:
            raise ValidationError('该用户名已被注册,请选择其他用户名')

    @staticmethod
    def validate_password(password):
        # 密码强度验证
        if len(password.data) < 8:
            raise ValidationError('密码长度至少为8个字符')
        if not re.search(r'[A-Z]', password.data):
            raise ValidationError('密码应包含至少一个大写字母')
        if not re.search(r'[a-z]', password.data):
            raise ValidationError('密码应包含至少一个小写字母')
        if not re.search(r'[0-9]', password.data):
            raise ValidationError('密码应包含至少一个数字')

    @staticmethod
    def validate_phone(phone):
        # 手机号验证(可选)
        if phone.data:
            if not re.match(r'^1[3-9]\d{9}$', phone.data):
                raise ValidationError('请输入有效的手机号码')


class CodeGenerateAPP:
    def __init__(self):
        self.app = Flask(__name__)
        self.app.secret_key = 'your_secret_key_here'
        self.users_db = users_db  # 用户数据库
        self.config = self.load_config()

        self.file_attr_mapping = [
            ('demo.c', 'origin_demo_c_file'),
            ('demo.h', 'origin_demo_h_file')
        ]

        # 注册路由
        self.register_routes()

    @staticmethod
    def load_config():
        """加载配置文件"""
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'conf.json'), 'r', encoding='utf-8') as f:
            return json.load(f)

    def register_routes(self):
        """注册所有路由"""

        # 首页
        @self.app.route('/')
        def home():
            return render_template('home.html')

        # 登录页
        @self.app.route('/login', methods=['GET', 'POST'])
        def login():
            error_message = None

            if request.method == 'POST':
                username = request.form['username'].strip()
                password = request.form['password']

                # 检查用户是否已注册
                if username in self.users_db:
                    user = self.users_db[username]

                    # 验证密码
                    input_hash = hashlib.sha256(password.encode()).hexdigest()
                    if input_hash == user['password']:
                        session['username'] = username
                        return redirect(url_for('dashboard'))
                    else:
                        error_message = "密码不正确"
                else:
                    error_message = "当前账户未注册"

            return render_template('login.html',
                                   error_message=error_message,
                                   request=request)

        # 注册页
        @self.app.route('/register', methods=['GET', 'POST'])
        def register():
            if 'username' in session:
                return redirect(url_for('dashboard'))

            form = RegistrationForm()

            if form.validate_on_submit():
                # 创建用户对象
                user = {
                    'username': form.username.data,
                    'password': hashlib.sha256(form.password.data.encode()).hexdigest(),
                    'phone': form.phone.data
                }

                self.users_db[form.username.data] = user
                session['username'] = form.username.data
                flash(f'欢迎 {form.username.data},您已成功注册!', 'success')
                return redirect(url_for('dashboard'))

            if form.errors:
                for field, errors in form.errors.items():
                    for error in errors:
                        flash(f'{error}', 'danger')

            return render_template('register.html', form=form)

        # 主页
        @self.app.route('/dashboard')
        def dashboard():
            if 'username' not in session:
                return redirect(url_for('login'))
            return render_template('dashboard.html',
                                   car_platform_list=self.config['car_platform_list'],
                                   username=session['username'])

        # MCU Project解析
        @self.app.route('/parse_code_project', methods=['POST'])
        def parse_code_project():
            data = request.get_json()
            result = {}
            # 模拟解析原始文件夹的过程

            time.sleep(2)
            if result:
                result['status'] = 'success'
            else:
                result['status'] = 'fail'
            return jsonify(result)

        # 处理生成代码请求
        @self.app.route('/generateEdr', methods=['POST'])
        def generate_edr():
            return self.simulate_processing("Code Generation", 2)

        # 退出登录
        @self.app.route('/logout')
        def logout():
            session.pop('username', None)
            return redirect(url_for('home'))

    @staticmethod
    def save_session_data(data):
        """保存用户数据到session"""
        session['car_platform'] = data.get('car_platform')
        session['over_write_flag'] = data.get('over_write_flag', False)
        session['author'] = data.get('author')
        session['version'] = data.get('version')
        session['changelog'] = data.get('changelog')
        session['code_project_folder'] = data.get('code_project_folder')

        # 保存特定操作的额外数据
        if 'Requirements_Path' in data:
            session['Requirements_Path'] = data.get('Requirements_Path')

    def simulate_processing(self, operation_name, sleep_time):
        """模拟处理过程"""
        data = request.json
        self.save_session_data(data)

        print(f"Received {operation_name} request:")
        for key, value in data.items():
            print(f"{key}: {value}")

        # 模拟处理时间
        time.sleep(sleep_time)

        # 生成模拟输出路径
        output_path = f"D:/output/{operation_name.replace(' ', '_')}_{int(time.time())}.txt"

        return jsonify({
            'status': 'success',
            'message': f'{operation_name} completed successfully!',
            'output_path': output_path
        })

    def run(self, **kwargs):
        """运行Flask应用"""
        self.app.run(**kwargs)


if __name__ == '__main__':
    app = CodeGenerateAPP()
    app.run(debug=True, host='0.0.0.0', port=5002)  # 'localhost'

3.2 templates html模板

3.2.1 home.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>代码生成工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3498db;
            --secondary-color: #2c3e50;
            --accent-color: #e74c3c;
            --light-color: #ecf0f1;
            --dark-color: #34495e;
        }

        body {
            background: linear-gradient(135deg, #1a2980, #26d0ce);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            padding: 20px 0;
        }

        /* 修复UI靠左问题 */
        .container {
            width: 100%;
            max-width: 1400px; /* 增加最大宽度 */
            margin: 0 auto; /* 确保居中 */
            padding: 0 15px;
        }

        .card {
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            border: none;
            transition: all 0.3s ease;
        }

        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);
        }

        .card-header {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            color: white;
            padding: 25px 20px;
            font-weight: 600;
            border: none;
        }

        .card-body {
            padding: 30px;
        }

        .lead {
            font-size: 1.25rem;
            line-height: 1.7;
        }

        .display-4 {
            font-weight: 800;
            letter-spacing: -0.5px;
        }

        .card-title {
            font-weight: 700;
            color: var(--secondary-color);
            margin-bottom: 15px;
        }

        .card-text {
            color: #666;
            line-height: 1.7;
        }

        .animation-container {
            position: relative;
            height: 150px;
            margin-bottom: 30px;
        }

        .floating-icon {
            position: absolute;
            font-size: 3rem;
            color: rgba(255, 255, 255, 0.7);
            animation: float 6s infinite ease-in-out;
        }

        .floating-icon:nth-child(1) {
            top: 10px;
            left: 10%;
            animation-delay: 0s;
        }

        .floating-icon:nth-child(2) {
            top: 40px;
            right: 15%;
            animation-delay: 1s;
        }

        .floating-icon:nth-child(3) {
            bottom: 20px;
            left: 20%;
            animation-delay: 2s;
        }

        .floating-icon:nth-child(4) {
            bottom: 50px;
            right: 25%;
            animation-delay: 3s;
        }

        @keyframes float {
            0% {
                transform: translateY(0px);
            }
            50% {
                transform: translateY(-20px);
            }
            100% {
                transform: translateY(0px);
            }
        }

        /* 安全登录按钮样式 */
        .login-btn-container {
            margin: 30px auto;
            max-width: 500px;
        }

        .login-btn {
            display: block;
            width: 100%;
            padding: 30px;
            text-align: center;
            background: linear-gradient(135deg, #3498db, #1a6fc4);
            color: white;
            border-radius: 15px;
            font-size: 1.8rem;
            font-weight: bold;
            box-shadow: 0 10px 25px rgba(0,0,0,0.2);
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
            border: none;
            cursor: pointer;
            text-decoration: none;
        }

        .login-btn:hover {
            transform: translateY(-7px);
            box-shadow: 0 15px 30px rgba(0,0,0,0.3);
            background: linear-gradient(135deg, #2980b9, #155a8a);
        }

        .login-btn i {
            font-size: 4rem;
            margin-bottom: 20px;
            display: block;
            transition: transform 0.3s ease;
        }

        .login-btn:hover i {
            transform: scale(1.1);
        }

        .login-btn-text {
            font-size: 2.2rem;
            letter-spacing: 1px;
            margin-bottom: 10px;
            display: block;
        }

        .login-btn-subtext {
            font-size: 1.2rem;
            opacity: 0.9;
            font-weight: normal;
        }

        .login-btn::after {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: rgba(255,255,255,0.1);
            transform: rotate(30deg);
            transition: all 0.6s ease;
        }

        .login-btn:hover::after {
            transform: rotate(30deg) translate(20%, 20%);
        }

        .pulse {
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0% {
                box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.7);
            }
            70% {
                box-shadow: 0 0 0 15px rgba(52, 152, 219, 0);
            }
            100% {
                box-shadow: 0 0 0 0 rgba(52, 152, 219, 0);
            }
        }

        .feature-icon {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            width: 100px;
            height: 100px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0 auto 20px;
            font-size: 40px;
            color: white;
            transition: all 0.3s ease;
        }

        .login-btn .feature-icon {
            margin-top: -20px;
            margin-bottom: 30px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-lg-10">
                <div class="card shadow-lg">
                    <div class="card-header text-center">
                        <h1 class="display-4 fw-bold"><i class="fas fa-lock me-2"></i>代码生成工具</h1>
                    </div>
                    <div class="card-body">
                        <div class="animation-container d-none d-md-block">
                            <div class="floating-icon">
                                <i class="fas fa-code"></i>
                            </div>
                            <div class="floating-icon">
                                <i class="fas fa-microchip"></i>
                            </div>
                            <div class="floating-icon">
                                <i class="fas fa-shield-alt"></i>
                            </div>
                            <div class="floating-icon">
                                <i class="fas fa-bolt"></i>
                            </div>
                        </div>

                        <p class="lead text-center text-secondary mb-3">
                            一个基于 Flask 的代码生成工具系统,提供安全、高效的代码生成解决方案
                        </p>

                        <!-- 安全登录按钮 -->
                        <div class="login-btn-container">
                            <a href="{{ url_for('login') }}" class="login-btn pulse">
                                <div class="feature-icon">
                                    <i class="fas fa-user-shield"></i>
                                </div>
                                <span class="login-btn-text">安全登录</span>
                                <span class="login-btn-subtext">点击进入登录页面</span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="row mt-5">
            <div class="col-12 text-center">
                <p class="text-white mb-0">&copy; <span id="currentYear"></span> 代码生成工具 | 版本 1.0.0 | Author: XXXX</p>
                <p class="text-white-50">自动化代码生成平台</p>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 显示当前年份
        document.getElementById('currentYear').textContent = new Date().getFullYear();

        // 添加动画效果
        document.addEventListener('DOMContentLoaded', function() {
            // 安全登录按钮动画
            const loginBtn = document.querySelector('.login-btn');
            setInterval(() => {
                loginBtn.classList.toggle('pulse');
            }, 2000);

            // 功能卡片动画
            const featureCards = document.querySelectorAll('.card');
            featureCards.forEach((card, index) => {
                setTimeout(() => {
                    card.style.opacity = '0';
                    card.style.transform = 'translateY(20px)';
                    
                    setTimeout(() => {
                        card.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
                        card.style.opacity = '1';
                        card.style.transform = 'translateY(0)';
                    }, 100);
                }, 300 * index);
            });
        });
    </script>
</body>
</html>

3.2.2 login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录 - 代码生成工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3498db;
            --secondary-color: #2c3e50;
            --accent-color: #e74c3c;
            --light-color: #ecf0f1;
            --dark-color: #34495e;
        }

        body {
            background: linear-gradient(135deg, #1a2980, #26d0ce);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            padding: 20px 0;
        }

        /* 修复UI靠左问题 */
        .container {
            width: 100%;
            max-width: 1400px; /* 增加最大宽度 */
            margin: 0 auto; /* 确保居中 */
            padding: 0 15px;
        }

        .auth-card {
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            border: none;
            transition: all 0.3s ease;
            background: rgba(255, 255, 255, 0.95);
        }

        .auth-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);
        }

        .card-header {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            color: white;
            padding: 25px 20px;
            font-weight: 600;
            border: none;
        }

        .card-body {
            padding: 30px;
        }

        .form-control {
            border-radius: 8px;
            padding: 12px 15px;
            border: 1px solid #ddd;
            transition: all 0.3s ease;
        }

        .form-control:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 0.25rem rgba(52, 152, 219, 0.25);
        }

        .input-group-text {
            background: #f8f9fa;
            border: 1px solid #ddd;
            border-radius: 8px 0 0 8px;
        }

        .btn-primary {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            border: none;
            padding: 12px 30px;
            font-weight: 600;
            font-size: 18px;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
            border-radius: 8px;
        }

        .btn-primary:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
            background: linear-gradient(135deg, #2980b9, #1a6fc4);
        }

        .btn-outline-primary {
            border: 2px solid var(--primary-color);
            color: var(--primary-color);
            font-weight: 600;
            padding: 12px 30px;
            font-size: 18px;
            transition: all 0.3s ease;
            border-radius: 8px;
        }

        .btn-outline-primary:hover {
            background: var(--primary-color);
            color: white;
            transform: translateY(-3px);
            box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
        }

        .form-label {
            font-weight: 600;
            color: var(--secondary-color);
            margin-bottom: 8px;
        }

        .auth-footer {
            border-top: 1px solid #eee;
            padding-top: 20px;
            margin-top: 20px;
        }

        .password-toggle {
            cursor: pointer;
            background: #f8f9fa;
            border: 1px solid #ddd;
            border-left: none;
            border-radius: 0 8px 8px 0;
            padding: 0 15px;
            display: flex;
            align-items: center;
        }

        .password-toggle:hover {
            background: #e9ecef;
        }

        .alert-danger {
            border-radius: 8px;
            padding: 15px;
            background: linear-gradient(135deg, rgba(231, 76, 60, 0.1), rgba(231, 76, 60, 0.05));
            border: 1px solid rgba(231, 76, 60, 0.2);
        }

        .social-login {
            display: flex;
            justify-content: center;
            gap: 15px;
            margin: 20px 0;
        }

        .social-btn {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            color: white;
            transition: all 0.3s ease;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }

        .social-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 12px rgba(0,0,0,0.15);
        }

        .google-btn {
            background: linear-gradient(135deg, #DB4437, #c5392c);
        }

        .github-btn {
            background: linear-gradient(135deg, #333, #222);
        }

        .microsoft-btn {
            background: linear-gradient(135deg, #0078d7, #0063b1);
        }

        .divider {
            display: flex;
            align-items: center;
            text-align: center;
            margin: 20px 0;
            color: #6c757d;
        }

        .divider::before,
        .divider::after {
            content: '';
            flex: 1;
            border-bottom: 1px solid #dee2e6;
        }

        .divider::before {
            margin-right: 15px;
        }

        .divider::after {
            margin-left: 15px;
        }
        
        .brand-logo {
            text-align: center;
            margin-bottom: 30px;
        }
        
        .brand-logo img {
            height: 60px;
            margin-bottom: 10px;
        }
        
        .remember-forgot {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        
        .form-check-input:checked {
            background-color: var(--primary-color);
            border-color: var(--primary-color);
        }
        
        .modal-content {
            border-radius: 15px;
            overflow: hidden;
        }
        
        .modal-header {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
        }
        
        .password-strength {
            height: 4px;
            background: #eee;
            border-radius: 2px;
            margin-top: 5px;
            overflow: hidden;
        }
        
        .strength-meter {
            height: 100%;
            width: 0;
            background: #e74c3c;
            transition: all 0.3s ease;
        }
        
        .password-hints {
            font-size: 0.85rem;
            color: #6c757d;
            margin-top: 5px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8 col-lg-6">
                <div class="auth-card">
                    <div class="card-header text-center py-4">
                        <h1 class="h3 mb-0"><i class="fas fa-lock me-2"></i>代码生成工具</h1>
                        <p class="mb-0 mt-2">用户登录</p>
                    </div>
                    
                    <div class="card-body p-4">
                        <div class="brand-logo">
                            <i class="fas fa-code fa-3x text-primary mb-2"></i>
                            <h3 class="mb-0">用户登录</h3>
                        </div>
                        
                        <!-- 错误消息容器 -->
                        {% if error_message %}
                        <div class="alert alert-danger d-flex align-items-center mb-4" role="alert">
                            <i class="fas fa-exclamation-circle me-3 fa-2x"></i>
                            <div>
                                <h5 class="alert-heading">登录失败</h5>
                                <p class="mb-0">{{ error_message }}</p>
                            </div>
                        </div>
                        {% endif %}

                        <form action="{{ url_for('login') }}" method="POST" id="loginForm">
                            <input type="hidden" name="next" value="{{ request.args.get('next', '') }}">

                            <div class="mb-4">
                                <label for="username" class="form-label">用户名</label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-user"></i></span>
                                    <input type="text" class="form-control form-control-lg" id="username" name="username"
                                        placeholder="请输入用户名" required autofocus
                                        value="{{ request.form.username if request.form.username else '' }}">
                                </div>
                            </div>

                            <div class="mb-4">
                                <label for="password" class="form-label">密码</label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-lock"></i></span>
                                    <input type="password" class="form-control form-control-lg" id="password" name="password"
                                        placeholder="请输入密码" required>
                                    <span class="password-toggle" id="passwordToggle">
                                        <i class="fas fa-eye"></i>
                                    </span>
                                </div>
                                <div class="password-strength mt-2">
                                    <div class="strength-meter" id="passwordStrength"></div>
                                </div>
                                <div class="password-hints">
                                    密码长度至少8位,包含字母和数字
                                </div>
                            </div>

                            <div class="remember-forgot">
                                <div class="form-check">
                                    <input type="checkbox" class="form-check-input" id="remember" name="remember">
                                    <label class="form-check-label" for="remember">记住我</label>
                                </div>
                                <div>
                                    <a href="#" class="text-decoration-none">忘记密码?</a>
                                </div>
                            </div>

                            <div class="d-grid mb-3">
                                <button type="submit" class="btn btn-primary btn-lg py-3">
                                    <i class="fas fa-sign-in-alt me-2"></i>登录
                                </button>
                            </div>
                            <div class="auth-footer text-center">
                                <p class="text-muted mb-2">还没有账户?</p>
                                <a href="{{ url_for('register') }}" class="btn btn-outline-primary">
                                    <i class="fas fa-user-plus me-2"></i>立即注册
                                </a>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 弹窗模态框 -->
    {% if error_message %}
    <div class="modal fade" id="errorModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-exclamation-triangle me-2"></i>账户未注册</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div class="d-flex align-items-center">
                        <div class="flex-shrink-0 me-3">
                            <i class="fas fa-user-slash text-danger" style="font-size: 2.5rem;"></i>
                        </div>
                        <div class="flex-grow-1">
                            <h5>账户未注册</h5>
                            <p class="mb-0">您输入的账户尚未注册,请先注册新账户</p>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <a href="{{ url_for('register') }}" class="btn btn-primary">
                        <i class="fas fa-user-plus me-1"></i>立即注册
                    </a>
                </div>
            </div>
        </div>
    </div>
    {% endif %}

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 页面加载完成后自动显示错误弹窗
        document.addEventListener('DOMContentLoaded', function() {
            {% if error_message %}
            const errorModal = new bootstrap.Modal(document.getElementById('errorModal'));
            errorModal.show();
            {% endif %}
            
            // 密码显示/隐藏切换
            const passwordToggle = document.getElementById('passwordToggle');
            const passwordInput = document.getElementById('password');
            
            passwordToggle.addEventListener('click', function() {
                const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
                passwordInput.setAttribute('type', type);
                passwordToggle.innerHTML = type === 'password' ? 
                    '<i class="fas fa-eye"></i>' : 
                    '<i class="fas fa-eye-slash"></i>';
            });
            
            // 密码强度检测
            passwordInput.addEventListener('input', function() {
                const password = passwordInput.value;
                let strength = 0;
                
                if (password.length > 0) strength += 20;
                if (password.length >= 8) strength += 20;
                if (/[A-Z]/.test(password)) strength += 20;
                if (/[0-9]/.test(password)) strength += 20;
                if (/[^A-Za-z0-9]/.test(password)) strength += 20;
                
                document.getElementById('passwordStrength').style.width = strength + '%';
                
                // 设置颜色
                const meter = document.getElementById('passwordStrength');
                if (strength < 40) {
                    meter.style.backgroundColor = '#e74c3c';
                } else if (strength < 80) {
                    meter.style.backgroundColor = '#f39c12';
                } else {
                    meter.style.backgroundColor = '#2ecc71';
                }
            });
            
            // 表单提交动画
            const loginForm = document.getElementById('loginForm');
            loginForm.addEventListener('submit', function() {
                const submitBtn = loginForm.querySelector('button[type="submit"]');
                submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>登录中...';
                submitBtn.disabled = true;
            });
        });
    </script>
</body>
</html>

3.2.3 register.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">">
    <title>用户注册 - 代码生成工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3498db;
            --secondary-color: #2c3e50;
            --accent-color: #e74c3c;
            --light-color: #ecf0f1;
            --dark-color: #34495e;
        }

        body {
            background: linear-gradient(135deg, #1a2980, #26d0ce);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            padding: 20px 0;
        }

        /* 修复UI靠左问题 */
        .container {
            width: 100%;
            max-width: 1400px; /* 增加最大宽度 */
            margin: 0 auto; /* 确保居中 */
            padding: 0 15px;
        }

        .auth-card {
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
            border: none;
            transition: all 0.3s ease;
            background: rgba(255, 255, 255, 0.97);
        }

        .auth-card:hover {
            transform: translateY(-7px);
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
        }

        .card-header {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            color: white;
            padding: 25px 20px;
            font-weight: 600;
            border: none;
            text-align: center;
        }

        .card-body {
            padding: 30px;
        }

        .form-control {
            border-radius: 10px;
            padding: 14px 18px;
            border: 1px solid #ddd;
            transition: all 0.3s ease;
            font-size: 1.05rem;
        }

        .form-control:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 0.3rem rgba(52, 152, 219, 0.2);
        }

        .input-group-text {
            background: #f8f9fa;
            border: 1px solid #ddd;
            border-radius: 10px 0 0 10px;
            padding: 0 15px;
            min-width: 50px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .btn-primary {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            border: none;
            padding: 15px 30px;
            font-weight: 600;
            font-size: 1.1rem;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);
            border-radius: 10px;
            letter-spacing: 0.5px;
        }

        .btn-primary:hover {
            transform: translateY(-4px);
            box-shadow: 0 8px 20px rgba(52, 152, 219, 0.4);
            background: linear-gradient(135deg, #2980b9, #1a6fc4);
        }

        .btn-outline-primary {
            border: 2px solid var(--primary-color);
            color: var(--primary-color);
            font-weight: 600;
            padding: 12px 30px;
            font-size: 1rem;
            transition: all 0.3s ease;
            border-radius: 10px;
        }

        .btn-outline-primary:hover {
            background: var(--primary-color);
            color: white;
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);
        }

        .form-label {
            font-weight: 600;
            color: var(--secondary-color);
            margin-bottom: 10px;
            font-size: 1.05rem;
        }

        .auth-footer {
            border-top: 1px solid #eee;
            padding-top: 20px;
            margin-top: 20px;
        }

        .password-toggle {
            cursor: pointer;
            background: #f8f9fa;
            border: 1px solid #ddd;
            border-left: none;
            border-radius: 0 10px 10px 0;
            padding: 0 15px;
            display: flex;
            align-items: center;
            min-width: 50px;
            justify-content: center;
        }

        .password-toggle:hover {
            background: #e9ecef;
        }

        .progress {
            height: 8px;
            border-radius: 4px;
            margin-top: 8px;
        }

        .progress-bar {
            transition: width 0.5s ease;
        }

        .strength-indicator {
            display: flex;
            justify-content: space-between;
            margin-top: 5px;
            font-size: 0.9rem;
        }

        .strength-point {
            flex: 1;
            height: 4px;
            background: #e9ecef;
            border-radius: 2px;
            margin: 0 2px;
        }

        .strength-point.active {
            background: var(--primary-color);
        }

        .password-hints {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 8px;
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }

        .password-hint {
            display: flex;
            align-items: center;
            gap: 5px;
        }

        .hint-icon {
            color: #adb5bd;
            font-size: 0.8rem;
        }

        .hint-icon.valid {
            color: #2ecc71;
        }

        .terms-container {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 15px;
            margin-top: 10px;
            border: 1px solid #eee;
        }

        .terms-scroll {
            max-height: 150px;
            overflow-y: auto;
            padding-right: 10px;
            margin-bottom: 15px;
            font-size: 0.9rem;
            color: #6c757d;
        }

        .form-check-input {
            width: 1.2em;
            height: 1.2em;
            margin-top: 0.2em;
        }

        .form-check-label {
            font-size: 0.95rem;
        }

        .brand-logo {
            text-align: center;
            margin-bottom: 25px;
        }

        .brand-logo i {
            font-size: 2.5rem;
            color: var(--primary-color);
            margin-bottom: 10px;
            display: inline-block;
        }

        .brand-logo h3 {
            font-weight: 700;
            color: var(--secondary-color);
            margin-bottom: 5px;
        }

        .brand-logo p {
            color: #6c757d;
            margin-bottom: 0;
        }

        .password-container {
            position: relative;
        }

        .password-toggle-container {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            z-index: 5;
        }

        @keyframes pulse {
            0% {
                box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.4);
            }
            70% {
                box-shadow: 0 0 0 10px rgba(52, 152, 219, 0);
            }
            100% {
                box-shadow: 0 0 0 0 rgba(52, 152, 219, 0);
            }
        }

        .pulse-animation {
            animation: pulse 2s infinite;
        }

        .submit-btn-container {
            position: relative;
            overflow: hidden;
            border-radius: 10px;
        }

        .submit-btn-container::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: rgba(255, 255, 255, 0.1);
            transform: rotate(30deg);
            transition: all 0.6s ease;
        }

        .submit-btn-container:hover::before {
            transform: rotate(30deg) translate(20%, 20%);
        }

        /* 错误提示样式增强 */
        .invalid-feedback {
            display: none;
            font-size: 0.9rem;
            margin-top: 5px;
            padding: 8px 12px;
            background-color: rgba(231, 76, 60, 0.1);
            border-radius: 8px;
            border-left: 3px solid #e74c3c;
        }

        .is-invalid {
            border-color: #e74c3c !important;
        }

        .is-invalid:focus {
            box-shadow: 0 0 0 0.25rem rgba(231, 76, 60, 0.25) !important;
        }

        .form-check-input.is-invalid {
            border-color: #e74c3c;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8 col-lg-6">
                <div class="auth-card">
                    <div class="card-header py-4">
                        <h3 class="mb-0"><i class="fas fa-user-plus me-2"></i>创建新账户</h3>
                    </div>

                    <div class="card-body p-4">
                        <div class="brand-logo">
                            <i class="fas fa-code"></i>
                            <h3>代码生成工具</h3>
                            <p>创建您的专属账户</p>
                        </div>

                        <form action="{{ url_for('register') }}" method="POST" id="registerForm" novalidate>
                            {{ form.hidden_tag() }}

                            <!-- 用户名 -->
                            <div class="mb-4">
                                <label for="username" class="form-label">用户名</label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-user"></i></span>
                                    <input type="text" class="form-control form-control-lg" id="username" name="username"
                                           placeholder="请输入用户名 (3-20字符)" required
                                           value="{{ request.form.username if request.form.username else '' }}">
                                </div>
                                <div class="invalid-feedback" id="usernameFeedback">
                                    用户名长度应在3-20个字符之间
                                </div>
                            </div>

                            <!-- 密码 -->
                            <div class="mb-4">
                                <label for="password" class="form-label">密码</label>
                                <div class="input-group password-container">
                                    <span class="input-group-text"><i class="fas fa-lock"></i></span>
                                    <input type="password" class="form-control form-control-lg" id="password" name="password"
                                           placeholder="请输入密码 (至少8字符)" required autocomplete="new-password">
                                    <span class="password-toggle" id="passwordToggle">
                                        <i class="fas fa-eye"></i>
                                    </span>
                                </div>

                                <!-- 密码强度指示器 -->
                                <div class="strength-indicator mt-3">
                                    <div class="strength-point" id="strength1"></div>
                                    <div class="strength-point" id="strength2"></div>
                                    <div class="strength-point" id="stre极3"></div>
                                    <div class="strength-point" id="strength4"></div>
                                    <div class="strength-point" id="strength5"></div>
                                </div>

                                <!-- 密码要求提示 -->
                                <div class="password-hints mt-2">
                                    <div class="password-hint" id="lengthHint">
                                        <span class="hint-icon"><i class="fas fa-circle"></i></span>
                                        <span>至少8个字符</span>
                                    </div>
                                    <div class="password-hint" id="numberHint">
                                        <span class="hint-icon"><i class="fas fa-circle"></i></span>
                                        <span>包含数字</span>
                                    </div>
                                    <div class="password-hint" id="letterHint">
                                        <span class="hint-icon"><i class="fas fa-circle"></i></span>
                                        <span>包含字母</span>
                                    </div>
                                </div>
                                <div class="invalid-feedback" id="passwordFeedback">
                                    密码至少需要8个字符,包含字母和数字
                                </div>
                            </div>

                            <!-- 确认密码 -->
                            <div class="mb-4">
                                <label for="confirm_password" class="form-label">确认密码</label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-lock"></i></span>
                                    <input type="password" class="form-control form-control-lg" id="confirm_password"
                                           name="confirm_password" placeholder="请再次输入密码" required>
                                </div>
                                <div class="invalid-feedback" id="confirmPasswordFeedback">
                                    两次输入的密码不一致
                                </div>
                            </div>

                            <!-- 手机号码 - 非必填 -->
                            <div class="mb-4">
                                <label for="phone" class="form-label">
                                    手机号码
                                    <span class="optional-label">(选填)</span>
                                </label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-mobile-alt"></i></span>
                                    <input type="tel" class="form-control form-control-lg" id="phone" name="phone"
                                           placeholder="请输入11位手机号码"
                                           value="{{ request.form.phone if request.form.phone else '' }}">
                                </div>
                                <div class="invalid-feedback" id="phoneFeedback">
                                    请输入有效的手机号码
                                </div>
                            </div>

                            <!-- 条款同意 -->
                            <div class="mb-4">
                                <div class="terms-container">
                                    <h6 class="fw-bold">服务条款</h6>
                                    <div class="terms-scroll">
                                        <p>1. 用户在使用本服务前需仔细阅读本协议,注册成功后即视为同意本协议全部内容。</p>
                                        <p>2. 用户应妥善保管账号和密码,并对利用该账号和密码所进行的一切活动负全部责任。</p>
                                        <p>3. 用户需遵守国家相关法律法规,不得利用本服务进行任何违法或不正当的活动。</p>
                                        <p>4. 本平台尊重并保护所有用户的个人隐私权,不会泄露用户注册资料及保存在本平台中的非公开内容。</p>
                                        <p>5. 本平台保留随时修改本协议条款的权利,修改后的协议一旦公布即有效代替原来的协议。</p>
                                    </div>
                                    <div class="form-check">
                                        <input type="checkbox" class="form-check-input" id="agree_terms" name="agree_terms" required>
                                        <label class="form-check-label" for="agree_terms">
                                            我已阅读并同意 <a href="#" class="text-decoration-none">服务条款</a> 和 <a href="#" class="text-decoration-none">隐私政策</a>
                                        </label>
                                    </div>
                                </div>
                                <div class="invalid-feedback" id="termsFeedback">
                                    您必须同意服务条款才能注册
                                </div>
                            </div>

                            <!-- 注册按钮 - 移除了动画效果 -->
                            <div class="mb-3">
                                <button type="submit" class="btn btn-primary btn-lg w-100 py-3">
                                    <i class="fas fa-user-plus me-2"></i>立即注册
                                </button>
                            </div>

                            <!-- 已有账户 -->
                            <div class="auth-footer text-center">
                                <p class="text-muted mb-2">已有账户?</p>
                                <a href="{{ url_for('login') }}" class="btn btn-outline-primary">
                                    <i class="fas fa-sign-in-alt me-2"></i>立即登录
                                </a>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const form = document.getElementById('registerForm');
            const usernameInput = document.getElementById('username');
            const passwordInput = document.getElementById('password');
            const confirmPasswordInput = document.getElementById('confirm_password');
            const phoneInput = document.getElementById('phone');
            const termsCheckbox = document.getElementById('agree_terms');
            const passwordToggle = document.getElementById('passwordToggle');

            // 显示所有错误信息
            function showAllErrors() {
                // 用户名验证
                if (usernameInput.value.length < 3 || usernameInput.value.length > 20) {
                    usernameInput.classList.add('is-invalid');
                    document.getElementById('usernameFeedback').style.display = 'block';
                }

                // 密码验证
                if (passwordInput.value.length < 8) {
                    passwordInput.classList.add('is-invalid');
                    document.getElementById('passwordFeedback').style.display = 'block';
                }

                // 确认密码验证
                if (passwordInput.value !== confirmPasswordInput.value) {
                    confirmPasswordInput.classList.add('is-invalid');
                    document.getElementById('confirmPasswordFeedback').style.display = '极block';
                }

                // 手机号验证 - 仅当有输入时验证
                if (phoneInput.value.trim() !== '') {
                    const phoneRegex = /^1[3-9]\d{9}$/;
                    if (!phoneRegex.test(phoneInput.value)) {
                        phoneInput.classList.add('is-invalid');
                        document.getElementById('phoneFeedback').style.display = 'block';
                    }
                }

                // 条款同意验证
                if (!termsCheckbox.checked) {
                    termsCheckbox.classList.add('is-invalid');
                    document.getElementById('termsFeedback').style.display = 'block';
                }
            }

            // 密码可见性切换
            passwordToggle.addEventListener('click', function() {
                const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
                passwordInput.setAttribute('type', type);
                passwordToggle.innerHTML = type === 'password' ?
                    '<i class="fas fa-eye"></i>' :
                    '<i class="fas fa-eye-slash"></i>';
            });

            // 密码强度检测和提示
            passwordInput.addEventListener('input', function() {
                const password = this.value;

                // 密码要求检查
                const hasLength = password.length >= 8;
                const hasNumber = /\d/.test(password);
                const hasLetter = /[a-zA-Z]/.test(password);

                // 更新提示图标
                document.getElementById('lengthHint').querySelector('.hint-icon').className =
                    `hint-icon fas ${hasLength ? 'fa-check valid' : 'fa-circle'}`;
                document.getElementById('numberHint').querySelector('.hint-icon').className =
                    `hint-icon fas ${hasNumber ? 'fa-check valid' : 'fa-circle'}`;
                document.getElementById('letterHint').querySelector('.hint-icon').className =
                    `hint-icon fas ${hasLetter ? 'fa-check valid' : 'fa-circle'}`;

                // 密码强度计算
                let strength = 0;
                if (hasLength) strength += 2;
                if (hasNumber) strength += 1;
                if (hasLetter) strength += 1;
                if (password.length > 12) strength += 1;
                if (/[^A-Za-z0-9]/.test(password)) strength += 1;

                // 重置所有强度点
                for (let i = 1; i <= 5; i++) {
                    document.getElementById(`strength${i}`).classList.remove('active');
                }

                // 激活强度点
                for (let i = 1; i <= strength; i++) {
                    document.getElementById(`strength${i}`).classList.add('active');
                }

                // 设置强度点颜色
                if (strength <= 2) {
                    for (let i = 1; i <= 5; i++) {
                        const el = document.getElementById(`strength${i}`);
                        if (el.classList.contains('active')) {
                            el.style.background = '#e74c3c';
                        }
                    }
                } else if (strength <= 4) {
                    for (let i = 1; i <= 5; i++) {
                        const el = document.getElementById(`strength${i}`);
                        if (el.classList.contains('active')) {
                            el.style.background = '#f39c12';
                        }
                    }
                } else {
                    for (let i = 1; i <= 5; i++) {
                        const el = document.getElementById(`strength${i}`);
                        if (el.classList.contains('active')) {
                            el.style.background = '#2ecc71';
                        }
                    }
                }
            });

            // 密码确认验证
            confirmPasswordInput.addEventListener('input', function() {
                if (passwordInput.value !== this.value) {
                    this.classList.add('is-invalid');
                    document.getElementById('confirmPasswordFeedback').style.display = 'block';
                } else {
                    this.classList.remove('is-invalid');
                    document.getElementById('confirmPasswordFeedback').style.display = 'none';
                }
            });

            // 手机号码验证 - 仅当有输入时验证
            phoneInput.addEventListener('input', function() {
                if (this.value.trim() === '') {
                    this.classList.remove('is-invalid');
                    document.getElementById('phoneFeedback').style.display = 'none';
                    return;
                }

                const phoneRegex = /^1[3-9]\d{9}$/;
                if (!phoneRegex.test(this.value)) {
                    this.classList.add('is-invalid');
                    document.getElementById('phoneFeedback').style.display = 'block';
                } else {
                    this.classList.remove('is-invalid');
                    document.getElementById('phoneFeedback').style.display = 'none';
                }
            });

            // 输入时移除错误状态
            const inputs = form.querySelectorAll('input');
            inputs.forEach(input => {
                input.addEventListener('input', function() {
                    this.classList.remove('is-invalid');
                    const feedbackId = this.id + 'Feedback';
                    if (document.getElementById(feedbackId)) {
                        document.getElementById(feedbackId).style.display = 'none';
                    }
                });
            });

            // 条款复选框点击事件
            termsCheckbox.addEventListener('change', function() {
                if (this.checked) {
                    this.classList.remove('is-invalid');
                    document.getElementById('termsFeedback').style.display = 'none';
                }
            });

            // 表单提交验证
            form.addEventListener('submit', function(event) {
                let isValid = true;

                // 用户名验证
                if (usernameInput.value.length < 3 || usernameInput.value.length > 20) {
                    usernameInput.classList.add('is-invalid');
                    document.getElementById('usernameFeedback').style.display = 'block';
                    isValid = false;
                }

                // 密码验证
                if (passwordInput.value.length < 8) {
                    passwordInput.classList.add('is-invalid');
                    document.getElementById('passwordFeedback').style.display = 'block';
                    isValid = false;
                }

                // 确认密码验证
                if (passwordInput.value !== confirmPasswordInput.value) {
                    confirmPasswordInput.classList.add('is-invalid');
                    document.getElementById('confirmPasswordFeedback').style.display = 'block';
                    isValid = false;
                }

                // 手机号验证 - 仅当有输入时验证
                if (phoneInput.value.trim() !== '') {
                    const phoneRegex = /^1[3-9]\d{9}$/;
                    if (!phoneRegex.test(phoneInput.value)) {
                        phoneInput.classList.add('is-invalid');
                        document.getElementById('phoneFeedback').style.display = 'block';
                        isValid = false;
                    }
                }

                // 条款同意验证
                if (!termsCheckbox.checked) {
                    termsCheckbox.classList.add('is-invalid');
                    document.getElementById('termsFeedback').style.display = 'block';
                    isValid = false;
                }

                if (!isValid) {
                    event.preventDefault();
                    event.stopPropagation();

                    // 显示所有错误信息
                    showAllErrors();

                    // 滚动到第一个错误位置
                    const firstError = form.querySelector('.is-invalid');
                    if (firstError) {
                        firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    }
                } else {
                    // 显示加载状态
                    const submitBtn = form.querySelector('button[type="submit"]');
                    submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>注册中...';
                    submitBtn.disabled = true;

                    // 实际提交表单
                    console.log('表单提交中...');
                }
            });
        });
    </script>
</body>
</html>

3.2.4 dashboard.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> Tool Dashboard</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3498db;
            --secondary-color: #2c3e50;
            --accent-color: #e74c3c;
            --light-color: #ecf0f1;
            --dark-color: #34495e;
            --success-color: #2ecc71;
            --warning-color: #f39c12;
            --info-color: #1abc9c;
        }

        body {
            background: linear-gradient(135deg, #1a2980, #26d0ce);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            min-height: 100vh;
            padding: 20px 0;
            color: #333;
            margin: 0;
            overflow-x: hidden;
        }

        /* 修复UI靠左问题 */
        .container {
            width: 100%;
            max-width: 1400px; /* 增加最大宽度 */
            margin: 0 auto; /* 确保居中 */
            padding: 0 15px;
        }

        .dashboard-header {
            background: linear-gradient(135deg, var(--secondary-color), var(--dark-color));
            color: white;
            padding: 25px 0;
            margin-bottom: 30px;
            box-shadow: 0 6px 15px rgba(0,0,0,0.2);
            border-radius: 0 0 20px 20px;
        }

        .logo-container {
            text-align: center;
            margin-bottom: 20px;
        }

        .logo {
            max-width: 120px;
            height: auto;
            filter: drop-shadow(0 0 5px rgba(255,255,255,0.5));
        }

        .section-card {
            border-radius: 15px;
            box-shadow: 0 10px 25px rgba(0,0,0,0.15);
            margin-bottom: 30px;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            border: none;
            background: rgba(255, 255, 255, 0.97);
            overflow: hidden;
            will-change: transform; /* 启用硬件加速 */
        }

        .section-card:hover {
            transform: translateY(-8px);
            box-shadow: 0 15px 35px rgba(0,0,0,0.25);
        }

        .card-header {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            color: white;
            border-radius: 0 !important;
            padding: 18px 25px;
            font-weight: 600;
            border: none;
            font-size: 1.2rem;
        }

        .card-body {
            padding: 30px;
        }

        .form-group {
            margin-bottom: 25px;
        }

        .form-label {
            font-weight: 600;
            color: var(--secondary-color);
            margin-bottom: 10px;
            font-size: 1.05rem;
        }

        .form-control {
            border-radius: 10px;
            padding: 14px 18px;
            border: 1px solid #ddd;
            transition: all 0.3s ease;
            font-size: 1.05rem;
            background: rgba(255, 255, 255, 0.95);
        }

        .form-control:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 0.3rem rgba(52, 152, 219, 0.2);
        }

        .btn-primary {
            background: linear-gradient(135deg, var(--primary-color), #1a6fc4);
            border: none;
            padding: 15px 30px;
            font-weight: 600;
            font-size: 1.1rem;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);
            border-radius: 10px;
            letter-spacing: 0.5px;
        }

        .btn-primary:hover {
            transform: translateY(-4px);
            box-shadow: 0 8px 20px rgba(52, 152, 219, 0.4);
            background: linear-gradient(135deg, #2980b9, #1a6fc4);
        }

        .btn-action {
            width: 100%;
            margin: 10px 0;
            padding: 14px;
            font-weight: 600;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 10px;
            transition: all 0.3s ease;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }

        .btn-action:hover {
            transform: translateY(-3px);
            box-shadow: 0 7px 14px rgba(0,0,0,0.15);
        }

        .btn-action i {
            margin-right: 10px;
            font-size: 1.2rem;
        }

        .btn-success {
            background: linear-gradient(135deg, var(--success-color), #27ae60);
        }

        .btn-secondary {
            background: linear-gradient(135deg, #7f8c8d, #95a5a6);
        }

        .btn-info {
            background: linear-gradient(135deg, var(--info-color), #16a085);
        }

        .btn-warning {
            background: linear-gradient(135deg, var(--warning-color), #e67e22);
        }

        .btn-dark {
            background: linear-gradient(135deg, var(--dark-color), #2c3e50);
        }

        .status-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 8px;
        }

        .status-active {
            background-color: var(--success-color);
            box-shadow: 0 0 8px var(--success-color);
        }

        .status-inactive {
            background-color: var(--accent-color);
        }

        .file-path {
            background-color: var(--light-color);
            padding: 10px 15px;
            border-radius: 8px;
            font-size: 14px;
            margin-top: 8px;
            word-break: break-all;
            border-left: 3px solid var(--primary-color);
        }

        .progress-container {
            height: 8px;
            background-color: #e9ecef;
            border-radius: 4px;
            margin-top: 10px;
            overflow: hidden;
        }

        .progress-bar {
            height: 100%;
            background: linear-gradient(to right, var(--primary-color), #1a6fc4);
            width: 0%;
            transition: width 0.5s ease;
        }

        .section-title {
            color: var(--secondary-color);
            margin-bottom: 25px;
            padding-bottom: 15px;
            border-bottom: 2px solid var(--primary-color);
            font-weight: 600;
            font-size: 1.3rem;
            display: flex;
            align-items: center;
        }

        .tooltip-icon {
            color: var(--primary-color);
            margin-left: 8px;
            cursor: help;
            font-size: 1.1rem;
        }

        .action-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-top: 20px;
        }

        .config-badge {
            background: rgba(52, 152, 219, 0.15);
            color: var(--primary-color);
            border-radius: 20px;
            padding: 8px 15px;
            font-size: 0.95rem;
            display: inline-flex;
            align-items: center;
            margin: 0 8px 8px 0;
            border: 1px solid rgba(52, 152, 219, 0.3);
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }

        .config-badge i {
            margin-right: 8px;
            font-size: 0.9rem;
        }

        .dynamic-badge {
            background: rgba(46, 204, 113, 0.15);
            color: var(--success-color);
            border: 1px solid rgba(46, 204, 113, 0.3);
        }

        .result-panel {
            background: rgba(236, 240, 241, 0.95);
            border-left: 4px solid var(--primary-color);
            padding: 20px;
            margin-top: 25px;
            display: none;
            animation: fadeIn 0.5s;
            border-radius: 10px;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .result-title {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
        }

        .result-icon {
            font-size: 1.8rem;
            margin-right: 15px;
        }

        .success-icon {
            color: var(--success-color);
        }

        .error-icon {
            color: var(--accent-color);
        }

        .project-section {
            margin-top: 30px;
            padding-top: 25px;
            border-top: 1px solid rgba(0,0,0,0.1);
        }

        .input-group .btn {
            border-radius: 0 10px 10px 0;
            padding: 14px 20px;
            font-weight: 600;
        }

        .input-group-text {
            background: #f8f9fa;
            border: 1px solid #ddd;
            border-radius: 10px 0 0 10px;
            padding: 0 15px;
            min-width: 50px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        footer {
            background: linear-gradient(135deg, var(--dark-color), var(--secondary-color));
            color: white;
            text-align: center;
            padding: 25px 0;
            margin-top: 40px;
            border-radius: 20px 20px 0 0;
            box-shadow: 0 -5px 15px rgba(0,0,0,0.1);
        }

        .form-switch .form-check-input {
            width: 3em;
            height: 1.5em;
        }

        .form-switch .form-check-label {
            font-weight: 500;
            color: var(--secondary-color);
            font-size: 1.05rem;
        }

        .action-btn-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
            gap: 15px;
            margin-top: 25px;
        }
    </style>
</head>
<body>
    <div class="dashboard-header">
        <div class="container">
            <h1 class="text-center"> Code Generate Tool </h1>
            <p class="text-center">Automated Code Generation</p>
        </div>
    </div>

    <div class="container">
        <!-- User Info Section -->
        <div class="row mb-4">
            <div class="col-md-6">
                <div class="section-card perf-optimized">
                    <div class="card-header">
                        <i class="fas fa-user-circle me-2"></i>Basic Information
                    </div>
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-6">
                                <div class="form-group">
                                    <label class="form-label">Author</label>
                                    <input type="text" class="form-control" id="authorInput" value="{{ username }}">
                                </div>
                            </div>
                            <div class="col-md-6">
                                <div class="form-group">
                                    <label class="form-label">Version</label>
                                    <input type="text" class="form-control" id="versionInput" value="v2.1.5">
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="form-label">Change Log</label>
                            <textarea class="form-control" id="changeLog" rows="1" placeholder="Fill In Change Log"></textarea>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <div class="form-group">
                                    <label class="form-label">Car Platform</label>
                                    <select class="form-select" id="carPlatformSelect">
                                        {% for platform in car_platform_list %}
                                        <option value="{{ platform }}">{{ platform }}</option>
                                        {% endfor %}
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="form-check form-switch">
                                <!-- 移除 checked 属性 -->
                                <input class="form-check-input" type="checkbox" id="overwriteToggle">
                                <label class="form-check-label" for="overwriteToggle">Overwrite Original Code Files</label>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="col-md-6">
                <div class="section-card perf-optimized">
                    <div class="card-header">
                        <i class="fas fa-cog me-2"></i>Configuration
                    </div>
                    <div class="card-body">
                        <h5 class="section-title"><i class="fas fa-microchip me-2"></i> Configuration</h5>

                        <div id="configBadges" class="mb-4">
                            <span class="config-badge dynamic-badge">
                                <i class="fas fa-car"></i> EVA3
                            </span>
                        </div>

                        <div class="project-section">
                            <div class="form-group">
                                <label class="form-label"> Project Folder</label>
                                <div class="input-group">
                                    <span class="input-group-text"><i class="fas fa-folder"></i></span>
                                    <input type="text" class="form-control" id="codeProjectFolder" placeholder="Select or enter code project folder path">
                                    <button class="btn btn-outline-primary" type="button" id="importProjectFolderBtn">
                                        <i class="fas fa-folder-open folder-icon"></i> Import
                                    </button>
                                </div>
                            </div>
                            <div class="d-grid mt-3">
                                <button class="btn btn-primary perf-optimized" id="CodeProjectParse">
                                    <i class="fas fa-bolt me-2"></i>  Code Parse
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Code Generate Section -->
        <div class="card section-card perf-optimized">
            <div class="card-header">
                <i class="fas fa-car me-2"></i>Code Generate
            </div>
            <div class="card-body">
                <div class="row">
                    <div class="col-md-12">
                        <div class="form-group">
                            <label class="form-label">Requirement Path</label>
                            <div class="input-group">
                                <span class="input-group-text"><i class="fas fa-file-excel"></i></span>
                                <input type="text" class="form-control" id="Requirements_Path" placeholder="Select or Enter Requirement Path">
                                <button class="btn btn-outline-primary" type="button">Import</button>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="d-grid mt-3">
                    <button class="btn btn-primary btn-action perf-optimized" id="generateCodeBtn">
                        <i class="fas fa-file-code"></i> Generate Code
                    </button>
                </div>

                <div class="result-panel perf-optimized" id="edrResult">
                    <div class="result-title">
                        <i class="fas fa-check-circle result-icon success-icon"></i>
                        <h5>Operation Result</h5>
                    </div>
                    <p id="edrResultMessage"></p>
                </div>
            </div>
        </div>
    </div>

    <footer class="bg-dark text-white text-center py-4 mt-5">
        <div class="container">
            <p>&copy; <span id="currentYear"></span> CodeGenerate Tool Dashboard | Version 1.0.0 | Author: XXX</p>
            <p>Automated Code Generation Platform</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 性能优化:减少DOM操作
        const perfOptimizedElements = [
            '.section-card',
            '.btn-action',
            '.progress-bar',
            '.result-panel'
        ];

        // 添加硬件加速类
        document.addEventListener('DOMContentLoaded', function() {
            // 确保所有复选框默认未选中
            document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
                checkbox.checked = false;
            });

            perfOptimizedElements.forEach(selector => {
                document.querySelectorAll(selector).forEach(el => {
                    el.classList.add('perf-optimized');
                });
            });

            // 优化事件委托
            setupEventDelegation();

            // 初始化页面
            initializePage();
        });

        // 事件委托优化(减少事件监听器数量)
        function setupEventDelegation() {
            document.body.addEventListener('click', function(e) {
                // 处理导入按钮
                if (e.target.closest('.btn-outline-primary')) {
                    handleImportButton(e.target);
                    e.stopPropagation();
                }

                // 处理解析按钮
                if (e.target.id === 'CodeProjectParse') {
                    handleProjectParse();
                }

                // 处理其他操作按钮
                const actionButtons = [
                    'generateCodeBtn'
                ];

                if (actionButtons.includes(e.target.id)) {
                    handleActionButton(e.target.id);
                }
            });

            // 下拉框变更事件
            const dropdowns = [
                'carPlatformSelect'
            ];

            dropdowns.forEach(id => {
                document.getElementById(id).addEventListener('change', updateConfigBadges);
            });
        }

        // 页面初始化
        function initializePage() {
            // 获取初始车平台值
            const carPlatform = document.getElementById('carPlatformSelect').value;

            // 添加车平台变更事件监听器
            document.getElementById('carPlatformSelect').addEventListener('change', function() {
                const carPlatform = this.value;
            });
        }

        // 更新配置徽章函数
        function updateConfigBadges() {
            const badgesContainer = document.getElementById('configBadges');
            const carPlatform = document.getElementById('carPlatformSelect').value;

            badgesContainer.innerHTML = `
                <span class="config-badge dynamic-badge">
                    <i class="fas fa-car"></i> ${carPlatform}
                </span>
            `;
        }

        // 处理导入按钮
        function handleImportButton(button) {
            const inputGroup = button.closest('.input-group');
            if (!inputGroup) return;

            const input = inputGroup.querySelector('.form-control');
            if (!input) return;

            // 获取当前路径或默认路径
            let currentPath = input.value.trim();
            if (!currentPath) {
                // 根据输入框ID设置默认路径
                if (input.id === 'ProjectFolder') {
                    currentPath = 'D:/projects';
                }
                // 其他输入框的默认路径...
            }

            // 显示单次确认对话框
            const newPath = prompt('请输入文件路径:', currentPath);
            if (newPath !== null) {
                // 统一使用左斜杠
                const normalizedPath = newPath.replace(/\\/g, '/');
                input.value = normalizedPath;

                // 自动聚焦到输入框
                setTimeout(() => input.focus(), 100);
            }
        }

        // 优化后的项目解析函数
        function handleProjectParse() {
            const projectFolder = document.getElementById('codeProjectFolder').value;

            if (!projectFolder) {
                showAlert('⚠️  Project Folder路径为空!请先导入项目仓库', 'warning');
                document.getElementById('codeProjectFolder').focus();
                return;
            }

            const button = document.getElementById('CodeProjectParse');
            const originalText = button.innerHTML;
            button.innerHTML = `<i class="fas fa-spinner fa-spin"></i> Parsing...`;
            button.disabled = true;

            // 创建进度条容器
            const progressContainer = document.createElement('div');
            progressContainer.className = 'progress-container mt-3';
            progressContainer.innerHTML = `
                <div class="progress" style="height: 10px;">
                    <div id="parseProgress" class="progress-bar progress-bar-striped progress-bar-animated"
                         role="progressbar" style="width: 0%"></div>
                </div>
                <div id="parseStatus" class="text-center small mt-2">初始化解析...</div>
            `;

            // 插入进度条
            const codeSection = document.querySelector('.project-section');
            if (!document.querySelector('.progress-container')) {
                codeSection.appendChild(progressContainer);
            }

            // 使用轻量级进度更新
            const progress = {
                current: 0,
                max: 100,
                interval: setInterval(() => {
                    progress.current += 5;
                    if (progress.current > 100) progress.current = 100;
                    updateProgress(progress.current);

                    if (progress.current === 100) {
                        clearInterval(progress.interval);
                    }
                }, 200)
            };

            // 收集数据
            const data = {
                code_project_folder: projectFolder,
                car_platform: document.getElementById('carPlatformSelect').value,
            };

            // 发送解析请求
            fetch('/parse_code_project', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(result => {
                clearInterval(progress.interval);
                updateProgress(100);

                if (result.status === 'success') {
                    updatePathFields(result);
                    showAlert('✅ 项目解析完成!所有路径已自动填充', 'success');
                } else {
                    showAlert(`❌ 解析失败: ${result.message}`, 'error');
                }

                button.innerHTML = originalText;
                button.disabled = false;
            })
            .catch(error => {
                clearInterval(progress.interval);
                updateProgress(100);
                showAlert(`⚠️ 网络错误: ${error.message}`, 'error');
                button.innerHTML = originalText;
                button.disabled = false;
            });
        }

        // 轻量级进度更新
        function updateProgress(percent) {
            const progressBar = document.getElementById('parseProgress');
            const statusText = document.getElementById('parseStatus');

            if (progressBar) {
                progressBar.style.width = `${percent}%`;
            }
            if (statusText) {
                statusText.textContent = `解析中... ${percent}%`;
            }
        }

        // 更新所有路径输入框
        function updatePathFields(result) {
            const pathMap = {
                'Requirements_Path': 'Requirements_Path'
            };

            for (const [apiKey, fieldId] of Object.entries(pathMap)) {
                if (result[apiKey]) {
                    const inputElement = document.getElementById(fieldId);
                    if (inputElement) {
                        // 统一使用左斜杠
                        const normalizedPath = result[apiKey].replace(/\\/g, '/');
                        inputElement.value = normalizedPath;
                    } else {
                        console.warn(`Element with id '${fieldId}' not found.`);
                    }
                }
            }
        }

        // 轻量级提示
        function showAlert(message, type) {
            // 移除现有提示
            const existingAlert = document.getElementById('globalAlert');
            if (existingAlert) existingAlert.remove();

            const alert = document.createElement('div');
            alert.id = 'globalAlert';
            alert.className = `alert alert-${type === 'error' ? 'danger' : type} fixed-top mx-auto mt-3`;
            alert.style.maxWidth = '600px';
            alert.style.zIndex = '1060';
            alert.innerHTML = `
                <div class="d-flex align-items-center">
                    <i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-triangle'} me-2"></i>
                    <div>${message}</div>
                    <button type="button" class="btn-close ms-auto" data-bs-dismiss="alert"></button>
                </div>
            `;

            document.body.appendChild(alert);

            // 5秒后自动消失
            setTimeout(() => {
                if (alert.parentNode) {
                    alert.parentNode.removeChild(alert);
                }
            }, 5000);
        }

        // 处理按钮操作
        function handleActionButton(buttonId) {
            // 按钮ID到后端端点的映射
            const endpointMap = {
                'generateExtractionBtn': 'generateExtraction',
                'arxmlCheckBtn': 'arxmlCheck',
                'generateDomainBBtn': 'generateDomainB',
                'generateVcodmBtn': 'generateVcodm',
                'generateCaplBtn': 'generateCapl',
                'calculateSocketBtn': 'calculateSocket',
                'generateAdapterBtn': 'generateAdapter',
                'generateOneTruckBtn': 'generateOneTruck',
                'generateServiceManagerBtn': 'generateServiceManager',
                'generateCodeBtn': 'generateEdr'
            };

            const endpoint = endpointMap[buttonId];
            if (!endpoint) {
                console.error(`Unknown button ID: ${buttonId}`);
                return;
            }

            const button = document.getElementById(buttonId);
            const originalText = button.innerHTML;
            const resultPanelId = buttonId.replace('Btn', 'Result');
            const resultPanel = document.getElementById(resultPanelId);

            // 隐藏结果面板
            if (resultPanel) resultPanel.style.display = 'none';

            // 禁用按钮并显示加载动画
            button.innerHTML = `<i class="fas fa-spinner fa-spin"></i> Processing...`;
            button.disabled = true;

            // 收集通用数据
            const data = {
                author: document.getElementById('authorInput').value,
                version: document.getElementById('versionInput').value,
                changelog: document.getElementById('changeLog').value,
                car_platform: document.getElementById('carPlatformSelect').value,
                over_write_flag: document.getElementById('overwriteToggle').checked,
                code_project_folder: document.getElementById('codeProjectFolder').value
            };

            // 添加特定于操作的数据
            if (buttonId === 'generateCodeBtn') {
                Object.assign(data, {
                    Requirements_Path: document.getElementById('Requirements_Path').value
                });
            }

            // 发送到后端
            fetch(`/${endpoint}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(result => {
                // 显示结果
                if (resultPanel) {
                    document.getElementById(`${resultPanelId}Message`).textContent = result.message;
                    if (result.output_path) {
                        const outputPathElement = document.getElementById(`${resultPanelId}OutputPath`);
                        if (outputPathElement) outputPathElement.textContent = result.output_path;
                    }
                    resultPanel.style.display = 'block';
                }

                // 重置按钮
                button.innerHTML = originalText;
                button.disabled = false;
            })
            .catch(error => {
                console.error('Error:', error);

                if (resultPanel) {
                    document.getElementById(`${resultPanelId}Message`).textContent = 'Error: ' + error.message;
                    resultPanel.style.display = 'block';
                }

                // 重置按钮
                button.innerHTML = originalText;
                button.disabled = false;
            });
        }

        // 显示当前年份
        document.getElementById('currentYear').textContent = new Date().getFullYear();
    </script>
</body>
</html>

4 总结

        本文介绍了Python轻量级Web框架Flask及其在实际项目开发中的应用。主要内容包括:

  1. Flask核心特性:轻量模块化设计、内置开发服务器、RESTful支持和Jinja2模板引擎
  2. AI在Flask开发中的应用:代码生成、错误调试、性能优化和安全加固
  3. 实际案例演示:通过用户认证系统展示Flask项目结构,包括app.py主程序、用户注册/登录表单验证和Dashboard界面模板
  4. 技术对比:分析了Flask相较于Tkinter在跨平台性、界面丰富度和可扩展性方面的优势

        案例展示了完整的Flask项目结构,包含路由定义、表单处理、会话管理和前端模板集成,体现了Flask快速开发Web应用的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值