From f6f5a8af7e6c5359e13d7c75172adb0bc6cac555 Mon Sep 17 00:00:00 2001
From: hyb <kk_huangyangbo@163.com>
Date: Fri, 23 Jan 2026 01:53:11 +0000
Subject: [PATCH] feat: 添加用户登录功能、添加注册功能、注册审批功能,参考:注册审批功能测试指南.md、驱动代码模块增加插入其他项目代码功能,驱动代码模块增加插入其他项目代码功能,优化测试报告模块前端布局和美化 - 实现超级用户管理系统用户,可进行增删改查,其他用户只可查看本人的数据,不可进行增删改 - 将Django后台管理中的用户配置相关功能迁移到系统中进行适配、可配置禁用、是否管理员、是否超级用户 - 增加用户管理的分组字段、可直接进行分组操作,实现用户管理即可通过分组配置实现各项目的访问权限 - 实现登录页面注册 - 实现管理员首页点击注册用户审批可实现通过不通过 - 实现未审核用户的登录提示与审核未通过的用户登录提示 - 实现一键插入其他本人可访问项目的脚本代码

---
 测试组/Test_platform/Interface_automation/backend/add_status_field.py                             |  275 +++
 测试组/Test_platform/Interface_automation/backend/scripts/collect_static.py                       |   58 
 测试组/Test_platform/Interface_automation/backend/apps/lunaruser/serializers.py                   |  170 ++
 测试组/Test_platform/Interface_automation/frontend/src/store/state.js                             |    1 
 测试组/Test_platform/Interface_automation/backend/apps/lunaruser/migrations/0003_myuser_status.py |   22 
 测试组/Test_platform/Interface_automation/backend/scripts/README.md                               |  231 +++
 测试组/Test_platform/Interface_automation/backend/scripts/__init__.py                             |    0 
 测试组/Test_platform/Interface_automation/backend/scripts/deploy_init.py                          |  258 +++
 测试组/Test_platform/Interface_automation/frontend/src/pages/user/UserManagementDrawer.vue        |  591 ++++++++
 测试组/Test_platform/Interface_automation/frontend/src/pages/home/components/Header.vue           |  303 ++++
 测试组/Test_platform/Interface_automation/frontend/src/store/mutations.js                         |    4 
 测试组/Test_platform/Interface_automation/backend/scripts/create_groups.py                        |  110 +
 测试组/Test_platform/Interface_automation/backend/check_users.py                                  |  223 +++
 测试组/Test_platform/Interface_automation/backend/scripts/run_migrations.py                       |   43 
 测试组/Test_platform/Interface_automation/backend/backend/utils/permissions.py                    |    3 
 测试组/Test_platform/Interface_automation/backend/apps/lunaruser/urls.py                          |   20 
 测试组/Test_platform/Interface_automation/backend/apps/lunaruser/models.py                        |   13 
 测试组/Test_platform/Interface_automation/backend/backend/settings.py                             |    2 
 测试组/Test_platform/Interface_automation/注册审批功能测试指南.md                                           |  144 ++
 测试组/Test_platform/Interface_automation/backend/scripts/create_admin_user.py                    |  158 ++
 测试组/Test_platform/Interface_automation/backend/DEPLOY.md                                       |  186 ++
 测试组/Test_platform/Interface_automation/frontend/src/pages/user/UserManagement.vue              |  687 +++++++++
 测试组/Test_platform/Interface_automation/frontend/src/pages/login/Login.vue                      |  307 ++++
 测试组/Test_platform/Interface_automation/backend/apps/lunaruser/views.py                         |  236 +++
 测试组/Test_platform/Interface_automation/frontend/src/pages/project/ProjectList.vue              |   29 
 测试组/Test_platform/Interface_automation/frontend/src/api/user.js                                |   37 
 测试组/Test_platform/Interface_automation/frontend/src/restful/api.js                             |   55 
 27 files changed, 4,103 insertions(+), 63 deletions(-)

diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/DEPLOY.md" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/DEPLOY.md"
new file mode 100644
index 0000000..8d3baab
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/DEPLOY.md"
@@ -0,0 +1,186 @@
+# 首次部署说明
+
+## 快速开始(推荐方式)
+
+使用更新后的脚本一键完成所有初始化:
+
+```bash
+cd backend
+python add_status_field.py --init
+```
+
+这将自动完成:
+1. 检查数据库连接
+2. 执行数据库迁移(makemigrations + migrate)
+3. 创建管理员用户(admin/admin123)
+4. 创建默认用户组
+5. 收集静态文件
+
+## 使用 Django 标准命令
+
+如果您更喜欢使用 Django 的标准命令,也可以按以下步骤执行:
+
+```bash
+cd backend
+
+# 1. 生成迁移文件
+python manage.py makemigrations
+
+# 2. 应用迁移
+python manage.py migrate
+
+# 3. 创建管理员用户(交互式)
+python manage.py createsuperuser
+```
+
+## 脚本功能说明
+
+### add_status_field.py - 首次部署初始化脚本
+
+**完整初始化:**
+```bash
+python add_status_field.py --init
+```
+
+**分步执行:**
+```bash
+# 仅执行数据库迁移
+python add_status_field.py --migrate
+
+# 仅创建管理员用户
+python add_status_field.py --create-admin
+
+# 仅创建用户组
+python add_status_field.py --create-groups
+
+# 仅收集静态文件
+python add_status_field.py --collect-static
+```
+
+### check_users.py - 用户管理脚本
+
+**列出所有用户:**
+```bash
+python check_users.py --list
+```
+
+**创建管理员用户:**
+```bash
+python check_users.py --create-admin
+```
+
+**创建测试用户:**
+```bash
+python check_users.py --create-test
+```
+
+**创建用户组:**
+```bash
+python check_users.py --create-groups
+```
+
+**列出所有用户组:**
+```bash
+python check_users.py --list-groups
+```
+
+**一键初始化用户数据:**
+```bash
+python check_users.py --init
+```
+
+## 默认账号信息
+
+**管理员账号:**
+- 用户名: `admin`
+- 密码: `admin123`
+
+⚠️ **重要提示:** 请在首次登录后立即修改默认密码!
+
+**测试账号:**
+- `testuser` / `test123` - 测试用户
+- `developer` / `dev123` - 开发人员
+
+## 部署前准备
+
+1. **配置数据库连接**
+
+编辑 `backend/conf/env.py` 文件:
+
+```python
+DATABASE_NAME = 'your_database_name'
+DATABASE_USER = 'your_database_user'
+DATABASE_PASSWORD = 'your_database_password'
+DATABASE_HOST = 'localhost'
+DATABASE_PORT = '3306'
+```
+
+2. **创建数据库**
+
+在 MySQL 中执行:
+
+```sql
+CREATE DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+```
+
+3. **安装依赖**
+
+```bash
+cd backend
+pip install -r requirements.txt
+```
+
+## 启动服务
+
+**开发环境:**
+```bash
+cd backend
+python manage.py runserver
+```
+
+**生产环境:**
+```bash
+cd backend
+gunicorn backend.wsgi:application -c gunicorn_conf.py
+```
+
+## 数据库表结构
+
+### lunaruser 应用
+- `lunaruser_myuser` - 用户表(包含 phone、show_hosts、name、status 字段)
+
+### lunarlink 应用
+- `project` - 项目信息表
+- `config` - 环境信息表
+- `api` - 接口信息表
+- `case` - 用例信息表
+- `case_step` - 用例步骤表
+- `variables` - 全局变量表
+- `debugtalk` - 驱动代码表
+- `report` - 测试报告表
+- `report_detail` - 测试报告详情表
+- `relation` - 树形结构关系表
+- `visit` - 访问日志表
+- `login_log` - 登录日志表
+
+## 常见问题
+
+### 1. 数据库连接失败
+
+检查 `conf/env.py` 中的数据库配置是否正确,确保数据库已创建且用户有足够的权限。
+
+### 2. 迁移失败
+
+确保数据库表不存在或为空。如果之前有迁移历史,可能需要删除 `migrations` 目录下的迁移文件(保留 `__init__.py`)。
+
+### 3. 静态文件收集失败
+
+确保 `STATIC_ROOT` 目录有写入权限。
+
+### 4. 用户已存在
+
+脚本会自动检测用户是否已存在,如果存在则跳过创建。
+
+## 技术支持
+
+如有问题,请查看项目文档或联系技术支持团队。
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/add_status_field.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/add_status_field.py"
new file mode 100644
index 0000000..96fb74d
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/add_status_field.py"
@@ -0,0 +1,275 @@
+#!/usr/bin/env python
+"""
+首次部署初始化脚本
+
+该脚本用于首次部署系统时执行所有必要的初始化操作,包括:
+1. 检查数据库连接
+2. 执行数据库迁移
+3. 创建管理员用户
+4. 创建默认用户组
+5. 收集静态文件
+
+使用方法:
+    python add_status_field.py --init
+
+或者使用 Django 标准命令:
+    python manage.py makemigrations
+    python manage.py migrate
+    python manage.py createsuperuser
+"""
+
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.core.management import call_command
+from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Group
+
+
+def check_database_connection():
+    """
+    检查数据库连接
+    """
+    print("=" * 60)
+    print("检查数据库连接...")
+    print("=" * 60)
+
+    try:
+        from django.db import connection
+        with connection.cursor() as cursor:
+            cursor.execute("SELECT 1")
+            print("✓ 数据库连接正常")
+            return True
+    except Exception as e:
+        print(f"✗ 数据库连接失败: {e}")
+        print("\n请检查 conf/env.py 中的数据库配置")
+        return False
+
+
+def run_migrations():
+    """
+    执行数据库迁移
+    """
+    print("\n" + "=" * 60)
+    print("执行数据库迁移...")
+    print("=" * 60)
+
+    try:
+        print("\n[1/2] 生成迁移文件...")
+        call_command('makemigrations', verbosity=1)
+        print("✓ 迁移文件生成成功")
+
+        print("\n[2/2] 应用迁移...")
+        call_command('migrate', verbosity=1)
+        print("✓ 数据库迁移成功")
+        return True
+
+    except Exception as e:
+        print(f"✗ 数据库迁移失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+def create_admin_user(username='admin', password='admin123', email='admin@example.com', name='系统管理员'):
+    """
+    创建管理员用户
+    """
+    print("\n" + "=" * 60)
+    print("创建管理员用户...")
+    print("=" * 60)
+
+    User = get_user_model()
+
+    try:
+        user = User.objects.get(username=username)
+        print(f"管理员用户 '{username}' 已存在,跳过创建")
+        print(f"  用户名: {user.username}")
+        print(f"  姓名: {user.name}")
+        print(f"  邮箱: {user.email}")
+        return True
+
+    except User.DoesNotExist:
+        try:
+            user = User.objects.create_superuser(
+                username=username,
+                email=email,
+                password=password
+            )
+            user.name = name
+            user.phone = None
+            user.show_hosts = False
+            user.status = 'approved'
+            user.save()
+
+            print("✓ 管理员用户创建成功")
+            print(f"  用户名: {username}")
+            print(f"  密码: {password}")
+            print(f"  邮箱: {email}")
+            print(f"  姓名: {name}")
+            print("\n⚠️  重要提示: 请在首次登录后修改默认密码!")
+            return True
+
+        except Exception as e:
+            print(f"✗ 创建管理员用户失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+
+
+def create_default_groups():
+    """
+    创建默认用户组
+    """
+    print("\n" + "=" * 60)
+    print("创建默认用户组...")
+    print("=" * 60)
+
+    groups = [
+        {'name': '管理员组', 'description': '拥有所有权限的管理员组'},
+        {'name': '开发人员组', 'description': '开发人员组'},
+        {'name': '测试人员组', 'description': '测试人员组'},
+        {'name': '只读用户组', 'description': '只读用户组'},
+    ]
+
+    created_count = 0
+    for group_info in groups:
+        try:
+            Group.objects.get(name=group_info['name'])
+            print(f"  用户组 '{group_info['name']}' 已存在")
+        except Group.DoesNotExist:
+            try:
+                Group.objects.create(name=group_info['name'])
+                print(f"  ✓ 创建用户组: {group_info['name']}")
+                created_count += 1
+            except Exception as e:
+                print(f"  ✗ 创建用户组 '{group_info['name']}' 失败: {e}")
+
+    print(f"\n✓ 成功创建 {created_count} 个用户组")
+    return True
+
+
+def collect_static_files():
+    """
+    收集静态文件
+    """
+    print("\n" + "=" * 60)
+    print("收集静态文件...")
+    print("=" * 60)
+
+    try:
+        call_command('collectstatic', '--noinput', verbosity=1)
+        print("✓ 静态文件收集成功")
+        return True
+
+    except Exception as e:
+        print(f"✗ 静态文件收集失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+def display_summary():
+    """
+    显示部署摘要
+    """
+    print("\n" + "=" * 60)
+    print("部署摘要")
+    print("=" * 60)
+
+    User = get_user_model()
+
+    print(f"\n用户数量: {User.objects.count()}")
+    print(f"用户组数量: {Group.objects.count()}")
+
+    print("\n默认管理员账号:")
+    print("  用户名: admin")
+    print("  密码: admin123")
+    print("\n⚠️  请在首次登录后立即修改默认密码!")
+
+
+def main():
+    """
+    主函数
+    """
+    import argparse
+
+    parser = argparse.ArgumentParser(description='首次部署初始化脚本')
+    parser.add_argument('--init', action='store_true', help='执行完整的初始化流程')
+    parser.add_argument('--migrate', action='store_true', help='仅执行数据库迁移')
+    parser.add_argument('--create-admin', action='store_true', help='仅创建管理员用户')
+    parser.add_argument('--create-groups', action='store_true', help='仅创建用户组')
+    parser.add_argument('--collect-static', action='store_true', help='仅收集静态文件')
+
+    args = parser.parse_args()
+
+    if args.init:
+        print("\n")
+        print("╔" + "=" * 58 + "╗")
+        print("║" + " " * 10 + "接口自动化平台 - 首次部署初始化" + " " * 13 + "║")
+        print("╚" + "=" * 58 + "╝")
+        print()
+
+        steps = [
+            ("检查数据库连接", check_database_connection),
+            ("执行数据库迁移", run_migrations),
+            ("创建管理员用户", create_admin_user),
+            ("创建默认用户组", create_default_groups),
+            ("收集静态文件", collect_static_files),
+        ]
+
+        failed_steps = []
+
+        for step_name, step_func in steps:
+            if not step_func():
+                failed_steps.append(step_name)
+                print(f"\n✗ '{step_name}' 失败,终止部署")
+                break
+
+        if not failed_steps:
+            display_summary()
+            print("\n" + "=" * 60)
+            print("✓ 部署初始化完成!")
+            print("=" * 60)
+            print("\n系统已准备就绪,可以启动服务:")
+            print("  python manage.py runserver")
+            print()
+            return 0
+        else:
+            print("\n" + "=" * 60)
+            print("✗ 部署初始化失败!")
+            print("=" * 60)
+            print(f"\n失败的步骤: {', '.join(failed_steps)}")
+            return 1
+
+    elif args.migrate:
+        return 0 if run_migrations() else 1
+
+    elif args.create_admin:
+        return 0 if create_admin_user() else 1
+
+    elif args.create_groups:
+        return 0 if create_default_groups() else 1
+
+    elif args.collect_static:
+        return 0 if collect_static_files() else 1
+
+    else:
+        parser.print_help()
+        print("\n使用示例:")
+        print("  python add_status_field.py --init          # 完整初始化")
+        print("  python add_status_field.py --migrate       # 仅迁移数据库")
+        print("  python add_status_field.py --create-admin   # 仅创建管理员")
+        print("\n或使用 Django 标准命令:")
+        print("  python manage.py makemigrations")
+        print("  python manage.py migrate")
+        print("  python manage.py createsuperuser")
+        return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/migrations/0003_myuser_status.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/migrations/0003_myuser_status.py"
new file mode 100644
index 0000000..386876a
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/migrations/0003_myuser_status.py"
@@ -0,0 +1,22 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('lunaruser', '0002_myuser_name'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='myuser',
+            name='status',
+            field=models.CharField(
+                choices=[('pending', '待审核'), ('approved', '已通过'), ('rejected', '未通过')],
+                default='approved',
+                help_text='用户状态',
+                max_length=20,
+                verbose_name='状态'
+            ),
+        ),
+    ]
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/models.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/models.py"
index 0138d52..4a7e376 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/models.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/models.py"
@@ -2,7 +2,6 @@
 from django.contrib.auth.models import AbstractUser
 
 
-# Create your models here.
 class MyUser(AbstractUser):
     """
     使用AbstractUser可以对User进行扩展使用,添加用户自定义的属性
@@ -27,6 +26,18 @@
         null=True,
         help_text="姓名",
     )
+    STATUS_CHOICES = (
+        ('pending', '待审核'),
+        ('approved', '已通过'),
+        ('rejected', '未通过'),
+    )
+    status = models.CharField(
+        verbose_name="状态",
+        max_length=20,
+        choices=STATUS_CHOICES,
+        default='approved',
+        help_text="用户状态",
+    )
 
     class Meta(AbstractUser.Meta):
         pass
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/serializers.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/serializers.py"
index 0f05856..5bcac19 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/serializers.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/serializers.py"
@@ -10,6 +10,7 @@
 
 from rest_framework import serializers
 from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Group
 
 from lunarlink.models import LoginLog
 
@@ -67,3 +68,172 @@
         if attrs['new_password'] != attrs['confirm_password']:
             raise serializers.ValidationError("两次输入的新密码不一致")
         return attrs
+
+
+class UserCreateSerializer(serializers.ModelSerializer):
+    """
+    创建用户序列化
+    """
+    password = serializers.CharField(required=True, min_length=6, max_length=128, write_only=True)
+    confirm_password = serializers.CharField(required=True, max_length=128, write_only=True)
+    groups = serializers.PrimaryKeyRelatedField(
+        many=True,
+        queryset=Group.objects.all(),
+        required=False
+    )
+
+    class Meta:
+        model = User
+        fields = ['id', 'username', 'password', 'confirm_password', 'name', 'phone', 'is_staff', 'is_superuser', 'is_active', 'groups', 'show_hosts']
+
+    def validate(self, attrs):
+        if attrs['password'] != attrs['confirm_password']:
+            raise serializers.ValidationError("两次输入的密码不一致")
+        return attrs
+
+    def create(self, validated_data):
+        validated_data.pop('confirm_password')
+        password = validated_data.pop('password')
+        groups = validated_data.pop('groups', None)
+        user = User(**validated_data)
+        user.set_password(password)
+        user.save()
+        if groups:
+            user.groups.set(groups)
+        return user
+
+
+class UserUpdateSerializer(serializers.ModelSerializer):
+    """
+    更新用户序列化
+    """
+    groups = serializers.PrimaryKeyRelatedField(
+        many=True,
+        queryset=Group.objects.all(),
+        required=False
+    )
+
+    class Meta:
+        model = User
+        fields = ['id', 'username', 'name', 'phone', 'is_staff', 'is_superuser', 'is_active', 'groups', 'show_hosts']
+
+    def update(self, instance, validated_data):
+        groups = validated_data.pop('groups', None)
+        for attr, value in validated_data.items():
+            setattr(instance, attr, value)
+        instance.save()
+        if groups is not None:
+            instance.groups.set(groups)
+        return instance
+
+
+class UserDetailSerializer(serializers.ModelSerializer):
+    """
+    用户详情序列化
+    """
+    groups = serializers.SerializerMethodField()
+    accessible_projects = serializers.SerializerMethodField()
+    status_display = serializers.CharField(source='get_status_display', read_only=True)
+
+    class Meta:
+        model = User
+        fields = ['id', 'username', 'name', 'phone', 'is_staff', 'is_superuser', 'is_active', 'groups', 'show_hosts', 'date_joined', 'last_login', 'accessible_projects', 'status', 'status_display']
+
+    def get_groups(self, obj):
+        return [g.name for g in obj.groups.all()]
+
+    def get_accessible_projects(self, obj):
+        from lunarlink.models import Project
+        user_groups = obj.groups.all()
+        return list(Project.objects.filter(groups__in=user_groups).distinct().values_list("name", flat=True))
+
+
+class UserRegisterSerializer(serializers.ModelSerializer):
+    """
+    用户注册序列化
+    """
+    password = serializers.CharField(required=True, min_length=6, max_length=128, write_only=True)
+    confirm_password = serializers.CharField(required=True, max_length=128, write_only=True)
+    groups = serializers.PrimaryKeyRelatedField(
+        many=True,
+        queryset=Group.objects.all(),
+        required=False
+    )
+
+    class Meta:
+        model = User
+        fields = ['username', 'password', 'confirm_password', 'name', 'phone', 'groups']
+        extra_kwargs = {
+            'username': {'validators': []},
+            'phone': {'validators': []}
+        }
+
+    def validate_username(self, value):
+        existing_user = User.objects.filter(username=value).first()
+        if existing_user and existing_user.status != 'rejected':
+            raise serializers.ValidationError("用户名已存在")
+        return value
+
+    def validate_phone(self, value):
+        if value:
+            existing_user = User.objects.filter(phone=value).first()
+            if existing_user and existing_user.status != 'rejected':
+                raise serializers.ValidationError("手机号已存在")
+        return value
+
+    def validate(self, attrs):
+        if attrs['password'] != attrs['confirm_password']:
+            raise serializers.ValidationError("两次输入的密码不一致")
+        return attrs
+
+    def create(self, validated_data):
+        validated_data.pop('confirm_password')
+        password = validated_data.pop('password')
+        groups = validated_data.pop('groups', None)
+        
+        username = validated_data['username']
+        phone = validated_data.get('phone')
+        
+        existing_user = User.objects.filter(username=username).first()
+        if existing_user and existing_user.status == 'rejected':
+            user = existing_user
+            user.name = validated_data.get('name', user.name)
+            user.phone = phone
+            user.set_password(password)
+            user.status = 'pending'
+            user.is_active = False
+            user.save()
+            if groups:
+                user.groups.set(groups)
+            return user
+        
+        if phone:
+            existing_phone_user = User.objects.filter(phone=phone).first()
+            if existing_phone_user and existing_phone_user.status == 'rejected':
+                user = existing_phone_user
+                user.username = username
+                user.name = validated_data.get('name', user.name)
+                user.set_password(password)
+                user.status = 'pending'
+                user.is_active = False
+                user.save()
+                if groups:
+                    user.groups.set(groups)
+                return user
+        
+        user = User(**validated_data)
+        user.set_password(password)
+        user.status = 'pending'
+        user.is_active = False
+        user.save()
+        if groups:
+            user.groups.set(groups)
+        return user
+
+
+class UserApprovalSerializer(serializers.Serializer):
+    """
+    用户审批序列化
+    """
+    action = serializers.ChoiceField(choices=['approve', 'reject'])
+    reason = serializers.CharField(required=False, allow_blank=True, max_length=500)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/urls.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/urls.py"
index 6016ba7..8ab6853 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/urls.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/urls.py"
@@ -1,22 +1,20 @@
-# -*- coding: utf-8 -*-
-"""
-@File    : urls.py
-@Time    : 2023/1/13 16:09
-@Author  : geekbing
-@LastEditTime : -
-@LastEditors : -
-@Description : 接口路径
-"""
-
-from django.urls import path
+from django.urls import path, include
+from rest_framework.routers import DefaultRouter
 from lunaruser import views
+
+router = DefaultRouter()
+router.register(r'management', views.UserManagementViewSet, basename='user-management')
+router.register(r'approval', views.UserApprovalViewSet, basename='user-approval')
 
 urlpatterns = [
     path("login", views.LoginView.as_view()),
+    path("register", views.RegisterView.as_view()),
     path("list", views.UserView.as_view()),
     path(
         "login_log",
         views.LoginLogView.as_view({"get": "list"}),
     ),
     path('change_password/', views.ChangePasswordView.as_view(), name='change_password'),
+    path('groups', views.GroupListView.as_view(), name='group-list'),
+    path('', include(router.urls)),
 ]
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/views.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/views.py"
index 4d6fa9b..c75e23e 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/views.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/apps/lunaruser/views.py"
@@ -4,11 +4,15 @@
 from rest_framework_jwt.settings import api_settings
 from rest_framework.response import Response
 from rest_framework.views import APIView
-from rest_framework.viewsets import GenericViewSet
+from rest_framework.viewsets import GenericViewSet, ModelViewSet
+from rest_framework.decorators import action
 from drf_yasg.utils import swagger_auto_schema
 from rest_framework import status
 from rest_framework.permissions import IsAuthenticated
+from rest_framework.filters import SearchFilter
 from backend.utils.auth import MyJWTAuthentication
+from backend.utils.permissions import CustomIsAdminUser
+import logging
 
 from backend.utils.request_util import save_login_log
 from lunarlink.models import LoginLog
@@ -43,16 +47,33 @@
         except KeyError:
             return Response(response.KEY_MISS)
 
-        user = authenticate(username=username, password=password)
-
-        if user is None:
+        try:
+            user = User.objects.get(username=username)
+        except User.DoesNotExist:
             return Response(response.LOGIN_FAILED)
 
-        # 0后面还需要优化定义明确
+        if not user.check_password(password):
+            return Response(response.LOGIN_FAILED)
+
+        if hasattr(user, 'status') and user.status == 'pending':
+            return Response({
+                "success": False,
+                "msg": "你提交的注册还在审批中,暂时无法登录,可联系管理员确认!"
+            }, status=status.HTTP_403_FORBIDDEN)
+
+        if hasattr(user, 'status') and user.status == 'rejected':
+            return Response({
+                "success": False,
+                "msg": "你的注册申请未通过审核,无法登录!"
+            }, status=status.HTTP_403_FORBIDDEN)
+
         if user.is_active == 0:
             return Response(response.USER_BLOCKED)
 
-        # JWT token creation
+        from django.utils import timezone
+        user.last_login = timezone.now()
+        user.save(update_fields=['last_login'])
+
         jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
         jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
 
@@ -65,6 +86,7 @@
                 "user": user.username,
                 "name": user.name,
                 "is_superuser": user.is_superuser,
+                "is_staff": user.is_staff,
                 "show_hosts": user.show_hosts,
                 "token": token,
             }
@@ -144,3 +166,205 @@
                 "success": False,
                 "msg": str(e)
             }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class UserManagementViewSet(ModelViewSet):
+    """
+    用户管理视图集
+    超级用户可以管理所有用户,普通用户只能查看自己的信息
+    """
+    authentication_classes = [MyJWTAuthentication]
+    permission_classes = [IsAuthenticated]
+    pagination_class = None
+    filter_backends = [SearchFilter]
+    search_fields = ['username', 'name']
+
+    def get_queryset(self):
+        if self.request.user.is_superuser:
+            return User.objects.filter(status='approved').prefetch_related('groups')
+        else:
+            return User.objects.filter(id=self.request.user.id).prefetch_related('groups')
+
+    def get_serializer_class(self):
+        if self.action == 'create':
+            return serializers.UserCreateSerializer
+        elif self.action in ['update', 'partial_update']:
+            return serializers.UserUpdateSerializer
+        else:
+            return serializers.UserDetailSerializer
+
+    def get_permissions(self):
+        if self.action in ['create', 'update', 'partial_update', 'destroy']:
+            self.permission_classes = [IsAuthenticated, CustomIsAdminUser]
+        return super().get_permissions()
+
+    def create(self, request, *args, **kwargs):
+        try:
+            return super().create(request, *args, **kwargs)
+        except Exception as e:
+            import logging
+            logger = logging.getLogger(__name__)
+            logger.error(f"创建用户失败: {str(e)}", exc_info=True)
+            return Response({
+                "success": False,
+                "msg": f"创建用户失败: {str(e)}"
+            }, status=status.HTTP_400_BAD_REQUEST)
+
+    def update(self, request, *args, **kwargs):
+        try:
+            return super().update(request, *args, **kwargs)
+        except Exception as e:
+            import logging
+            logger = logging.getLogger(__name__)
+            logger.error(f"更新用户失败: {str(e)}", exc_info=True)
+            return Response({
+                "success": False,
+                "msg": f"更新用户失败: {str(e)}"
+            }, status=status.HTTP_400_BAD_REQUEST)
+
+    def perform_create(self, serializer):
+        serializer.save()
+
+    def perform_update(self, serializer):
+        serializer.save()
+
+    def perform_destroy(self, instance):
+        instance.delete()
+
+
+class RegisterView(APIView):
+    """
+    用户注册视图
+    """
+
+    authentication_classes = ()
+    permission_classes = ()
+
+    @swagger_auto_schema(request_body=serializers.UserRegisterSerializer)
+    def post(self, request):
+        """
+        用户注册
+        {
+            username: str
+            password: str
+            confirm_password: str
+            name: str
+            phone: str
+            groups: list (optional)
+        }
+        """
+        serializer = serializers.UserRegisterSerializer(data=request.data)
+        if not serializer.is_valid():
+            return Response({
+                "success": False,
+                "msg": serializer.errors
+            }, status=status.HTTP_400_BAD_REQUEST)
+
+        try:
+            user = serializer.save()
+            return Response({
+                "success": True,
+                "msg": "你的注册申请已提交,待管理员审核中!",
+                "data": {
+                    "id": user.id,
+                    "username": user.username
+                }
+            }, status=status.HTTP_201_CREATED)
+        except Exception as e:
+            import logging
+            logger = logging.getLogger(__name__)
+            logger.error(f"注册失败: {str(e)}", exc_info=True)
+            return Response({
+                "success": False,
+                "msg": f"注册失败: {str(e)}"
+            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class UserApprovalViewSet(ModelViewSet):
+    """
+    用户审批视图集
+    """
+    authentication_classes = [MyJWTAuthentication]
+    permission_classes = [IsAuthenticated]
+    pagination_class = None
+    filter_backends = [SearchFilter]
+    search_fields = ['username', 'name']
+
+    def get_queryset(self):
+        if self.request.user.is_superuser or self.request.user.is_staff:
+            return User.objects.filter(status='pending').prefetch_related('groups')
+        else:
+            return User.objects.none()
+
+    def get_serializer_class(self):
+        return serializers.UserDetailSerializer
+
+    def list(self, request, *args, **kwargs):
+        queryset = self.get_queryset()
+        serializer = self.get_serializer(queryset, many=True)
+        return Response({
+            "success": True,
+            "results": serializer.data
+        })
+
+    @swagger_auto_schema(request_body=serializers.UserApprovalSerializer)
+    @action(detail=True, methods=['post'])
+    def approve(self, request, pk=None):
+        """
+        审批用户
+        {
+            action: 'approve' | 'reject'
+            reason: str (optional)
+        }
+        """
+        user_id = pk
+        try:
+            user = User.objects.get(id=user_id)
+        except User.DoesNotExist:
+            return Response({
+                "success": False,
+                "msg": "用户不存在"
+            }, status=status.HTTP_404_NOT_FOUND)
+
+        serializer = serializers.UserApprovalSerializer(data=request.data)
+        if not serializer.is_valid():
+            return Response({
+                "success": False,
+                "msg": serializer.errors
+            }, status=status.HTTP_400_BAD_REQUEST)
+
+        action = serializer.validated_data['action']
+        
+        if action == 'approve':
+            user.status = 'approved'
+            user.is_active = True
+            user.save()
+            return Response({
+                "success": True,
+                "msg": "用户审批已通过"
+            })
+        elif action == 'reject':
+            user.status = 'rejected'
+            user.save()
+            return Response({
+                "success": True,
+                "msg": "用户审批未通过"
+            })
+
+
+class GroupListView(APIView):
+    """
+    获取分组列表(无需认证)
+    用于注册时选择分组
+    """
+    authentication_classes = ()
+    permission_classes = ()
+
+    def get(self, request):
+        """
+        获取所有分组列表
+        """
+        from django.contrib.auth.models import Group
+        groups = Group.objects.all()
+        group_list = [{"id": group.id, "name": group.name} for group in groups]
+        return Response(group_list)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/settings.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/settings.py"
index b24a522..9cf6887 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/settings.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/settings.py"
@@ -158,6 +158,8 @@
     "DEFAULT_PERMISSION_CLASSES": (
         "rest_framework.permissions.IsAuthenticated",  # 有经过身份认证确定用户身份才能访问
     ),
+    "DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S",  # 日期时间格式
+    "DATE_FORMAT": "%Y-%m-%d",  # 日期格式
 }
 
 # ================================================= #
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/utils/permissions.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/utils/permissions.py"
index dcae617..cd624ec 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/utils/permissions.py"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/backend/utils/permissions.py"
@@ -62,3 +62,6 @@
 
 class CustomIsAdminUser(IsAdminUser):
     message = "您没有执行此操作的权限"
+
+    def has_permission(self, request, view):
+        return request.user.is_superuser
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/check_users.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/check_users.py"
new file mode 100644
index 0000000..fa1c1b5
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/check_users.py"
@@ -0,0 +1,223 @@
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Group
+
+User = get_user_model()
+
+
+def list_users():
+    """
+    列出所有用户
+    """
+    print("=" * 60)
+    print("系统用户列表:")
+    print("=" * 60)
+    users = User.objects.all()
+    if not users:
+        print("暂无用户")
+    else:
+        for user in users:
+            print(f"\n用户名: {user.username}")
+            print(f"  姓名: {user.name}")
+            print(f"  邮箱: {user.email}")
+            print(f"  手机号: {user.phone}")
+            print(f"  状态: {user.status}")
+            print(f"  是否管理员: {'是' if user.is_superuser else '否'}")
+            print(f"  是否员工: {'是' if user.is_staff else '否'}")
+            print(f"  是否激活: {'是' if user.is_active else '否'}")
+            print(f"  所属用户组: {', '.join([g.name for g in user.groups.all()]) or '无'}")
+
+
+def create_admin_user(username='admin', password='admin123', email='admin@example.com', name='系统管理员'):
+    """
+    创建管理员用户
+    """
+    try:
+        user = User.objects.get(username=username)
+        print(f"\n用户 '{username}' 已存在,跳过创建")
+        return user
+
+    except User.DoesNotExist:
+        try:
+            user = User.objects.create_superuser(
+                username=username,
+                email=email,
+                password=password
+            )
+            user.name = name
+            user.phone = None
+            user.show_hosts = False
+            user.status = 'approved'
+            user.save()
+            print(f"\n✓ 成功创建管理员用户: {username}")
+            print(f"  - 姓名: {name}")
+            print(f"  - 邮箱: {email}")
+            print(f"  - 密码: {password}")
+            print(f"  - 状态: {user.status}")
+            return user
+
+        except Exception as e:
+            print(f"\n✗ 创建用户失败: {e}")
+            return None
+
+
+def create_test_users():
+    """
+    创建测试用户
+    """
+    test_users = [
+        {
+            'username': 'testuser',
+            'password': 'test123',
+            'email': 'test@example.com',
+            'name': '测试用户',
+            'is_staff': False,
+            'is_superuser': False
+        },
+        {
+            'username': 'developer',
+            'password': 'dev123',
+            'email': 'dev@example.com',
+            'name': '开发人员',
+            'is_staff': True,
+            'is_superuser': False
+        }
+    ]
+
+    created_count = 0
+    print("\n" + "=" * 60)
+    print("创建测试用户...")
+    print("=" * 60)
+
+    for user_data in test_users:
+        try:
+            user = User.objects.get(username=user_data['username'])
+            print(f"用户 '{user_data['username']}' 已存在,跳过创建")
+            continue
+
+        except User.DoesNotExist:
+            try:
+                user = User.objects.create_user(
+                    username=user_data['username'],
+                    email=user_data['email'],
+                    password=user_data['password']
+                )
+                user.name = user_data['name']
+                user.is_staff = user_data['is_staff']
+                user.is_superuser = user_data['is_superuser']
+                user.phone = None
+                user.show_hosts = False
+                user.status = 'approved'
+                user.save()
+                print(f"✓ 成功创建用户: {user_data['username']} ({user_data['name']})")
+                created_count += 1
+
+            except Exception as e:
+                print(f"✗ 创建用户 '{user_data['username']}' 失败: {e}")
+
+    return created_count
+
+
+def list_groups():
+    """
+    列出所有用户组
+    """
+    print("\n" + "=" * 60)
+    print("系统用户组列表:")
+    print("=" * 60)
+    groups = Group.objects.all()
+    if not groups:
+        print("暂无用户组")
+    else:
+        for group in groups:
+            print(f"\n组名: {group.name}")
+            print(f"  权限数量: {group.permissions.count()}")
+            print(f"  用户数量: {group.user_set.count()}")
+            if group.user_set.exists():
+                print(f"  成员: {', '.join([u.username for u in group.user_set.all()])}")
+
+
+def create_default_groups():
+    """
+    创建默认用户组
+    """
+    groups_config = [
+        {'name': '管理员组', 'description': '拥有所有权限的管理员组'},
+        {'name': '开发人员组', 'description': '开发人员组'},
+        {'name': '测试人员组', 'description': '测试人员组'},
+        {'name': '只读用户组', 'description': '只读用户组'},
+    ]
+
+    created_count = 0
+    print("\n" + "=" * 60)
+    print("创建默认用户组...")
+    print("=" * 60)
+
+    for group_config in groups_config:
+        try:
+            Group.objects.get(name=group_config['name'])
+            print(f"用户组 '{group_config['name']}' 已存在")
+        except Group.DoesNotExist:
+            try:
+                Group.objects.create(name=group_config['name'])
+                print(f"✓ 创建用户组: {group_config['name']}")
+                created_count += 1
+            except Exception as e:
+                print(f"✗ 创建用户组 '{group_config['name']}' 失败: {e}")
+
+    return created_count
+
+
+if __name__ == '__main__':
+    import argparse
+
+    parser = argparse.ArgumentParser(description='用户管理脚本')
+    parser.add_argument('--list', action='store_true', help='列出所有用户')
+    parser.add_argument('--create-admin', action='store_true', help='创建管理员用户')
+    parser.add_argument('--create-test', action='store_true', help='创建测试用户')
+    parser.add_argument('--create-groups', action='store_true', help='创建默认用户组')
+    parser.add_argument('--list-groups', action='store_true', help='列出所有用户组')
+    parser.add_argument('--init', action='store_true', help='初始化所有数据(创建管理员、测试用户和用户组)')
+
+    args = parser.parse_args()
+
+    if args.list:
+        list_users()
+    elif args.create_admin:
+        create_admin_user()
+    elif args.create_test:
+        create_test_users()
+    elif args.create_groups:
+        create_default_groups()
+    elif args.list_groups:
+        list_groups()
+    elif args.init:
+        print("=" * 60)
+        print("初始化用户数据...")
+        print("=" * 60)
+
+        admin = create_admin_user()
+        if admin:
+            test_count = create_test_users()
+            group_count = create_default_groups()
+
+            list_users()
+            list_groups()
+
+            print("\n" + "=" * 60)
+            print("初始化完成!")
+            print("=" * 60)
+            print(f"✓ 创建了 {test_count} 个测试用户")
+            print(f"✓ 创建了 {group_count} 个用户组")
+            print("\n默认管理员账号:")
+            print("  用户名: admin")
+            print("  密码: admin123")
+            print("\n⚠️  请在首次登录后修改默认密码!")
+    else:
+        parser.print_help()
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/README.md" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/README.md"
new file mode 100644
index 0000000..94c8b3e
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/README.md"
@@ -0,0 +1,231 @@
+# 首次部署脚本使用说明
+
+本目录包含接口自动化平台首次部署时所需的初始化脚本。
+
+## 脚本列表
+
+### 1. deploy_init.py - 首次部署初始化脚本(推荐)
+
+一键执行所有初始化操作,包括:
+- 检查数据库连接
+- 执行数据库迁移
+- 创建管理员用户
+- 创建默认用户组
+- 收集静态文件
+
+**使用方法:**
+```bash
+cd backend
+python scripts/deploy_init.py
+```
+
+**默认管理员账号:**
+- 用户名: `admin`
+- 密码: `admin123`
+
+⚠️ **重要提示:** 请在首次登录后立即修改默认密码!
+
+---
+
+### 2. run_migrations.py - 数据库迁移脚本
+
+单独执行数据库迁移操作。
+
+**使用方法:**
+```bash
+cd backend
+python scripts/run_migrations.py
+```
+
+---
+
+### 3. create_admin_user.py - 创建管理员用户脚本
+
+创建管理员用户和测试用户。
+
+**使用方法:**
+```bash
+cd backend
+python scripts/create_admin_user.py
+```
+
+**默认创建的用户:**
+- `admin` - 系统管理员(超级用户)
+- `testuser` - 测试用户(普通用户)
+- `developer` - 开发人员(员工用户)
+
+**自定义管理员账号:**
+修改脚本中的 `create_admin_user()` 函数参数:
+```python
+create_admin_user(
+    username='your_username',
+    password='your_password',
+    email='your_email@example.com',
+    name='your_name'
+)
+```
+
+---
+
+### 4. create_groups.py - 创建用户组脚本
+
+创建默认用户组并分配权限。
+
+**使用方法:**
+```bash
+cd backend
+python scripts/create_groups.py
+```
+
+**默认创建的用户组:**
+- `管理员组` - 拥有所有权限
+- `开发人员组` - 可以查看、添加和修改数据
+- `测试人员组` - 可以查看和添加数据
+- `只读用户组` - 只能查看数据
+
+---
+
+### 5. collect_static.py - 收集静态文件脚本
+
+收集所有静态文件到 STATIC_ROOT 目录。
+
+**使用方法:**
+```bash
+cd backend
+python scripts/collect_static.py
+```
+
+---
+
+## 部署前准备
+
+### 1. 配置数据库连接
+
+编辑 `backend/conf/env.py` 文件,配置数据库连接信息:
+
+```python
+DATABASE_NAME = 'your_database_name'
+DATABASE_USER = 'your_database_user'
+DATABASE_PASSWORD = 'your_database_password'
+DATABASE_HOST = 'localhost'
+DATABASE_PORT = '3306'
+```
+
+### 2. 创建数据库
+
+在 MySQL 中创建数据库:
+
+```sql
+CREATE DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+```
+
+### 3. 安装依赖
+
+```bash
+cd backend
+pip install -r requirements.txt
+```
+
+---
+
+## 完整部署流程
+
+### 方式一:使用一键部署脚本(推荐)
+
+```bash
+cd backend
+python scripts/deploy_init.py
+```
+
+### 方式二:分步执行
+
+```bash
+cd backend
+
+# 1. 执行数据库迁移
+python scripts/run_migrations.py
+
+# 2. 创建管理员用户
+python scripts/create_admin_user.py
+
+# 3. 创建用户组
+python scripts/create_groups.py
+
+# 4. 收集静态文件
+python scripts/collect_static.py
+```
+
+---
+
+## 启动服务
+
+### 开发环境
+
+```bash
+cd backend
+python manage.py runserver
+```
+
+### 生产环境
+
+```bash
+cd backend
+gunicorn backend.wsgi:application -c gunicorn_conf.py
+```
+
+---
+
+## 常见问题
+
+### 1. 数据库连接失败
+
+检查 `conf/env.py` 中的数据库配置是否正确,确保数据库已创建且用户有足够的权限。
+
+### 2. 迁移失败
+
+确保数据库表不存在或为空。如果之前有迁移历史,可能需要删除 `migrations` 目录下的迁移文件(保留 `__init__.py`)。
+
+### 3. 静态文件收集失败
+
+确保 `STATIC_ROOT` 目录有写入权限。
+
+### 4. 用户已存在
+
+脚本会自动检测用户是否已存在,如果存在则跳过创建。
+
+---
+
+## 数据库表结构说明
+
+### lunaruser 应用
+- `lunaruser_myuser` - 用户表(继承自 Django AbstractUser)
+
+### lunarlink 应用
+- `project` - 项目信息表
+- `config` - 环境信息表
+- `api` - 接口信息表
+- `case` - 用例信息表
+- `case_step` - 用例步骤表
+- `variables` - 全局变量表
+- `debugtalk` - 驱动代码表
+- `report` - 测试报告表
+- `report_detail` - 测试报告详情表
+- `relation` - 树形结构关系表
+- `visit` - 访问日志表
+- `login_log` - 登录日志表
+
+---
+
+## 安全建议
+
+1. **修改默认密码:** 首次登录后立即修改管理员密码
+2. **使用强密码:** 密码长度至少 8 位,包含大小写字母、数字和特殊字符
+3. **限制访问:** 在生产环境中配置防火墙规则
+4. **启用 HTTPS:** 生产环境必须使用 HTTPS
+5. **定期备份:** 定期备份数据库和重要文件
+
+---
+
+## 技术支持
+
+如有问题,请查看项目文档或联系技术支持团队。
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/__init__.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/__init__.py"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/__init__.py"
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/collect_static.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/collect_static.py"
new file mode 100644
index 0000000..8dec938
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/collect_static.py"
@@ -0,0 +1,58 @@
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.core.management import call_command
+
+
+def collect_static():
+    """
+    收集静态文件
+    """
+    print("=" * 60)
+    print("开始收集静态文件...")
+    print("=" * 60)
+
+    try:
+        call_command('collectstatic', '--noinput', verbosity=2)
+        print("\n✓ 静态文件收集完成!")
+        return True
+
+    except Exception as e:
+        print(f"\n✗ 静态文件收集失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+def create_superuser():
+    """
+    交互式创建超级用户
+    """
+    print("\n" + "=" * 60)
+    print("创建超级用户 (可选)")
+    print("=" * 60)
+    print("如需创建超级用户,请按 Ctrl+C 取消,然后单独运行 create_admin_user.py")
+    print()
+
+    try:
+        call_command('createsuperuser')
+        return True
+    except KeyboardInterrupt:
+        print("\n跳过创建超级用户")
+        return True
+    except Exception as e:
+        print(f"创建超级用户失败: {e}")
+        return False
+
+
+if __name__ == '__main__':
+    success = collect_static()
+    if success:
+        create_superuser()
+        sys.exit(0)
+    else:
+        sys.exit(1)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_admin_user.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_admin_user.py"
new file mode 100644
index 0000000..f7072f1
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_admin_user.py"
@@ -0,0 +1,158 @@
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.contrib.auth import get_user_model
+from django.core.exceptions import ValidationError
+
+
+User = get_user_model()
+
+
+def create_admin_user(username='admin', password='admin123', email='admin@example.com', name='系统管理员'):
+    """
+    创建管理员用户
+
+    Args:
+        username: 用户名
+        password: 密码
+        email: 邮箱
+        name: 姓名
+
+    Returns:
+        User: 创建的用户对象或已存在的用户对象
+    """
+    try:
+        user = User.objects.get(username=username)
+        print(f"用户 '{username}' 已存在,跳过创建")
+        return user
+
+    except User.DoesNotExist:
+        try:
+            user = User.objects.create_superuser(
+                username=username,
+                email=email,
+                password=password
+            )
+            user.name = name
+            user.phone = None
+            user.show_hosts = False
+            user.status = 'approved'
+            user.save()
+            print(f"✓ 成功创建管理员用户: {username}")
+            print(f"  - 姓名: {name}")
+            print(f"  - 邮箱: {email}")
+            print(f"  - 状态: {user.status}")
+            return user
+
+        except ValidationError as e:
+            print(f"✗ 创建用户失败,验证错误: {e}")
+            return None
+        except Exception as e:
+            print(f"✗ 创建用户失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return None
+
+
+def create_test_users():
+    """
+    创建测试用户
+    """
+    test_users = [
+        {
+            'username': 'testuser',
+            'password': 'test123',
+            'email': 'test@example.com',
+            'name': '测试用户',
+            'is_staff': False,
+            'is_superuser': False
+        },
+        {
+            'username': 'developer',
+            'password': 'dev123',
+            'email': 'dev@example.com',
+            'name': '开发人员',
+            'is_staff': True,
+            'is_superuser': False
+        }
+    ]
+
+    created_count = 0
+    for user_data in test_users:
+        try:
+            user = User.objects.get(username=user_data['username'])
+            print(f"用户 '{user_data['username']}' 已存在,跳过创建")
+            continue
+
+        except User.DoesNotExist:
+            try:
+                user = User.objects.create_user(
+                    username=user_data['username'],
+                    email=user_data['email'],
+                    password=user_data['password']
+                )
+                user.name = user_data['name']
+                user.is_staff = user_data['is_staff']
+                user.is_superuser = user_data['is_superuser']
+                user.phone = None
+                user.show_hosts = False
+                user.status = 'approved'
+                user.save()
+                print(f"✓ 成功创建用户: {user_data['username']} ({user_data['name']})")
+                created_count += 1
+
+            except Exception as e:
+                print(f"✗ 创建用户 '{user_data['username']}' 失败: {e}")
+
+    return created_count
+
+
+def list_all_users():
+    """
+    列出所有用户
+    """
+    print("\n" + "=" * 60)
+    print("当前系统用户列表:")
+    print("=" * 60)
+    users = User.objects.all()
+    if not users:
+        print("暂无用户")
+    else:
+        for user in users:
+            print(f"  - 用户名: {user.username}")
+            print(f"    姓名: {user.name}")
+            print(f"    邮箱: {user.email}")
+            print(f"    手机号: {user.phone}")
+            print(f"    状态: {user.status}")
+            print(f"    是否管理员: {'是' if user.is_superuser else '否'}")
+            print(f"    是否员工: {'是' if user.is_staff else '否'}")
+            print(f"    是否激活: {'是' if user.is_active else '否'}")
+            print()
+
+
+if __name__ == '__main__':
+    print("=" * 60)
+    print("开始初始化用户数据...")
+    print("=" * 60)
+
+    admin = create_admin_user()
+    if admin:
+        print("\n创建测试用户...")
+        test_count = create_test_users()
+        print(f"\n✓ 成功创建 {test_count} 个测试用户")
+
+        list_all_users()
+
+        print("\n" + "=" * 60)
+        print("用户初始化完成!")
+        print("=" * 60)
+        sys.exit(0)
+    else:
+        print("\n" + "=" * 60)
+        print("用户初始化失败!")
+        print("=" * 60)
+        sys.exit(1)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_groups.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_groups.py"
new file mode 100644
index 0000000..3735186
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/create_groups.py"
@@ -0,0 +1,110 @@
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.contrib.auth.models import Group, Permission
+from django.contrib.contenttypes.models import ContentType
+from apps.lunarlink.models import Project, API, Case, Config, Variables, Report
+
+
+def create_default_groups():
+    """
+    创建默认用户组
+    """
+    groups_config = [
+        {
+            'name': '管理员组',
+            'permissions': ['all'],
+            'description': '拥有所有权限的管理员组'
+        },
+        {
+            'name': '开发人员组',
+            'permissions': ['view', 'add', 'change'],
+            'description': '开发人员组,可以查看、添加和修改数据'
+        },
+        {
+            'name': '测试人员组',
+            'permissions': ['view', 'add'],
+            'description': '测试人员组,可以查看和添加数据'
+        },
+        {
+            'name': '只读用户组',
+            'permissions': ['view'],
+            'description': '只读用户组,只能查看数据'
+        }
+    ]
+
+    created_count = 0
+    for group_config in groups_config:
+        try:
+            group = Group.objects.get(name=group_config['name'])
+            print(f"用户组 '{group_config['name']}' 已存在,跳过创建")
+            continue
+
+        except Group.DoesNotExist:
+            try:
+                group = Group.objects.create(name=group_config['name'])
+                print(f"✓ 成功创建用户组: {group_config['name']}")
+
+                if 'all' in group_config['permissions']:
+                    all_permissions = Permission.objects.all()
+                    group.permissions.set(all_permissions)
+                    print(f"  - 已添加所有权限")
+                else:
+                    for perm_type in group_config['permissions']:
+                        for model in [Project, API, Case, Config, Variables, Report]:
+                            content_type = ContentType.objects.get_for_model(model)
+                            codename = f"{perm_type}_{model._meta.model_name}"
+                            try:
+                                perm = Permission.objects.get(
+                                    content_type=content_type,
+                                    codename=codename
+                                )
+                                group.permissions.add(perm)
+                            except Permission.DoesNotExist:
+                                pass
+
+                    print(f"  - 已添加权限: {', '.join(group_config['permissions'])}")
+
+                created_count += 1
+
+            except Exception as e:
+                print(f"✗ 创建用户组 '{group_config['name']}' 失败: {e}")
+
+    return created_count
+
+
+def list_all_groups():
+    """
+    列出所有用户组
+    """
+    print("\n" + "=" * 60)
+    print("当前系统用户组列表:")
+    print("=" * 60)
+    groups = Group.objects.all()
+    if not groups:
+        print("暂无用户组")
+    else:
+        for group in groups:
+            print(f"  - 组名: {group.name}")
+            print(f"    权限数量: {group.permissions.count()}")
+            print(f"    用户数量: {group.user_set.count()}")
+            print()
+
+
+if __name__ == '__main__':
+    print("=" * 60)
+    print("开始初始化用户组数据...")
+    print("=" * 60)
+
+    count = create_default_groups()
+    print(f"\n✓ 成功创建 {count} 个用户组")
+
+    list_all_groups()
+
+    print("\n" + "=" * 60)
+    print("用户组初始化完成!")
+    print("=" * 60)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/deploy_init.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/deploy_init.py"
new file mode 100644
index 0000000..90916fa
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/deploy_init.py"
@@ -0,0 +1,258 @@
+#!/usr/bin/env python
+"""
+首次部署初始化脚本
+
+该脚本用于首次部署系统时执行所有必要的初始化操作,包括:
+1. 数据库迁移
+2. 创建管理员用户
+3. 创建默认用户组
+4. 收集静态文件
+
+使用方法:
+    python scripts/deploy_init.py
+
+注意事项:
+    - 确保已配置好数据库连接信息 (conf/env.py)
+    - 确保数据库已创建
+    - 确保已安装所有依赖 (pip install -r requirements.txt)
+"""
+
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.core.management import call_command
+
+
+def check_database_connection():
+    """
+    检查数据库连接
+    """
+    print("=" * 60)
+    print("检查数据库连接...")
+    print("=" * 60)
+
+    try:
+        from django.db import connection
+        with connection.cursor() as cursor:
+            cursor.execute("SELECT 1")
+            print("✓ 数据库连接正常")
+            return True
+    except Exception as e:
+        print(f"✗ 数据库连接失败: {e}")
+        print("\n请检查 conf/env.py 中的数据库配置:")
+        print("  - DATABASE_NAME")
+        print("  - DATABASE_USER")
+        print("  - DATABASE_PASSWORD")
+        print("  - DATABASE_HOST")
+        print("  - DATABASE_PORT")
+        return False
+
+
+def run_migrations():
+    """
+    执行数据库迁移
+    """
+    print("\n" + "=" * 60)
+    print("执行数据库迁移...")
+    print("=" * 60)
+
+    try:
+        print("\n[1/2] 生成迁移文件...")
+        call_command('makemigrations', verbosity=1)
+        print("✓ 迁移文件生成成功")
+
+        print("\n[2/2] 应用迁移...")
+        call_command('migrate', verbosity=1)
+        print("✓ 数据库迁移成功")
+        return True
+
+    except Exception as e:
+        print(f"✗ 数据库迁移失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+def create_admin_user():
+    """
+    创建管理员用户
+    """
+    print("\n" + "=" * 60)
+    print("创建管理员用户...")
+    print("=" * 60)
+
+    from django.contrib.auth import get_user_model
+    User = get_user_model()
+
+    default_username = 'admin'
+    default_password = 'admin123'
+    default_email = 'admin@example.com'
+    default_name = '系统管理员'
+
+    try:
+        user = User.objects.get(username=default_username)
+        print(f"管理员用户 '{default_username}' 已存在,跳过创建")
+        print(f"  用户名: {user.username}")
+        print(f"  姓名: {user.name}")
+        print(f"  邮箱: {user.email}")
+        return True
+
+    except User.DoesNotExist:
+        try:
+            user = User.objects.create_superuser(
+                username=default_username,
+                email=default_email,
+                password=default_password
+            )
+            user.name = default_name
+            user.phone = None
+            user.show_hosts = False
+            user.status = 'approved'
+            user.save()
+
+            print("✓ 管理员用户创建成功")
+            print(f"  用户名: {default_username}")
+            print(f"  密码: {default_password}")
+            print(f"  邮箱: {default_email}")
+            print(f"  姓名: {default_name}")
+            print("\n⚠️  重要提示: 请在首次登录后修改默认密码!")
+            return True
+
+        except Exception as e:
+            print(f"✗ 创建管理员用户失败: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+
+
+def create_default_groups():
+    """
+    创建默认用户组
+    """
+    print("\n" + "=" * 60)
+    print("创建默认用户组...")
+    print("=" * 60)
+
+    from django.contrib.auth.models import Group
+
+    groups = [
+        {'name': '管理员组', 'description': '拥有所有权限的管理员组'},
+        {'name': '开发人员组', 'description': '开发人员组'},
+        {'name': '测试人员组', 'description': '测试人员组'},
+        {'name': '只读用户组', 'description': '只读用户组'},
+    ]
+
+    created_count = 0
+    for group_info in groups:
+        try:
+            Group.objects.get(name=group_info['name'])
+            print(f"  用户组 '{group_info['name']}' 已存在")
+        except Group.DoesNotExist:
+            try:
+                Group.objects.create(name=group_info['name'])
+                print(f"  ✓ 创建用户组: {group_info['name']}")
+                created_count += 1
+            except Exception as e:
+                print(f"  ✗ 创建用户组 '{group_info['name']}' 失败: {e}")
+
+    print(f"\n✓ 成功创建 {created_count} 个用户组")
+    return True
+
+
+def collect_static_files():
+    """
+    收集静态文件
+    """
+    print("\n" + "=" * 60)
+    print("收集静态文件...")
+    print("=" * 60)
+
+    try:
+        call_command('collectstatic', '--noinput', verbosity=1)
+        print("✓ 静态文件收集成功")
+        return True
+
+    except Exception as e:
+        print(f"✗ 静态文件收集失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+def display_summary():
+    """
+    显示部署摘要
+    """
+    print("\n" + "=" * 60)
+    print("部署摘要")
+    print("=" * 60)
+
+    from django.contrib.auth import get_user_model
+    from django.contrib.auth.models import Group
+    from apps.lunarlink.models import Project
+
+    User = get_user_model()
+
+    print(f"\n用户数量: {User.objects.count()}")
+    print(f"用户组数量: {Group.objects.count()}")
+    print(f"项目数量: {Project.objects.count()}")
+
+    print("\n默认管理员账号:")
+    print("  用户名: admin")
+    print("  密码: admin123")
+    print("\n⚠️  请在首次登录后立即修改默认密码!")
+
+
+def main():
+    """
+    主函数
+    """
+    print("\n")
+    print("╔" + "=" * 58 + "╗")
+    print("║" + " " * 10 + "接口自动化平台 - 首次部署初始化" + " " * 13 + "║")
+    print("╚" + "=" * 58 + "╝")
+    print()
+
+    steps = [
+        ("检查数据库连接", check_database_connection),
+        ("执行数据库迁移", run_migrations),
+        ("创建管理员用户", create_admin_user),
+        ("创建默认用户组", create_default_groups),
+        ("收集静态文件", collect_static_files),
+    ]
+
+    failed_steps = []
+
+    for step_name, step_func in steps:
+        if not step_func():
+            failed_steps.append(step_name)
+            print(f"\n✗ '{step_name}' 失败,终止部署")
+            break
+
+    if not failed_steps:
+        display_summary()
+        print("\n" + "=" * 60)
+        print("✓ 部署初始化完成!")
+        print("=" * 60)
+        print("\n系统已准备就绪,可以启动服务:")
+        print("  python manage.py runserver")
+        print("\n或使用 gunicorn 启动:")
+        print("  gunicorn backend.wsgi:application -c gunicorn_conf.py")
+        print()
+        return 0
+    else:
+        print("\n" + "=" * 60)
+        print("✗ 部署初始化失败!")
+        print("=" * 60)
+        print(f"\n失败的步骤: {', '.join(failed_steps)}")
+        print("\n请检查错误信息并修复后重试")
+        print()
+        return 1
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/run_migrations.py" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/run_migrations.py"
new file mode 100644
index 0000000..8c24452
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/backend/scripts/run_migrations.py"
@@ -0,0 +1,43 @@
+import os
+import sys
+import django
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+django.setup()
+
+from django.core.management import call_command
+
+
+def run_migrations():
+    """
+    执行数据库迁移脚本
+    用于首次部署时创建数据库表结构
+    """
+    print("=" * 60)
+    print("开始执行数据库迁移...")
+    print("=" * 60)
+
+    try:
+        print("\n[1/2] 执行 makemigrations...")
+        call_command('makemigrations', verbosity=2)
+        print("✓ makemigrations 执行成功")
+
+        print("\n[2/2] 执行 migrate...")
+        call_command('migrate', verbosity=2)
+        print("✓ migrate 执行成功")
+
+        print("\n" + "=" * 60)
+        print("数据库迁移完成!")
+        print("=" * 60)
+        return True
+
+    except Exception as e:
+        print(f"\n✗ 数据库迁移失败: {e}")
+        import traceback
+        traceback.print_exc()
+        return False
+
+
+if __name__ == '__main__':
+    success = run_migrations()
+    sys.exit(0 if success else 1)
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/api/user.js" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/api/user.js"
index 0042831..41b4d96 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/api/user.js"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/api/user.js"
@@ -10,11 +10,46 @@
       Authorization: store.token
     }
   }).then(res => {
-    // 密码修改成功后清除token和用户信息
     store.token = null
     store.user = null
     store.name = null
     store.id = null
     return res.data
   })
+}
+
+export function register(data) {
+  return axios({
+    url: '/api/user/register',
+    method: 'post',
+    data
+  }).then(res => {
+    return res.data
+  })
+}
+
+export function getUserApprovalList(params) {
+  return axios({
+    url: '/api/user/approval/',
+    method: 'get',
+    params,
+    headers: {
+      Authorization: store.token
+    }
+  }).then(res => {
+    return res.data
+  })
+}
+
+export function approveUser(userId, data) {
+  return axios({
+    url: `/api/user/approval/${userId}/approve/`,
+    method: 'post',
+    data,
+    headers: {
+      Authorization: store.token
+    }
+  }).then(res => {
+    return res.data
+  })
 }
\ No newline at end of file
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/home/components/Header.vue" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/home/components/Header.vue"
index 70ff7c9..b0e2953 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/home/components/Header.vue"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/home/components/Header.vue"
@@ -11,6 +11,13 @@
       }}</span>
     </div>
     <div class="right">
+      <div class="approval-button-wrapper" v-if="$store.state.is_superuser || $store.state.is_staff">
+        <el-badge :value="pendingCount" :hidden="pendingCount === 0" class="approval-badge">
+          <el-button type="success" size="small" icon="el-icon-s-check" @click="handleApproval">
+            注册用户审批
+          </el-button>
+        </el-badge>
+      </div>
       <div style="float: right; color: #262626; margin-right: 35px;">
         <el-dropdown trigger="click" @command="handleCommand">
           <span class="el-dropdown-link">
@@ -18,7 +25,6 @@
             {{ $store.state.name }}
             <i class="el-icon-arrow-down el-icon--right"></i>
           </span>
-
           <el-dropdown-menu slot="dropdown">
             <el-dropdown-item command="changePassword">
               <i class="el-icon-edit"></i>修改密码
@@ -71,11 +77,81 @@
         <el-button type="primary" @click="submitPasswordChange">确 定</el-button>
       </span>
     </el-dialog>
+
+    <el-drawer
+      title="注册用户审批"
+      :visible.sync="approvalDrawerVisible"
+      direction="rtl"
+      size="60%"
+      :modal="false"
+      :append-to-body="true"
+    >
+      <div class="approval-container">
+        <el-table
+          :data="approvalData"
+          v-loading="approvalLoading"
+          stripe
+          style="width: 100%"
+        >
+          <el-table-column prop="username" label="用户名" width="120"></el-table-column>
+          <el-table-column prop="name" label="姓名" width="120"></el-table-column>
+          <el-table-column prop="phone" label="手机号" width="120"></el-table-column>
+          <el-table-column label="所属分组" width="200">
+            <template slot-scope="scope">
+              <el-tag
+                v-for="group in scope.row.groups"
+                :key="group"
+                size="mini"
+                style="margin-right: 3px"
+              >
+                {{ group }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" width="100">
+            <template slot-scope="scope">
+              <el-tag :type="getStatusType(scope.row.status)">
+                {{ scope.row.status_display }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="注册时间" width="180">
+            <template slot-scope="scope">
+              {{ scope.row.date_joined | datetimeFormat }}
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" fixed="right" width="200">
+            <template slot-scope="scope">
+              <el-button
+                type="success"
+                size="mini"
+                icon="el-icon-check"
+                @click="handleApprove(scope.row, 'approve')"
+              >
+                通过
+              </el-button>
+              <el-button
+                type="danger"
+                size="mini"
+                icon="el-icon-close"
+                @click="handleApprove(scope.row, 'reject')"
+              >
+                不通过
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div v-if="!approvalLoading && approvalData.length === 0" class="empty-tip">
+          <el-empty description="暂无待审批用户"></el-empty>
+        </div>
+      </div>
+    </el-drawer>
   </div>
 </template>
 
 <script>
-import { changePassword } from '@/api/user'
+import { changePassword, approveUser } from '@/api/user'
+import { getUserApprovalList } from '@/api/user'
 
 export default {
   data() {
@@ -89,6 +165,10 @@
 
     return {
       passwordDialogVisible: false,
+      approvalDrawerVisible: false,
+      approvalLoading: false,
+      approvalData: [],
+      pendingCount: 0,
       passwordForm: {
         old_password: '',
         new_password: '',
@@ -110,6 +190,25 @@
     }
   },
   methods: {
+    addBadgeAnimation() {
+      if (this.pendingCount > 0) {
+        const badge = document.querySelector('.approval-badge .el-badge__content');
+        if (badge) {
+          badge.classList.add('badge-enter');
+          setTimeout(() => {
+            badge.classList.remove('badge-enter');
+          }, 1000);
+        }
+      }
+    },
+    getStatusType(status) {
+      const statusMap = {
+        'pending': 'warning',
+        'approved': 'success',
+        'rejected': 'danger'
+      };
+      return statusMap[status] || 'info';
+    },
     handleCommand(command) {
       if (command === 'changePassword') {
         // 重置表单数据和验证状态
@@ -128,10 +227,42 @@
         this.$store.commit("isLogin", null);
         this.setLocalValue("token", null);
         this.setLocalValue("is_superuser", false);
+        this.setLocalValue("is_staff", false);
         this.setLocalValue("show_hosts", false);
         this.$store.commit("setProjectName", "");
         this.$router.push({ name: "Login" });
       }
+    },
+    handleApproval() {
+      this.approvalDrawerVisible = true;
+      this.getApprovalList();
+    },
+    getApprovalList() {
+      this.approvalLoading = true;
+      getUserApprovalList().then(resp => {
+        this.approvalData = resp.results || resp;
+        this.pendingCount = this.approvalData.length;
+        this.approvalLoading = false;
+        if (this.pendingCount > 0) {
+          this.addBadgeAnimation();
+        }
+      }).catch(() => {
+        this.approvalLoading = false;
+      });
+    },
+    handleApprove(row, action) {
+      const actionText = action === 'approve' ? '通过' : '不通过';
+      this.$confirm(`确定要${actionText}该用户的注册申请吗?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.$api.approveUser(row.id, { action: action }).then(() => {
+          this.$message.success(`用户审批已${actionText}`);
+          this.pendingCount = Math.max(0, this.pendingCount - 1);
+          this.getApprovalList();
+        });
+      }).catch(() => {});
     },
     submitPasswordChange() {
       this.$refs.passwordForm.validate(valid => {
@@ -166,6 +297,14 @@
             })
         }
       })
+    }
+  },
+  mounted() {
+    if (this.$store.state.is_superuser || this.$store.state.is_staff) {
+      this.getApprovalList();
+      setTimeout(() => {
+        this.addBadgeAnimation();
+      }, 500);
     }
   }
 }
@@ -219,4 +358,164 @@
   color: #409EFF;
   padding: 0 15px;
 }
+
+.approval-container {
+  padding: 20px;
+}
+
+.empty-tip {
+  text-align: center;
+  padding: 40px 0;
+}
+
+.approval-button-wrapper {
+  float: right;
+  color: #262626;
+  margin-right: 15px;
+  display: flex;
+  align-items: center;
+  height: 49px;
+  position: relative;
+}
+
+/* 优化按钮本身 */
+.approval-button-wrapper .el-button {
+  position: relative;
+  padding: 7px 12px;
+  border-radius: 6px;
+  font-weight: 500;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 8px rgba(103, 194, 58, 0.2);
+}
+
+.approval-button-wrapper .el-button:hover {
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
+}
+
+.approval-button-wrapper .el-button:active {
+  transform: translateY(0);
+}
+
+/* 徽章优化 - 更自然的设计 */
+.approval-badge {
+  position: relative;
+  display: inline-flex;
+  align-items: center;
+}
+
+.approval-badge ::v-deep .el-badge__content {
+  position: absolute !important;
+  top: -8px !important;
+  right: -8px !important;
+  height: 20px;
+  min-width: 20px;
+  line-height: 20px;
+  padding: 0 4px;
+  font-size: 12px;
+  font-weight: 600;
+  border-radius: 10px;
+  background: linear-gradient(135deg, #ff6b6b, #ff4757);
+  color: white;
+  border: 2px solid white;
+  box-shadow: 0 3px 6px rgba(255, 107, 107, 0.3);
+  z-index: 10;
+  animation: badge-pulse 2s infinite;
+}
+
+/* 徽章脉冲动画 */
+@keyframes badge-pulse {
+  0% {
+    box-shadow: 0 0 0 0 rgba(255, 107, 107, 0.4);
+  }
+  70% {
+    box-shadow: 0 0 0 4px rgba(255, 107, 107, 0);
+  }
+  100% {
+    box-shadow: 0 0 0 0 rgba(255, 107, 107, 0);
+  }
+}
+
+/* 徽章入场动画 */
+@keyframes badge-bounce {
+  0% {
+    transform: scale(0);
+  }
+  50% {
+    transform: scale(1.2);
+  }
+  100% {
+    transform: scale(1);
+  }
+}
+
+.approval-badge ::v-deep .el-badge__content.badge-enter {
+  animation: badge-bounce 0.5s ease;
+}
+
+/* 当徽章值为0时的隐藏效果 */
+.approval-badge ::v-deep .el-badge__content.is-fixed.is-dot {
+  top: -4px !important;
+  right: -4px !important;
+  height: 8px;
+  width: 8px;
+  min-width: 8px;
+  border: 1px solid white;
+  background: linear-gradient(135deg, #ffa502, #ff7f00);
+}
+
+/* 可选:添加图标徽章效果 */
+.approval-button-wrapper .el-button i {
+  position: relative;
+  margin-right: 4px;
+}
+
+/* 添加按钮渐变效果 */
+.approval-button-wrapper .el-button--success {
+  background: linear-gradient(135deg, #85d27a, #67c23a);
+  border: none;
+}
+
+.approval-button-wrapper .el-button--success:hover {
+  background: linear-gradient(135deg, #7ac76f, #5da534);
+}
+
+/* 徽章数字特殊样式 */
+.approval-badge ::v-deep .el-badge__content .el-badge__inner {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+  letter-spacing: -0.5px;
+}
+
+/* 调整整体布局 */
+.right {
+  position: fixed;
+  left: 300px;
+  right: 0;
+  top: 0;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  padding-right: 10px;
+  gap: 10px; /* 增加元素间距 */
+}
+
+/* 用户下拉菜单样式优化 */
+.el-dropdown-link {
+  cursor: pointer;
+  color: #409EFF;
+  padding: 8px 16px;
+  border-radius: 6px;
+  transition: all 0.3s ease;
+  display: inline-flex;
+  align-items: center;
+}
+
+.el-dropdown-link:hover {
+  background-color: rgba(64, 158, 255, 0.1);
+}
+
+.el-dropdown-link i {
+  margin-right: 4px;
+}
+
 </style>
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/login/Login.vue" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/login/Login.vue"
index 45565c9..49e1f77 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/login/Login.vue"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/login/Login.vue"
@@ -1,6 +1,5 @@
 <template>
   <div class="login-container">
-    <!-- 动态背景 -->
     <div class="background-animation">
       <div class="floating-shapes">
         <div class="shape shape-1"></div>
@@ -12,28 +11,20 @@
       <div class="gradient-overlay"></div>
     </div>
 
-    <!-- 主登录区域 -->
     <div class="login-content">
-      <!-- 左侧品牌展示区 -->
       <div class="brand-section">
         <div class="brand-logo-container">
           <div class="logo-icon">
             <svg viewBox="0 0 100 100" class="api-icon">
-              <!-- 主API连接图标 -->
               <path d="M20,30 L50,10 L80,30 L80,70 L50,90 L20,70 Z" fill="rgba(0,212,255,0.1)" stroke="rgba(0,212,255,0.6)" stroke-width="2"/>
-              <!-- 内部连接层 -->
               <path d="M30,40 L50,25 L70,40 L70,60 L50,75 L30,60 Z" fill="rgba(148,0,211,0.1)" stroke="rgba(148,0,211,0.6)" stroke-width="1.5"/>
-              <!-- 核心数据点 -->
               <path d="M40,50 L50,40 L60,50 L60,55 L50,60 L40,55 Z" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
-              <!-- 动态连接线 -->
               <line x1="35" y1="45" x2="45" y2="52" stroke="#00d4ff" stroke-width="1.5" stroke-dasharray="2,2"/>
               <line x1="55" y1="45" x2="65" y2="52" stroke="#9400d3" stroke-width="1.5" stroke-dasharray="2,2"/>
-              <!-- 中心数据流点 -->
               <circle cx="50" cy="50" r="4" fill="#00d4ff">
                 <animate attributeName="r" values="4;6;4" dur="2s" repeatCount="indefinite"/>
                 <animate attributeName="opacity" values="1;0.7;1" dur="2s" repeatCount="indefinite"/>
               </circle>
-              <!-- 外围数据点 -->
               <circle cx="35" cy="35" r="2" fill="#00d4ff">
                 <animate attributeName="opacity" values="0.5;1;0.5" dur="1.5s" repeatCount="indefinite"/>
               </circle>
@@ -68,12 +59,11 @@
         </div>
       </div>
 
-      <!-- 右侧登录表单 -->
       <div class="login-form-section">
         <div class="form-container">
           <div class="form-header">
-            <h2>欢迎登录</h2>
-            <p>请使用您的账号密码登录系统</p>
+            <h2>{{ isLoginMode ? '欢迎登录' : '用户注册' }}</h2>
+            <p>{{ isLoginMode ? '请使用您的账号密码登录系统' : '请填写以下信息完成注册' }}</p>
           </div>
 
           <el-form
@@ -81,7 +71,104 @@
             @submit.native.prevent="submitForm"
             class="login-form"
           >
-            <div class="input-group">
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">用户名</label>
+              <el-input
+                v-model="registerForm.username"
+                placeholder="请输入用户名"
+                prefix-icon="el-icon-user"
+                class="modern-input"
+                :class="{ 'input-error': registerErrors.username }"
+                @blur="validateRegisterField('username')"
+              />
+              <transition name="slide-fade">
+                <div v-if="registerErrors.username" class="error-msg">{{ registerErrors.username }}</div>
+              </transition>
+            </div>
+
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">姓名</label>
+              <el-input
+                v-model="registerForm.name"
+                placeholder="请输入姓名"
+                prefix-icon="el-icon-edit"
+                class="modern-input"
+                :class="{ 'input-error': registerErrors.name }"
+                @blur="validateRegisterField('name')"
+              />
+              <transition name="slide-fade">
+                <div v-if="registerErrors.name" class="error-msg">{{ registerErrors.name }}</div>
+              </transition>
+            </div>
+
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">手机号</label>
+              <el-input
+                v-model="registerForm.phone"
+                placeholder="请输入手机号"
+                prefix-icon="el-icon-phone"
+                class="modern-input"
+                :class="{ 'input-error': registerErrors.phone }"
+                @blur="validateRegisterField('phone')"
+              />
+              <transition name="slide-fade">
+                <div v-if="registerErrors.phone" class="error-msg">{{ registerErrors.phone }}</div>
+              </transition>
+            </div>
+
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">所属分组(可选)</label>
+              <el-select
+                v-model="registerForm.groups"
+                multiple
+                placeholder="请选择分组"
+                class="modern-input"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="group in groupList"
+                  :key="group.id"
+                  :label="group.name"
+                  :value="group.id"
+                ></el-option>
+              </el-select>
+            </div>
+
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">密码</label>
+              <el-input
+                v-model="registerForm.password"
+                type="password"
+                placeholder="请输入密码"
+                prefix-icon="el-icon-lock"
+                show-password
+                class="modern-input"
+                :class="{ 'input-error': registerErrors.password }"
+                @blur="validateRegisterField('password')"
+              />
+              <transition name="slide-fade">
+                <div v-if="registerErrors.password" class="error-msg">{{ registerErrors.password }}</div>
+              </transition>
+            </div>
+
+            <div class="input-group" v-if="!isLoginMode">
+              <label class="input-label">确认密码</label>
+              <el-input
+                v-model="registerForm.confirm_password"
+                type="password"
+                placeholder="请再次输入密码"
+                prefix-icon="el-icon-lock"
+                show-password
+                class="modern-input"
+                :class="{ 'input-error': registerErrors.confirm_password }"
+                @blur="validateRegisterField('confirm_password')"
+              />
+              <transition name="slide-fade">
+                <div v-if="registerErrors.confirm_password" class="error-msg">{{ registerErrors.confirm_password }}</div>
+              </transition>
+            </div>
+
+            <div class="input-group" v-if="isLoginMode">
               <label class="input-label">用户名</label>
               <el-input
                 v-model="loginForm.username"
@@ -96,7 +183,7 @@
               </transition>
             </div>
 
-            <div class="input-group">
+            <div class="input-group" v-if="isLoginMode">
               <label class="input-label">密码</label>
               <el-input
                 v-model="loginForm.password"
@@ -119,12 +206,13 @@
               :loading="isLoading"
               @click="submitForm"
             >
-              {{ isLoading ? '登录中...' : '登录系统' }}
+              {{ isLoading ? (isLoginMode ? '登录中...' : '注册中...') : (isLoginMode ? '登录系统' : '注册账号') }}
             </el-button>
           </el-form>
 
           <div class="form-footer">
-            <p>还没有账号?<a href="#" class="register-link">联系管理员注册</a></p>
+            <p v-if="isLoginMode">还没有账号?<a href="#" class="register-link" @click.prevent="switchMode">立即注册</a></p>
+            <p v-else>已有账号?<a href="#" class="register-link" @click.prevent="switchMode">返回登录</a></p>
             <p class="copyright">© 2025 APITest Pro 智能接口自动化平台</p>
           </div>
         </div>
@@ -140,16 +228,63 @@
     data() {
         return {
             isLoading: false,
+            isLoginMode: true,
             loginForm: {
                 username: "",
                 password: ""
             },
+            registerForm: {
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                groups: []
+            },
             usernameInvalid: "",
-            passwordInvalid: ""
+            passwordInvalid: "",
+            registerErrors: {
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: ""
+            },
+            groupList: []
         };
     },
 
     methods: {
+        switchMode() {
+            this.isLoginMode = !this.isLoginMode;
+            this.resetForms();
+            if (!this.isLoginMode) {
+                this.getGroupList();
+            }
+        },
+        resetForms() {
+            this.loginForm = {
+                username: "",
+                password: ""
+            };
+            this.registerForm = {
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                groups: []
+            };
+            this.usernameInvalid = "";
+            this.passwordInvalid = "";
+            this.registerErrors = {
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: ""
+            };
+        },
         validateUserName() {
             if (this.loginForm.username.replace(/(^\s*)/g, "") === "") {
                 this.usernameInvalid = "用户名不能为空";
@@ -164,18 +299,83 @@
             }
             return true;
         },
+        validateRegisterField(field) {
+            const form = this.registerForm;
+            let isValid = true;
+
+            switch (field) {
+                case 'username':
+                    if (!form.username) {
+                        this.registerErrors.username = "用户名不能为空";
+                        isValid = false;
+                    } else {
+                        this.registerErrors.username = "";
+                    }
+                    break;
+                case 'name':
+                    if (!form.name) {
+                        this.registerErrors.name = "姓名不能为空";
+                        isValid = false;
+                    } else {
+                        this.registerErrors.name = "";
+                    }
+                    break;
+                case 'phone':
+                    if (!form.phone) {
+                        this.registerErrors.phone = "手机号不能为空";
+                        isValid = false;
+                    } else if (!/^1[3-9]\d{9}$/.test(form.phone)) {
+                        this.registerErrors.phone = "手机号格式不正确";
+                        isValid = false;
+                    } else {
+                        this.registerErrors.phone = "";
+                    }
+                    break;
+                case 'password':
+                    if (!form.password) {
+                        this.registerErrors.password = "密码不能为空";
+                        isValid = false;
+                    } else if (form.password.length < 6) {
+                        this.registerErrors.password = "密码长度不能少于6位";
+                        isValid = false;
+                    } else {
+                        this.registerErrors.password = "";
+                    }
+                    break;
+                case 'confirm_password':
+                    if (!form.confirm_password) {
+                        this.registerErrors.confirm_password = "请再次输入密码";
+                        isValid = false;
+                    } else if (form.password !== form.confirm_password) {
+                        this.registerErrors.confirm_password = "两次输入的密码不一致";
+                        isValid = false;
+                    } else {
+                        this.registerErrors.confirm_password = "";
+                    }
+                    break;
+            }
+            return isValid;
+        },
+        validateRegisterForm() {
+            let isValid = true;
+            const fields = ['username', 'name', 'phone', 'password', 'confirm_password'];
+            fields.forEach(field => {
+                if (!this.validateRegisterField(field)) {
+                    isValid = false;
+                }
+            });
+            return isValid;
+        },
         handleLoginSuccess(resp) {
             if (resp.success) {
-                // 显示登录信息提示
                 this.showLoginNotification(resp);
-
-                // 原有路由跳转和存储逻辑
                 this.$router.push({ name: "ProjectList" });
                 this.$store.commit("isLogin", resp.token);
                 this.$store.commit("setUser", resp.user);
                 this.$store.commit("setName", resp.name);
                 this.$store.commit("setId", resp.id);
                 this.$store.commit("setIsSuperuser", resp.is_superuser);
+                this.$store.commit("setIsStaff", resp.is_staff);
                 this.$store.commit("setRouterName", "ProjectList");
                 this.$store.commit("setShowHosts", resp.show_hosts);
 
@@ -184,6 +384,7 @@
                 this.setLocalValue("name", resp.name);
                 this.setLocalValue("id", resp.id);
                 this.setLocalValue("is_superuser", resp.is_superuser);
+                this.setLocalValue("is_staff", resp.is_staff);
                 this.setLocalValue("routerName", "ProjectList");
                 this.setLocalValue("show_hosts", resp.show_hosts);
             } else {
@@ -207,14 +408,68 @@
             });
         },
         submitForm() {
-            if (this.validateUserName() && this.validatePassword()) {
-                this.isLoading = true;
-                this.$api.login(this.loginForm).then(resp => {
-                    this.handleLoginSuccess(resp);
-                    this.isLoading = false;
-                });
+            if (this.isLoginMode) {
+                if (this.validateUserName() && this.validatePassword()) {
+                    this.isLoading = true;
+                    this.$api.login(this.loginForm).then(resp => {
+                        this.handleLoginSuccess(resp);
+                        this.isLoading = false;
+                    }).catch(error => {
+                        this.isLoading = false;
+                        if (error.response && error.response.data && error.response.data.msg) {
+                            this.$message.error({
+                                message: error.response.data.msg,
+                                duration: 2000,
+                                center: true
+                            });
+                        }
+                    });
+                }
+            } else {
+                if (this.validateRegisterForm()) {
+                    this.isLoading = true;
+                    this.$api.register(this.registerForm).then(resp => {
+                        this.$message.success(resp.msg);
+                        this.isLoading = false;
+                        this.switchMode();
+                    }).catch(error => {
+                        this.isLoading = false;
+                        if (error.response && error.response.data && error.response.data.msg) {
+                            this.$message.error({
+                                message: error.response.data.msg,
+                                duration: 2000,
+                                center: true
+                            });
+                        } else if (error.response && error.response.data) {
+                            const errors = error.response.data;
+                            let errorMsg = '';
+                            for (let key in errors) {
+                                if (Array.isArray(errors[key])) {
+                                    errorMsg += errors[key].join('、') + ';';
+                                } else if (typeof errors[key] === 'string') {
+                                    errorMsg += errors[key] + ';';
+                                }
+                            }
+                            this.$message.error({
+                                message: errorMsg || '注册失败,请检查输入信息',
+                                duration: 3000,
+                                center: true
+                            });
+                        }
+                    });
+                }
             }
+        },
+        getGroupList() {
+            this.$api.getGroupList().then(resp => {
+                this.groupList = resp;
+            }).catch(() => {
+                this.groupList = [];
+            });
         }
+    },
+    mounted() {
+        this.getGroupList();
     }
 };
 </script>
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/project/ProjectList.vue" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/project/ProjectList.vue"
index 62d34ea..7c5a597 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/project/ProjectList.vue"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/project/ProjectList.vue"
@@ -24,6 +24,13 @@
                         >项目看板</el-button
                     >
                     <el-button
+                        type="warning"
+                        size="small"
+                        icon="el-icon-user"
+                        @click="handleUserManagement"
+                        >用户管理</el-button
+                    >
+                    <el-button
                         type="info"
                         size="small"
                         icon="el-icon-arrow-left"
@@ -375,6 +382,18 @@
         >
             <ProjectDashBoard></ProjectDashBoard>
         </el-drawer>
+
+        <el-drawer
+            title="用户管理"
+            :visible.sync="userManagementVisible"
+            direction="rtl"
+            size="80%"
+            :before-close="handleUserManagementClose"
+            :modal="false"
+            class="user-management-drawer-wrapper"
+        >
+            <user-management-drawer v-if="userManagementVisible"></user-management-drawer>
+        </el-drawer>
         <el-container>
             <el-main style="padding: 0; margin-left: 10px">
                 <el-table
@@ -550,9 +569,10 @@
 
 <script>
 import ProjectDashBoard from "@/pages/project/ProjectDashBoard.vue";
+import UserManagementDrawer from "@/pages/user/UserManagementDrawer.vue";
 export default {
     name: "ProjectList",
-    components: { ProjectDashBoard },
+    components: { ProjectDashBoard, UserManagementDrawer },
     data() {
         return {
             recentEnabledProjects: [], // 存储有启动任务的项目
@@ -563,6 +583,7 @@
             task_count: 0,
             dialogVisible: false,
             dashBoardVisible: false,
+            userManagementVisible: false,
             editVisible: false,
             hoveringSuccess: false,
             hoveringError: false,
@@ -675,6 +696,12 @@
             this.dialogVisible = true;
             this.resetProjectForm();
         },
+        handleUserManagement() {
+            this.userManagementVisible = true;
+        },
+        handleUserManagementClose() {
+            this.userManagementVisible = false;
+        },
         handleEdit(index, row) {
             this.editVisible = true;
             this.projectForm.name = row["name"];
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagement.vue" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagement.vue"
new file mode 100644
index 0000000..509ffb4
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagement.vue"
@@ -0,0 +1,687 @@
+<template>
+    <el-container>
+        <el-container>
+            <el-header style="padding-top: 10px; margin-left: 10px; height: 50px">
+                <div class="env__header">
+                    <div class="env__header--item">
+                        <el-input
+                            style="width: 300px"
+                            size="small"
+                            placeholder="请输入用户名或姓名"
+                            v-model="search"
+                            clearable
+                        >
+                        </el-input>
+                    </div>
+
+                    <div class="env__header--item">
+                        <el-button
+                            plain
+                            size="small"
+                            icon="el-icon-refresh"
+                            @click="resetSearch"
+                            >重置</el-button
+                        >
+                    </div>
+
+                    <div class="env__header--item" v-if="isSuperuser">
+                        <el-button
+                            type="primary"
+                            size="small"
+                            icon="el-icon-plus"
+                            @click="handleAdd"
+                            >新增用户</el-button
+                        >
+                    </div>
+
+                    <div class="env__header--item" v-if="isSuperuser || isStaff">
+                        <el-button
+                            type="success"
+                            size="small"
+                            icon="el-icon-s-check"
+                            @click="handleApproval"
+                            >注册用户审批</el-button
+                        >
+                    </div>
+                </div>
+            </el-header>
+
+            <el-dialog
+                :title="dialogTitle"
+                width="50%"
+                :close-on-click-modal="false"
+                :visible.sync="dialogVisible"
+                @close="handleDialogClose"
+            >
+                <el-form
+                    :inline="true"
+                    label-position="right"
+                    :model="userForm"
+                    :rules="rules"
+                    ref="userForm"
+                    label-width="100px"
+                >
+                    <el-form-item label="用户名" prop="username" v-if="isCreate">
+                        <el-input v-model="userForm.username" placeholder="请输入用户名"></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="用户名" prop="username" v-if="!isCreate">
+                        <el-input v-model="userForm.username" disabled></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="姓名" prop="name">
+                        <el-input v-model="userForm.name" placeholder="请输入姓名"></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="手机号" prop="phone">
+                        <el-input v-model="userForm.phone" placeholder="请输入手机号"></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="密码" prop="password" v-if="isCreate">
+                        <el-input
+                            type="password"
+                            v-model="userForm.password"
+                            placeholder="请输入密码"
+                        ></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="确认密码" prop="confirm_password" v-if="isCreate">
+                        <el-input
+                            type="password"
+                            v-model="userForm.confirm_password"
+                            placeholder="请再次输入密码"
+                        ></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="是否激活" prop="is_active" v-if="isSuperuser">
+                        <el-switch v-model="userForm.is_active"></el-switch>
+                    </el-form-item>
+
+                    <el-form-item label="是否管理员" prop="is_staff" v-if="isSuperuser">
+                        <el-switch v-model="userForm.is_staff"></el-switch>
+                    </el-form-item>
+
+                    <el-form-item label="超级用户" prop="is_superuser" v-if="isSuperuser">
+                        <el-switch v-model="userForm.is_superuser"></el-switch>
+                    </el-form-item>
+
+                    <el-form-item label="显示Hosts" prop="show_hosts" v-if="isSuperuser">
+                        <el-switch v-model="userForm.show_hosts"></el-switch>
+                    </el-form-item>
+
+                    <el-form-item label="所属分组" prop="groups" v-if="isSuperuser">
+                        <el-select
+                            v-model="userForm.groups"
+                            multiple
+                            placeholder="请选择分组"
+                            style="width: 100%"
+                        >
+                            <el-option
+                                v-for="group in groupList"
+                                :key="group.id"
+                                :label="group.name"
+                                :value="group.id"
+                            ></el-option>
+                        </el-select>
+                    </el-form-item>
+                </el-form>
+
+                <span slot="footer" class="dialog-footer">
+                    <el-button @click="dialogVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="handleSubmit">确 定</el-button>
+                </span>
+            </el-dialog>
+
+            <el-dialog
+                title="用户详情"
+                width="50%"
+                :close-on-click-modal="false"
+                :visible.sync="detailDialogVisible"
+            >
+                <el-form
+                    :inline="true"
+                    label-position="right"
+                    :model="userDetail"
+                    label-width="100px"
+                >
+                    <el-form-item label="用户名">
+                        <el-input v-model="userDetail.username" readonly></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="姓名">
+                        <el-input v-model="userDetail.name" readonly></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="手机号">
+                        <el-input v-model="userDetail.phone" readonly></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="是否激活">
+                        <el-tag :type="userDetail.is_active ? 'success' : 'danger'">
+                            {{ userDetail.is_active ? '是' : '否' }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="是否管理员">
+                        <el-tag :type="userDetail.is_staff ? 'success' : 'info'">
+                            {{ userDetail.is_staff ? '是' : '否' }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="超级用户">
+                        <el-tag :type="userDetail.is_superuser ? 'success' : 'info'">
+                            {{ userDetail.is_superuser ? '是' : '否' }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="显示Hosts">
+                        <el-tag :type="userDetail.show_hosts ? 'success' : 'info'">
+                            {{ userDetail.show_hosts ? '是' : '否' }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="所属分组">
+                        <el-tag
+                            v-for="group in userDetail.groups"
+                            :key="group"
+                            style="margin-right: 5px"
+                        >
+                            {{ group }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="可访问项目">
+                        <el-tag
+                            v-for="project in userDetail.accessible_projects"
+                            :key="project"
+                            style="margin-right: 5px"
+                        >
+                            {{ project }}
+                        </el-tag>
+                    </el-form-item>
+
+                    <el-form-item label="注册时间">
+                        <el-input
+                            :value="userDetail.date_joined | datetimeFormat"
+                            readonly
+                        ></el-input>
+                    </el-form-item>
+
+                    <el-form-item label="最后登录">
+                        <el-input
+                            :value="userDetail.last_login ? (userDetail.last_login | datetimeFormat) : '从未登录'"
+                            readonly
+                        ></el-input>
+                    </el-form-item>
+                </el-form>
+
+                <span slot="footer" class="dialog-footer">
+                    <el-button @click="detailDialogVisible = false">关 闭</el-button>
+                </span>
+            </el-dialog>
+
+            <el-drawer
+                title="注册用户审批"
+                :visible.sync="approvalDrawerVisible"
+                direction="rtl"
+                size="60%"
+            >
+                <div class="approval-container">
+                    <el-table
+                        :data="approvalData"
+                        v-loading="approvalLoading"
+                        stripe
+                        style="width: 100%"
+                    >
+                        <el-table-column prop="username" label="用户名" width="120"></el-table-column>
+                        <el-table-column prop="name" label="姓名" width="120"></el-table-column>
+                        <el-table-column prop="phone" label="手机号" width="120"></el-table-column>
+                        <el-table-column label="所属分组" width="200">
+                            <template slot-scope="scope">
+                                <el-tag
+                                    v-for="group in scope.row.groups"
+                                    :key="group"
+                                    size="mini"
+                                    style="margin-right: 3px"
+                                >
+                                    {{ group }}
+                                </el-tag>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="状态" width="100">
+                            <template slot-scope="scope">
+                                <el-tag :type="getStatusType(scope.row.status)">
+                                    {{ scope.row.status_display }}
+                                </el-tag>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="注册时间" width="180">
+                            <template slot-scope="scope">
+                                {{ scope.row.date_joined | datetimeFormat }}
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="操作" fixed="right" width="200">
+                            <template slot-scope="scope">
+                                <el-button
+                                    type="success"
+                                    size="mini"
+                                    icon="el-icon-check"
+                                    @click="handleApprove(scope.row, 'approve')"
+                                >
+                                    通过
+                                </el-button>
+                                <el-button
+                                    type="danger"
+                                    size="mini"
+                                    icon="el-icon-close"
+                                    @click="handleApprove(scope.row, 'reject')"
+                                >
+                                    不通过
+                                </el-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <div v-if="!approvalLoading && approvalData.length === 0" class="empty-tip">
+                        <el-empty description="暂无待审批用户"></el-empty>
+                    </div>
+                </div>
+            </el-drawer>
+
+            <el-container>
+                <el-main style="margin-left: 10px; margin-top: 10px">
+                    <div class="user-body-table">
+                        <el-table
+                            highlight-current-row
+                            stripe
+                            :data="userData"
+                            v-loading="isLoading"
+                            height="calc(100%)"
+                            @cell-mouse-enter="cellMouseEnter"
+                            @cell-mouse-leave="cellMouseLeave"
+                        >
+                            <el-table-column label="用户名" width="120">
+                                <template slot-scope="scope">
+                                    <div
+                                        :title="scope.row.username"
+                                        class="table-column"
+                                    >
+                                        {{ scope.row.username }}
+                                    </div>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="姓名" width="120">
+                                <template slot-scope="scope">
+                                    <div
+                                        :title="scope.row.name"
+                                        class="table-column"
+                                    >
+                                        {{ scope.row.name }}
+                                    </div>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="手机号" width="120">
+                                <template slot-scope="scope">
+                                    <div
+                                        :title="scope.row.phone"
+                                        class="table-column"
+                                    >
+                                        {{ scope.row.phone }}
+                                    </div>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="是否激活" width="100">
+                                <template slot-scope="scope">
+                                    <el-tag :type="scope.row.is_active ? 'success' : 'danger'">
+                                        {{ scope.row.is_active ? '是' : '否' }}
+                                    </el-tag>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="是否管理员" width="100">
+                                <template slot-scope="scope">
+                                    <el-tag :type="scope.row.is_staff ? 'success' : 'info'">
+                                        {{ scope.row.is_staff ? '是' : '否' }}
+                                    </el-tag>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="超级用户" width="100">
+                                <template slot-scope="scope">
+                                    <el-tag :type="scope.row.is_superuser ? 'success' : 'info'">
+                                        {{ scope.row.is_superuser ? '是' : '否' }}
+                                    </el-tag>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="所属分组" width="200">
+                                <template slot-scope="scope">
+                                    <div class="table-column">
+                                        <el-tag
+                                            v-for="group in scope.row.groups"
+                                            :key="group"
+                                            size="mini"
+                                            style="margin-right: 3px"
+                                        >
+                                            {{ group }}
+                                        </el-tag>
+                                    </div>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="注册时间" width="180">
+                                <template slot-scope="scope">
+                                    <div>
+                                        {{ scope.row.date_joined | datetimeFormat }}
+                                    </div>
+                                </template>
+                            </el-table-column>
+
+                            <el-table-column label="操作" width="200" fixed="right">
+                                <template slot-scope="scope">
+                                    <el-row v-show="currentRow === scope.row">
+                                        <el-button
+                                            type="success"
+                                            icon="el-icon-view"
+                                            title="查看"
+                                            circle
+                                            size="mini"
+                                            @click="handleView(scope.row)"
+                                        ></el-button>
+                                        <el-button
+                                            type="primary"
+                                            icon="el-icon-edit"
+                                            title="编辑"
+                                            circle
+                                            size="mini"
+                                            v-if="isSuperuser"
+                                            @click="handleEdit(scope.row)"
+                                        ></el-button>
+                                        <el-button
+                                            type="danger"
+                                            icon="el-icon-delete"
+                                            title="删除"
+                                            circle
+                                            size="mini"
+                                            v-if="isSuperuser && scope.row.id !== currentUserId"
+                                            @click="handleDelete(scope.row)"
+                                        ></el-button>
+                                    </el-row>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </div>
+                </el-main>
+            </el-container>
+        </el-container>
+    </el-container>
+</template>
+
+<script>
+export default {
+    name: "UserManagement",
+    data() {
+        var validateConfirmPassword = (rule, value, callback) => {
+            if (value !== this.userForm.password) {
+                callback(new Error("两次输入的密码不一致"));
+            } else {
+                callback();
+            }
+        };
+
+        return {
+            search: "",
+            currentRow: "",
+            isLoading: true,
+            userData: [],
+            groupList: [],
+            dialogVisible: false,
+            detailDialogVisible: false,
+            approvalDrawerVisible: false,
+            approvalLoading: false,
+            approvalData: [],
+            isCreate: false,
+            isSuperuser: false,
+            isStaff: false,
+            currentUserId: null,
+            userForm: {
+                id: null,
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                is_active: true,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: []
+            },
+            userDetail: {
+                username: "",
+                name: "",
+                phone: "",
+                is_active: false,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: [],
+                accessible_projects: [],
+                date_joined: "",
+                last_login: ""
+            },
+            rules: {
+                username: [
+                    { required: true, message: "请输入用户名", trigger: "blur" }
+                ],
+                name: [
+                    { required: true, message: "请输入姓名", trigger: "blur" }
+                ],
+                password: [
+                    { required: true, message: "请输入密码", trigger: "blur" },
+                    { min: 6, message: "密码长度不能少于6位", trigger: "blur" }
+                ],
+                confirm_password: [
+                    { required: true, message: "请再次输入密码", trigger: "blur" },
+                    { validator: validateConfirmPassword, trigger: "blur" }
+                ]
+            }
+        };
+    },
+    computed: {
+        dialogTitle() {
+            return this.isCreate ? "新增用户" : "编辑用户";
+        }
+    },
+    methods: {
+        cellMouseEnter(row) {
+            this.currentRow = row;
+        },
+        cellMouseLeave() {
+            this.currentRow = "";
+        },
+        handleAdd() {
+            this.isCreate = true;
+            this.dialogVisible = true;
+            this.resetForm();
+        },
+        handleEdit(row) {
+            this.isCreate = false;
+            this.dialogVisible = true;
+            this.userForm = {
+                id: row.id,
+                username: row.username,
+                name: row.name,
+                phone: row.phone,
+                is_active: row.is_active,
+                is_staff: row.is_staff,
+                is_superuser: row.is_superuser,
+                show_hosts: row.show_hosts,
+                groups: []
+            };
+        },
+        handleView(row) {
+            this.getUserDetail(row.id);
+        },
+        handleDelete(row) {
+            this.$confirm("确定要删除该用户吗?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning"
+            }).then(() => {
+                this.$api.deleteUser(row.id).then(() => {
+                    this.$message.success("删除成功");
+                    this.getUserList();
+                });
+            }).catch(() => {});
+        },
+        handleSubmit() {
+            this.$refs.userForm.validate(valid => {
+                if (valid) {
+                    if (this.isCreate) {
+                        this.$api.createUser(this.userForm).then(() => {
+                            this.$message.success("创建成功");
+                            this.dialogVisible = false;
+                            this.getUserList();
+                        });
+                    } else {
+                        this.$api.updateUser(this.userForm.id, this.userForm).then(() => {
+                            this.$message.success("更新成功");
+                            this.dialogVisible = false;
+                            this.getUserList();
+                        });
+                    }
+                }
+            });
+        },
+        handleDialogClose() {
+            this.$refs.userForm.resetFields();
+        },
+        resetForm() {
+            this.userForm = {
+                id: null,
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                is_active: true,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: []
+            };
+        },
+        getUserList() {
+            this.isLoading = true;
+            this.$api.getUserManagementList({ search: this.search }).then(resp => {
+                this.userData = resp.results || resp;
+                this.isLoading = false;
+            });
+        },
+        getUserDetail(userId) {
+            this.$api.getUserDetail(userId).then(resp => {
+                this.userDetail = resp;
+                this.detailDialogVisible = true;
+            });
+        },
+        getGroupList() {
+            this.$api.getGroupList().then(resp => {
+                this.groupList = resp;
+            });
+        },
+        resetSearch() {
+            this.search = "";
+            this.getUserList();
+        },
+        handleApproval() {
+            this.approvalDrawerVisible = true;
+            this.getApprovalList();
+        },
+        getApprovalList() {
+            this.approvalLoading = true;
+            this.$api.getUserApprovalList({ search: this.search }).then(resp => {
+                this.approvalData = resp.results || resp;
+                this.approvalLoading = false;
+            }).catch(() => {
+                this.approvalLoading = false;
+            });
+        },
+        getStatusType(status) {
+            const statusMap = {
+                'pending': 'warning',
+                'approved': 'success',
+                'rejected': 'danger'
+            };
+            return statusMap[status] || 'info';
+        },
+        handleApprove(row, action) {
+            const actionText = action === 'approve' ? '通过' : '不通过';
+            this.$confirm(`确定要${actionText}该用户的注册申请吗?`, "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning"
+            }).then(() => {
+                this.$api.approveUser(row.id, { action: action }).then(() => {
+                    this.$message.success(`用户审批已${actionText}`);
+                    this.getApprovalList();
+                });
+            }).catch(() => {});
+        }
+    },
+    watch: {
+        search() {
+            this.getUserList();
+        }
+    },
+    mounted() {
+        this.isSuperuser = this.$store.state.is_superuser;
+        this.isStaff = this.$store.state.is_staff;
+        this.currentUserId = this.$store.state.id;
+        this.getUserList();
+        if (this.isSuperuser) {
+            this.getGroupList();
+        }
+    }
+};
+</script>
+
+<style scoped>
+.env__header {
+    display: flex;
+    align-items: center;
+    margin-left: -30px;
+}
+
+.env__header--item {
+    display: flex;
+    margin-left: 10px;
+}
+
+.table-column {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.user-body-table {
+    position: fixed;
+    bottom: 0;
+    right: 0;
+    left: 220px;
+    top: 100px;
+    margin-left: -10px;
+    padding-bottom: 60px;
+}
+
+.approval-container {
+    padding: 20px;
+}
+
+.empty-tip {
+    text-align: center;
+    padding: 40px 0;
+}
+</style>
\ No newline at end of file
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagementDrawer.vue" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagementDrawer.vue"
new file mode 100644
index 0000000..7cd54b1
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/pages/user/UserManagementDrawer.vue"
@@ -0,0 +1,591 @@
+<template>
+    <div class="user-management-drawer">
+        <div class="toolbar">
+            <el-input
+                style="width: 300px"
+                size="small"
+                placeholder="请输入用户名或姓名"
+                v-model="search"
+                clearable
+            >
+            </el-input>
+
+            <el-button
+                plain
+                size="small"
+                icon="el-icon-refresh"
+                @click="resetSearch"
+                >重置</el-button
+            >
+
+            <el-button
+                v-if="isSuperuser"
+                type="primary"
+                size="small"
+                icon="el-icon-plus"
+                @click="handleAdd"
+                >新增用户</el-button
+            >
+        </div>
+
+        <el-dialog
+            :title="dialogTitle"
+            width="50%"
+            :close-on-click-modal="false"
+            :modal="false"
+            :visible.sync="dialogVisible"
+            @close="handleDialogClose"
+            append-to-body
+        >
+            <el-form
+                :inline="true"
+                label-position="right"
+                :model="userForm"
+                :rules="rules"
+                ref="userForm"
+                label-width="100px"
+            >
+                <el-form-item label="用户名" prop="username" v-if="isCreate">
+                    <el-input v-model="userForm.username" placeholder="请输入用户名"></el-input>
+                </el-form-item>
+
+                <el-form-item label="用户名" prop="username" v-if="!isCreate">
+                    <el-input v-model="userForm.username" disabled></el-input>
+                </el-form-item>
+
+                <el-form-item label="姓名" prop="name">
+                    <el-input v-model="userForm.name" placeholder="请输入姓名"></el-input>
+                </el-form-item>
+
+                <el-form-item label="手机号" prop="phone">
+                    <el-input v-model="userForm.phone" placeholder="请输入手机号"></el-input>
+                </el-form-item>
+
+                <el-form-item label="密码" prop="password" v-if="isCreate">
+                    <el-input
+                        type="password"
+                        v-model="userForm.password"
+                        placeholder="请输入密码"
+                    ></el-input>
+                </el-form-item>
+
+                <el-form-item label="确认密码" prop="confirm_password" v-if="isCreate">
+                    <el-input
+                        type="password"
+                        v-model="userForm.confirm_password"
+                        placeholder="请再次输入密码"
+                    ></el-input>
+                </el-form-item>
+
+                <el-form-item label="是否激活" prop="is_active">
+                    <el-switch v-model="userForm.is_active" :disabled="!isSuperuser"></el-switch>
+                </el-form-item>
+
+                <el-form-item label="是否管理员" prop="is_staff">
+                    <el-switch v-model="userForm.is_staff" :disabled="!isSuperuser"></el-switch>
+                </el-form-item>
+
+                <el-form-item label="超级用户" prop="is_superuser">
+                    <el-switch v-model="userForm.is_superuser" :disabled="!isSuperuser"></el-switch>
+                </el-form-item>
+
+                <el-form-item label="显示Hosts" prop="show_hosts">
+                    <el-switch v-model="userForm.show_hosts" :disabled="!isSuperuser"></el-switch>
+                </el-form-item>
+
+                <el-form-item label="所属分组" prop="groups">
+                    <el-select
+                        v-model="userForm.groups"
+                        multiple
+                        placeholder="请选择分组"
+                        style="width: 100%"
+                        :disabled="!isSuperuser"
+                    >
+                        <el-option
+                            v-for="group in groupList"
+                            :key="group.id"
+                            :label="group.name"
+                            :value="group.id"
+                        ></el-option>
+                    </el-select>
+                </el-form-item>
+            </el-form>
+
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="dialogVisible = false">取 消</el-button>
+                <el-button type="primary" @click="handleSubmit">确 定</el-button>
+            </span>
+        </el-dialog>
+
+        <el-dialog
+            title="用户详情"
+            width="50%"
+            :close-on-click-modal="false"
+            :modal="false"
+            :visible.sync="detailDialogVisible"
+            append-to-body
+        >
+            <el-form
+                :inline="true"
+                label-position="right"
+                :model="userDetail"
+                label-width="100px"
+            >
+                <el-form-item label="用户名">
+                    <el-input v-model="userDetail.username" readonly></el-input>
+                </el-form-item>
+
+                <el-form-item label="姓名">
+                    <el-input v-model="userDetail.name" readonly></el-input>
+                </el-form-item>
+
+                <el-form-item label="手机号">
+                    <el-input v-model="userDetail.phone" readonly></el-input>
+                </el-form-item>
+
+                <el-form-item label="是否激活">
+                    <el-tag :type="userDetail.is_active ? 'success' : 'danger'">
+                        {{ userDetail.is_active ? '是' : '否' }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="是否管理员">
+                    <el-tag :type="userDetail.is_staff ? 'success' : 'info'">
+                        {{ userDetail.is_staff ? '是' : '否' }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="超级用户">
+                    <el-tag :type="userDetail.is_superuser ? 'success' : 'info'">
+                        {{ userDetail.is_superuser ? '是' : '否' }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="显示Hosts">
+                    <el-tag :type="userDetail.show_hosts ? 'success' : 'info'">
+                        {{ userDetail.show_hosts ? '是' : '否' }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="所属分组">
+                    <el-tag
+                        v-for="group in userDetail.groups"
+                        :key="group"
+                        style="margin-right: 5px"
+                    >
+                        {{ group }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="可访问项目">
+                    <el-tag
+                        v-for="project in userDetail.accessible_projects"
+                        :key="project"
+                        style="margin-right: 5px"
+                    >
+                        {{ project }}
+                    </el-tag>
+                </el-form-item>
+
+                <el-form-item label="注册时间">
+                    <el-input
+                        :value="userDetail.date_joined | datetimeFormat"
+                        readonly
+                    ></el-input>
+                </el-form-item>
+
+                <el-form-item label="最后登录">
+                    <el-input
+                        :value="formatLastLogin(userDetail.last_login)"
+                        readonly
+                    ></el-input>
+                </el-form-item>
+            </el-form>
+
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="detailDialogVisible = false">关 闭</el-button>
+            </span>
+        </el-dialog>
+
+        <div class="table-container">
+            <el-table
+                highlight-current-row
+                stripe
+                :data="userData"
+                v-loading="isLoading"
+                height="calc(100vh - 150px)"
+                @cell-mouse-enter="cellMouseEnter"
+                @cell-mouse-leave="cellMouseLeave"
+            >
+                <el-table-column label="用户名" width="120">
+                    <template slot-scope="scope">
+                        <div
+                            :title="scope.row.username"
+                            class="table-column"
+                        >
+                            {{ scope.row.username }}
+                        </div>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="姓名" width="120">
+                    <template slot-scope="scope">
+                        <div
+                            :title="scope.row.name"
+                            class="table-column"
+                        >
+                            {{ scope.row.name }}
+                        </div>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="手机号" width="120">
+                    <template slot-scope="scope">
+                        <div
+                            :title="scope.row.phone"
+                            class="table-column"
+                        >
+                            {{ scope.row.phone }}
+                        </div>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="是否激活" width="100">
+                    <template slot-scope="scope">
+                        <el-tag :type="scope.row.is_active ? 'success' : 'danger'">
+                            {{ scope.row.is_active ? '是' : '否' }}
+                        </el-tag>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="是否管理员" width="100">
+                    <template slot-scope="scope">
+                        <el-tag :type="scope.row.is_staff ? 'success' : 'info'">
+                            {{ scope.row.is_staff ? '是' : '否' }}
+                        </el-tag>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="超级用户" width="100">
+                    <template slot-scope="scope">
+                        <el-tag :type="scope.row.is_superuser ? 'success' : 'info'">
+                            {{ scope.row.is_superuser ? '是' : '否' }}
+                        </el-tag>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="所属分组" width="200">
+                    <template slot-scope="scope">
+                        <div class="table-column">
+                            <el-tag
+                                v-for="group in scope.row.groups"
+                                :key="group"
+                                size="mini"
+                                style="margin-right: 3px"
+                            >
+                                {{ group }}
+                            </el-tag>
+                        </div>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="注册时间" width="180">
+                    <template slot-scope="scope">
+                        <div>
+                            {{ scope.row.date_joined | datetimeFormat }}
+                        </div>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="操作" width="200" fixed="right">
+                    <template slot-scope="scope">
+                        <el-row v-show="currentRow === scope.row">
+                            <el-button
+                                type="success"
+                                icon="el-icon-view"
+                                title="查看"
+                                circle
+                                size="mini"
+                                @click="handleView(scope.row)"
+                            ></el-button>
+                            <el-button
+                                type="primary"
+                                icon="el-icon-edit"
+                                title="编辑"
+                                circle
+                                size="mini"
+                                v-if="isSuperuser"
+                                @click="handleEdit(scope.row)"
+                            ></el-button>
+                            <el-button
+                                type="danger"
+                                icon="el-icon-delete"
+                                title="删除"
+                                circle
+                                size="mini"
+                                v-if="isSuperuser && scope.row.id !== currentUserId"
+                                @click="handleDelete(scope.row)"
+                            ></el-button>
+                        </el-row>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: "UserManagementDrawer",
+    data() {
+        var validateConfirmPassword = (rule, value, callback) => {
+            if (value !== this.userForm.password) {
+                callback(new Error("两次输入的密码不一致"));
+            } else {
+                callback();
+            }
+        };
+
+        return {
+            search: "",
+            currentRow: "",
+            isLoading: true,
+            userData: [],
+            groupList: [],
+            dialogVisible: false,
+            detailDialogVisible: false,
+            isCreate: false,
+            isSuperuser: false,
+            currentUserId: null,
+            userForm: {
+                id: null,
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                is_active: true,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: []
+            },
+            userDetail: {
+                username: "",
+                name: "",
+                phone: "",
+                is_active: false,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: [],
+                accessible_projects: [],
+                date_joined: "",
+                last_login: ""
+            },
+            rules: {
+                username: [
+                    { required: true, message: "请输入用户名", trigger: "blur" }
+                ],
+                name: [
+                    { required: true, message: "请输入姓名", trigger: "blur" }
+                ],
+                password: [
+                    { required: true, message: "请输入密码", trigger: "blur" },
+                    { min: 6, message: "密码长度不能少于6位", trigger: "blur" }
+                ],
+                confirm_password: [
+                    { required: true, message: "请再次输入密码", trigger: "blur" },
+                    { validator: validateConfirmPassword, trigger: "blur" }
+                ]
+            }
+        };
+    },
+    computed: {
+        dialogTitle() {
+            return this.isCreate ? "新增用户" : "编辑用户";
+        }
+    },
+    methods: {
+        cellMouseEnter(row) {
+            this.currentRow = row;
+        },
+        cellMouseLeave() {
+            this.currentRow = "";
+        },
+        handleAdd() {
+            this.isCreate = true;
+            this.dialogVisible = true;
+            this.resetForm();
+        },
+        handleEdit(row) {
+            this.isCreate = false;
+            this.dialogVisible = true;
+            const groupIds = this.getGroupIdsByName(row.groups || []);
+            this.userForm = {
+                id: row.id,
+                username: row.username,
+                name: row.name,
+                phone: row.phone,
+                is_active: row.is_active,
+                is_staff: row.is_staff,
+                is_superuser: row.is_superuser,
+                show_hosts: row.show_hosts,
+                groups: groupIds
+            };
+        },
+        handleView(row) {
+            this.getUserDetail(row.id);
+        },
+        handleDelete(row) {
+            this.$confirm("确定要删除该用户吗?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning"
+            }).then(() => {
+                this.$api.deleteUser(row.id).then(() => {
+                    this.$message.success("删除成功");
+                    this.getUserList();
+                });
+            }).catch(() => {});
+        },
+        handleSubmit() {
+            this.$refs.userForm.validate(valid => {
+                if (valid) {
+                    console.log("提交表单数据:", this.userForm);
+                    if (this.isCreate) {
+                        this.$api.createUser(this.userForm).then(() => {
+                            this.$message.success("创建成功");
+                            this.dialogVisible = false;
+                            this.getUserList();
+                        }).catch(err => {
+                            console.error("创建用户失败:", err);
+                            console.error("错误详情:", err.response ? err.response.data : err.message);
+                            this.$message.error("创建用户失败,请检查输入信息");
+                        });
+                    } else {
+                        this.$api.updateUser(this.userForm.id, this.userForm).then(() => {
+                            this.$message.success("更新成功");
+                            this.dialogVisible = false;
+                            this.getUserList();
+                        }).catch(err => {
+                            console.error("更新用户失败:", err);
+                            console.error("错误详情:", err.response ? err.response.data : err.message);
+                            this.$message.error("更新用户失败,请检查输入信息");
+                        });
+                    }
+                } else {
+                    this.$message.warning("请检查表单输入");
+                }
+            });
+        },
+        handleDialogClose() {
+            this.$refs.userForm.resetFields();
+        },
+        resetForm() {
+            this.userForm = {
+                id: null,
+                username: "",
+                name: "",
+                phone: "",
+                password: "",
+                confirm_password: "",
+                is_active: true,
+                is_staff: false,
+                is_superuser: false,
+                show_hosts: false,
+                groups: []
+            };
+        },
+        getUserList() {
+            this.isLoading = true;
+            console.log("搜索关键词:", this.search);
+            this.$api.getUserManagementList({ search: this.search }).then(resp => {
+                console.log("搜索结果:", resp);
+                this.userData = resp.results || resp;
+                this.isLoading = false;
+            }).catch(err => {
+                console.error("获取用户列表失败:", err);
+                this.isLoading = false;
+            });
+        },
+        getUserDetail(userId) {
+            this.$api.getUserDetail(userId).then(resp => {
+                this.userDetail = resp;
+                this.detailDialogVisible = true;
+            });
+        },
+        getGroupList() {
+            this.$api.getGroupList().then(resp => {
+                this.groupList = resp;
+            });
+        },
+        resetSearch() {
+            this.search = "";
+            this.getUserList();
+        },
+        formatLastLogin(lastLogin) {
+            if (!lastLogin) {
+                return "从未登录";
+            }
+            return lastLogin;
+        },
+        getGroupIdsByName(groupNames) {
+            if (!groupNames || groupNames.length === 0) {
+                return [];
+            }
+            const groupMap = {};
+            this.groupList.forEach(group => {
+                groupMap[group.name] = group.id;
+            });
+            return groupNames.map(name => groupMap[name]).filter(id => id !== undefined);
+        }
+    },
+    watch: {
+        search() {
+            this.getUserList();
+        }
+    },
+    mounted() {
+        this.isSuperuser = this.$store.state.is_superuser;
+        this.currentUserId = this.$store.state.id;
+        this.getUserList();
+        if (this.isSuperuser) {
+            this.getGroupList();
+        }
+    }
+};
+</script>
+
+<style scoped>
+.user-management-drawer {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+}
+
+.toolbar {
+    display: flex;
+    align-items: center;
+    padding: 10px 20px;
+    gap: 10px;
+    background: #f5f5f5;
+    border-bottom: 1px solid #e0e0e0;
+}
+
+.toolbar .el-input {
+    margin-right: 10px;
+}
+
+.table-container {
+    padding: 20px;
+    height: calc(100vh - 150px);
+    overflow: auto;
+}
+
+.table-column {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+</style>
\ No newline at end of file
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/restful/api.js" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/restful/api.js"
index 8a91dad..9e4ced7 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/restful/api.js"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/restful/api.js"
@@ -10,15 +10,14 @@
 
 axios.interceptors.request.use(
     function(config) {
-        if (
-            !config.url.startsWith("/api/user") ||
-            config.url === "/api/user/list" ||
-            config.url === "/api/user/login_log"
-        ) {
-            // 在请求拦截中,每次请求,都会加上一个Authorization头
+        const noAuthUrls = [
+            '/api/user/login',
+            '/api/user/register',
+            '/api/user/groups'
+        ];
+        
+        if (!noAuthUrls.includes(config.url)) {
             config.headers.Authorization = store.token;
-
-            // 取url地址的第四位作为projectId, 如果不存在,默认设置为0
             let projectId = window.location.pathname.split("/")[3];
             projectId = projectId ? projectId : 0;
             config.headers["Project"] = projectId;
@@ -58,12 +57,6 @@
                         duration: 2000
                     });
                 }
-                if (status === 403) {
-                    Message.error({
-                        message: error.response.data.detail,
-                        duration: 2000
-                    });
-                }
             } catch (e) {
                 Message.error({
                     message: "服务器连接超时, 请重试",
@@ -77,6 +70,10 @@
 
 export const login = params => {
     return axios.post("/api/user/login", params).then(res => res.data);
+};
+
+export const register = params => {
+    return axios.post("/api/user/register", params).then(res => res.data);
 };
 
 export const addProject = params => {
@@ -143,7 +140,7 @@
 
 export const getGroupList = () => {
     return axios
-        .get("/api/lunarlink/project/groups")
+        .get("/api/user/groups")
         .then(res => res.data);
 };
 
@@ -527,3 +524,31 @@
     }).then(res => res.data);
 };
 
+export const getUserManagementList = (params) => {
+    return axios.get("/api/user/management/", { params }).then(res => res.data);
+};
+
+export const createUser = (data) => {
+    return axios.post("/api/user/management/", data).then(res => res.data);
+};
+
+export const updateUser = (userId, data) => {
+    return axios.patch(`/api/user/management/${userId}/`, data).then(res => res.data);
+};
+
+export const deleteUser = (userId) => {
+    return axios.delete(`/api/user/management/${userId}/`).then(res => res.data);
+};
+
+export const getUserDetail = (userId) => {
+    return axios.get(`/api/user/management/${userId}/`).then(res => res.data);
+};
+
+export const getUserApprovalList = (params) => {
+    return axios.get("/api/user/approval/", { params }).then(res => res.data);
+};
+
+export const approveUser = (userId, data) => {
+    return axios.post(`/api/user/approval/${userId}/approve/`, data).then(res => res.data);
+};
+
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/mutations.js" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/mutations.js"
index 3690295..840c041 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/mutations.js"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/mutations.js"
@@ -31,6 +31,10 @@
         state.is_superuser = value;
     },
 
+    setIsStaff(state, value) {
+        state.is_staff = value;
+    },
+
     setShowHosts(state, value) {
         state.show_hosts = value;
     }
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/state.js" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/state.js"
index 2dcd625..818a8ce 100644
--- "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/state.js"
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/frontend/src/store/state.js"
@@ -5,6 +5,7 @@
     token: null,
     user: null,
     is_superuser: false,
+    is_staff: false,
     show_hosts: false,
     duration: 2000,
     report_path: "/api/lunarlink/reports/",
diff --git "a/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/\346\263\250\345\206\214\345\256\241\346\211\271\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md" "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/\346\263\250\345\206\214\345\256\241\346\211\271\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..ef626b2
--- /dev/null
+++ "b/\346\265\213\350\257\225\347\273\204/Test_platform/Interface_automation/\346\263\250\345\206\214\345\256\241\346\211\271\345\212\237\350\203\275\346\265\213\350\257\225\346\214\207\345\215\227.md"
@@ -0,0 +1,144 @@
+# 用户注册审批功能测试指南
+
+## 功能概述
+
+本系统实现了完整的用户注册审批流程,包括:
+
+1. 用户自主注册功能
+2. 管理员审批功能
+3. 登录状态检查
+4. 多管理员支持(一人审批即可)
+
+## 数据库迁移
+
+由于项目依赖问题,请手动执行以下SQL语句添加status字段:
+
+```sql
+ALTER TABLE lunaruser_myuser 
+ADD COLUMN status VARCHAR(20) DEFAULT 'approved' 
+COMMENT '用户状态';
+```
+
+或者运行以下Python脚本:
+
+```bash
+cd backend
+python add_status_field.py
+```
+
+## 测试步骤
+
+### 1. 用户注册测试
+
+1. 访问登录页面
+2. 点击"立即注册"链接
+3. 填写注册表单:
+   - 用户名(必填)
+   - 姓名(必填)
+   - 手机号(必填)
+   - 密码(必填,至少6位)
+   - 确认密码(必填)
+   - 所属分组(可选)
+4. 点击"注册账号"
+5. 预期结果:显示"你的注册申请已提交,待管理员审核中!"
+
+### 2. 管理员审批测试
+
+1. 使用超级管理员账号登录
+2. 进入用户管理页面
+3. 点击"注册用户审批"按钮
+4. 查看待审批用户列表
+5. 对某个用户点击"通过"或"不通过"
+6. 预期结果:
+   - 通过后,用户状态变为"已通过",is_active变为true
+   - 不通过后,用户状态变为"未通过"
+
+### 3. 登录状态检查测试
+
+#### 待审核状态登录
+1. 使用待审核的用户名和密码登录
+2. 预期结果:显示"你提交的注册还在审批中,暂时无法登录,可联系管理员确认!"
+
+#### 未通过状态登录
+1. 使用未通过的用户名和密码登录
+2. 预期结果:显示"你的注册申请未通过审核,无法登录!"
+
+#### 已通过状态登录
+1. 使用已通过的用户名和密码登录
+2. 预期结果:正常登录
+
+## API接口说明
+
+### 注册接口
+- URL: `POST /api/user/register`
+- 参数:
+  ```json
+  {
+    "username": "testuser",
+    "name": "测试用户",
+    "phone": "13800138000",
+    "password": "123456",
+    "confirm_password": "123456",
+    "groups": []
+  }
+  ```
+- 响应:
+  ```json
+  {
+    "success": true,
+    "msg": "你的注册申请已提交,待管理员审核中!",
+    "data": {
+      "id": 1,
+      "username": "testuser"
+    }
+  }
+  ```
+
+### 审批列表接口
+- URL: `GET /api/user/approval/`
+- 响应:
+  ```json
+  {
+    "success": true,
+    "results": [...]
+  }
+  ```
+
+### 审批操作接口
+- URL: `POST /api/user/approval/{user_id}/approve/`
+- 参数:
+  ```json
+  {
+    "action": "approve"
+  }
+  ```
+- 响应:
+  ```json
+  {
+    "success": true,
+    "msg": "用户审批已通过"
+  }
+  ```
+
+## 文件修改清单
+
+### 后端文件
+1. `backend/apps/lunaruser/models.py` - 添加status字段
+2. `backend/apps/lunaruser/serializers.py` - 添加注册和审批序列化器
+3. `backend/apps/lunaruser/views.py` - 添加注册和审批视图
+4. `backend/apps/lunaruser/urls.py` - 添加注册和审批路由
+5. `backend/apps/lunaruser/migrations/0003_myuser_status.py` - 数据库迁移文件
+
+### 前端文件
+1. `frontend/src/pages/login/Login.vue` - 添加注册表单
+2. `frontend/src/pages/user/UserManagement.vue` - 添加审批抽屉
+3. `frontend/src/restful/api.js` - 添加API接口
+4. `frontend/src/api/user.js` - 添加API接口
+
+## 注意事项
+
+1. 所有现有用户的status默认为'approved',可以正常登录
+2. 新注册用户的status默认为'pending',需要管理员审批
+3. 审批通过后,status变为'approved',is_active变为true
+4. 审批不通过后,status变为'rejected',is_active保持false
+5. 多个超级管理员时,任何一人审批即可生效

--
Gitblit v1.9.1