在这里插入图片描述

家庭成员管理是小区门禁系统中的重要功能,它为主用户提供了管理家庭成员信息和权限的便捷方式,同时确保了家庭访问的安全性。

在实际项目中,家庭成员管理需要解决几个关键问题:

  • 如何清晰展示家庭成员列表和状态
  • 如何支持成员的添加、编辑和删除操作
  • 如何管理不同成员的访问权限
  • 如何处理成员关系的验证和确认

这篇讲家庭成员管理页面的实现,重点是如何让家庭成员管理变得简单直观且安全可控。

对应源码

  • lib/pages/profile/family_members_page.dart

家庭成员管理页面的设计思路是:列表展示 + 权限管理 + 操作便捷

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'add_family_member_page.dart';

class FamilyMembersPage extends StatefulWidget {
  const FamilyMembersPage({Key? key}) : super(key: key);

  
  State<FamilyMembersPage> createState() => _FamilyMembersPageState();
}

class _FamilyMembersPageState extends State<FamilyMembersPage> {
  List<Map<String, dynamic>> _familyMembers = [];
  bool _isLoading = false;

  
  void initState() {
    super.initState();
    _loadFamilyMembers();
  }

基础结构说明

  • 家庭成员管理页面需要维护成员列表状态,所以用 StatefulWidget
  • 导入 add_family_member_page.dart 支持添加新成员。
  • _familyMembers 存储所有家庭成员信息。
  • _isLoading 控制加载状态,提供良好的用户体验。
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('家庭成员'),
        centerTitle: true,
        actions: [
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: () => _addFamilyMember(),
          ),
        ],
      ),
      body: RefreshIndicator(
        onRefresh: _refreshMembers,
        child: Column(
          children: [
            // 统计信息
            Container(
              width: double.infinity,
              padding: EdgeInsets.all(16.w),
              margin: EdgeInsets.all(16.w),
              decoration: BoxDecoration(
                gradient: const LinearGradient(
                  colors: [Color(0xFF9C27B0), Color(0xFF7B1FA2)],
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                ),
                borderRadius: BorderRadius.circular(12.r),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  _buildStatItem('成员总数', '${_familyMembers.length}'),
                  _buildStatItem('活跃成员', '${_getActiveMembersCount()}'),
                  _buildStatItem('待审核', '${_getPendingMembersCount()}'),
                ],
              ),
            ),

统计信息设计

  • 顶部紫色渐变统计卡片,视觉突出。
  • 显示成员总数、活跃成员数、待审核数。
  • 使用 _buildStatItem 统一统计项样式。
  • 统计信息实时更新,反映当前成员状态。
            // 成员列表
            Expanded(
              child: _isLoading
                  ? const Center(child: CircularProgressIndicator())
                  : _familyMembers.isEmpty
                      ? _buildEmptyState()
                      : ListView.builder(
                          padding: EdgeInsets.symmetric(horizontal: 16.w),
                          itemCount: _familyMembers.length,
                          itemBuilder: (context, index) {
                            return _buildMemberItem(_familyMembers[index], index);
                          },
                        ),
            ),
          ],
        ),
      ),
    );
  }

页面布局设计

  • 使用 RefreshIndicator 支持下拉刷新。
  • 统计信息固定在顶部,成员列表占据主要空间。
  • 空状态提示用户添加第一个家庭成员。
  • 加载状态显示进度器,用户体验友好。
  Widget _buildStatItem(String label, String value) {
    return Column(
      children: [
        Text(
          value,
          style: TextStyle(
            color: Colors.white,
            fontSize: 20.sp,
            fontWeight: FontWeight.bold,
          ),
        ),
        SizedBox(height: 4.h),
        Text(
          label,
          style: TextStyle(
            color: Colors.white70,
            fontSize: 12.sp,
          ),
        ),
      ],
    );
  }

统计项组件

  • 统一的统计项样式,数值大而醒目。
  • 标签使用较小字体和半透明白色。
  • 垂直布局,数值在上,标签在下。
  • 三个统计项均匀分布,视觉平衡。
  Widget _buildEmptyState() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.family_restroom,
            size: 80.sp,
            color: Colors.grey[300],
          ),
          SizedBox(height: 16.h),
          Text(
            '暂无家庭成员',
            style: TextStyle(
              fontSize: 16.sp,
              color: Colors.grey[600],
              fontWeight: FontWeight.w500,
            ),
          ),
          SizedBox(height: 8.h),
          Text(
            '点击右上角添加第一个家庭成员',
            style: TextStyle(
              fontSize: 12.sp,
              color: Colors.grey[500],
            ),
          ),
          SizedBox(height: 24.h),
          ElevatedButton.icon(
            onPressed: _addFamilyMember,
            icon: const Icon(Icons.add),
            label: const Text('添加成员'),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.purple,
              foregroundColor: Colors.white,
              padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h),
            ),
          ),
        ],
      ),
    );
  }

空状态设计

  • 大图标和文字说明当前状态。
  • 提供明确的操作指引。
  • 添加按钮使用紫色主题色,与统计卡片呼应。
  • 布局居中,视觉上更平衡。
  Widget _buildMemberItem(Map<String, dynamic> member, int index) {
    final isActive = member['status'] == 'active';
    final isPending = member['status'] == 'pending';
    
    return Container(
      margin: EdgeInsets.only(bottom: 12.h),
      padding: EdgeInsets.all(16.w),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12.r),
        border: Border.all(
          color: isPending ? Colors.orange[300]! : Colors.grey[200]!,
          width: isPending ? 2.w : 1.w,
        ),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.1),
            blurRadius: 4.r,
            offset: Offset(0, 2.h),
          ),
        ],
      ),
      child: Column(
        children: [
          Row(
            children: [
              // 头像
              Container(
                width: 50.w,
                height: 50.w,
                decoration: BoxDecoration(
                  color: isActive ? Colors.purple[100] : Colors.grey[200],
                  shape: BoxShape.circle,
                ),
                child: member['avatar'] != null && member['avatar'].isNotEmpty
                    ? ClipOval(
                        child: Image.network(
                          member['avatar'],
                          width: 50.w,
                          height: 50.w,
                          fit: BoxFit.cover,
                          errorBuilder: (context, error, stackTrace) {
                            return _buildDefaultAvatar();
                          },
                        ),
                      )
                    : _buildDefaultAvatar(),
              ),      
            ],
          ),

成员条目设计

  • 待审核成员用橙色边框突出显示。
  • 头像使用圆形设计,支持网络图片加载。
  • 显示成员姓名、关系、电话和权限信息。
  • 状态标签用不同颜色区分:活跃、待审核、停用。
          SizedBox(height: 12.h),
          
          // 权限详情
          Container(
            width: double.infinity,
            padding: EdgeInsets.all(12.w),
            decoration: BoxDecoration(
              color: Colors.grey[50],
              borderRadius: BorderRadius.circular(8.r),
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '访问权限',
                  style: TextStyle(
                    fontSize: 12.sp,
                    fontWeight: FontWeight.w500,
                    color: Colors.grey[700],
                  ),
                ),
                SizedBox(height: 8.h),
                Wrap(
                  spacing: 8.w,
                  runSpacing: 4.h,
                  children: _buildPermissionChips(member['permissions']),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

权限详情展示

  • 灰色背景区域显示权限详情。
  • 使用 Wrap 布局展示权限标签。
  • 权限标签使用不同颜色区分类型。
  • 信息层次清晰,便于快速了解权限。
  Widget _buildDefaultAvatar() {
    return Icon(
      Icons.person,
      size: 25.sp,
      color: Colors.grey[400],
    );
  }

  List<Widget> _buildPermissionChips(List<String> permissions) {
    return permissions.map((permission) {
      return Container(
        padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
        decoration: BoxDecoration(
          color: _getPermissionColor(permission),
          borderRadius: BorderRadius.circular(12.r),
        ),
        child: Text(
          _getPermissionLabel(permission),
          style: TextStyle(
            fontSize: 10.sp,
            color: Colors.white,
          ),
        ),
      );
    }).toList();
  }

权限标签组件

  • _buildDefaultAvatar 提供默认头像。
  • _buildPermissionChips 生成权限标签列表。
  • 每个权限标签使用不同颜色区分。
  • 标签尺寸小巧,信息密度适中。
  Future<void> _loadFamilyMembers() async {
    setState(() {
      _isLoading = true;
    });

    // 模拟加载家庭成员数据
    await Future.delayed(const Duration(seconds: 1));
    
    final mockMembers = [
      {
        'id': '1',
        'name': '李四',
        'relation': '配偶',
        'phone': '13900139000',
        'avatar': '',
        'status': 'active',
        'permissions': ['main_gate', 'parking', 'gym'],
        'joinDate': '2023-06-15',
      },
      {
        'id': '2',
        'name': '张小明',
        'relation': '子女',
        'phone': '13700137000',
        'avatar': '',
        'status': 'active',
        'permissions': ['main_gate', 'gym'],
        'joinDate': '2023-08-20',
      },
      {
        'id': '3',
        'name': '王阿姨',
        'relation': '保姆',
        'phone': '13600136000',
        'avatar': '',
        'status': 'pending',
        'permissions': ['main_gate'],
        'joinDate': '2024-01-10',
      },
    ];
    
    setState(() {
      _familyMembers = mockMembers;
      _isLoading = false;
    });
  }

数据加载逻辑

  • 模拟异步加载家庭成员数据。
  • 包含完整的成员信息:姓名、关系、电话、权限等。
  • 不同状态的成员:活跃、待审核。
  • 加载完成后更新UI状态。
  Future<void> _refreshMembers() async {
    await _loadFamilyMembers();
  }

  int _getActiveMembersCount() {
    return _familyMembers.where((member) => member['status'] == 'active').length;
  }

  int _getPendingMembersCount() {
    return _familyMembers.where((member) => member['status'] == 'pending').length;
  }

  Color _getStatusColor(String status) {
    switch (status) {
      case 'active':
        return Colors.green;
      case 'pending':
        return Colors.orange;
      case 'inactive':
        return Colors.grey;
      default:
        return Colors.grey;
    }
  }

  String _getStatusText(String status) {
    switch (status) {
      case 'active':
        return '正常';
      case 'pending':
        return '待审核';
      case 'inactive':
        return '停用';
      default:
        return '未知';
    }
  }

状态处理方法

  • _getActiveMembersCount_getPendingMembersCount 计算统计数量。
  • _getStatusColor_getStatusText 获取状态的颜色和文本。
  • 使用 switch 语句确保状态处理的完整性。
  String _getPermissionText(List<String> permissions) {
    return permissions.map((p) => _getPermissionLabel(p)).join('、');
  }

  String _getPermissionLabel(String permission) {
    switch (permission) {
      case 'main_gate':
        return '主门';
      case 'parking':
        return '停车场';
      case 'gym':
        return '健身房';
      case 'pool':
        return '游泳池';
      default:
        return '未知';
    }
  }

  Color _getPermissionColor(String permission) {
    switch (permission) {
      case 'main_gate':
        return Colors.blue;
      case 'parking':
        return Colors.green;
      case 'gym':
        return Colors.purple;
      case 'pool':
        return Colors.cyan;
      default:
        return Colors.grey;
    }
  }

权限处理方法

  • _getPermissionText 将权限列表转换为可读文本。
  • _getPermissionLabel 获取权限的中文标签。
  • _getPermissionColor 为不同权限分配不同颜色。
  • 支持多种权限类型:主门、停车场、健身房、游泳池。
  void _addFamilyMember() {
    Get.to(() => const AddFamilyMemberPage())?.then((result) {
      if (result != null) {
        _loadFamilyMembers();
      }
    });
  }

  void _handleMemberAction(String action, Map<String, dynamic> member) async {
    switch (action) {
      case 'edit':
        _editMember(member);
        break;
      case 'permissions':
        _managePermissions(member);
        break;
      case 'approve':
        await _approveMember(member);
        break;
      case 'reject':
        await _rejectMember(member);
        break;
      case 'delete':
        await _deleteMember(member);
        break;
    }
  }

操作处理逻辑

  • _addFamilyMember 跳转到添加成员页面。
  • _handleMemberAction 根据操作类型调用相应处理方法。
  • 支持编辑、权限管理、审核、拒绝、删除等操作。
  • 添加成员成功后刷新列表。
  void _editMember(Map<String, dynamic> member) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('编辑功能开发中...')),
    );
  }

  void _managePermissions(Map<String, dynamic> member) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('权限管理功能开发中...')),
    );
  }

  Future<void> _approveMember(Map<String, dynamic> member) async {
    final index = _familyMembers.indexWhere((m) => m['id'] == member['id']);
    if (index != -1) {
      setState(() {
        _familyMembers[index]['status'] = 'active';
      });
      
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('成员审核通过'),
          backgroundColor: Colors.green,
        ),
      );
    }
  }

  Future<void> _rejectMember(Map<String, dynamic> member) async {
    final index = _familyMembers.indexWhere((m) => m['id'] == member['id']);
    if (index != -1) {
      setState(() {
        _familyMembers.removeAt(index);
      });
      
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('已拒绝成员申请'),
          backgroundColor: Colors.orange,
        ),
      );
    }
  }

具体操作实现

  • _approveMember 审核通过成员,更新状态为活跃。
  • _rejectMember 拒绝成员申请,从列表中移除。
  • 编辑和权限管理功能预留接口。
  • 所有操作都有相应的用户反馈。
  Future<void> _deleteMember(Map<String, dynamic> member) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('确认删除'),
        content: Text('确定要删除成员"${member['name']}"吗?\n删除后无法恢复。'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, false),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () => Navigator.pop(context, true),
            child: const Text('删除'),
          ),
        ],
      ),
    );
    
    if (confirmed == true) {
      final index = _familyMembers.indexWhere((m) => m['id'] == member['id']);
      if (index != -1) {
        setState(() {
          _familyMembers.removeAt(index);
        });
        
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('成员已删除'),
            backgroundColor: Colors.red,
          ),
        );
      }
    }
  }
}

删除操作实现

  • 删除操作需要用户二次确认,防止误删。
  • 确认后从列表中移除对应成员。
  • 删除成功后显示红色提示信息。
  • 操作完成后自动刷新统计信息。

用户体验设计

家庭成员管理页面的用户体验重点:

  1. 状态可视化:用颜色和标签区分成员状态
  2. 权限清晰:权限信息展示直观易懂
  3. 操作便捷:常用操作集中在右键菜单
  4. 反馈及时:每个操作都有明确的反馈

这些设计让家庭成员管理变得简单直观。

权限管理策略

权限管理的安全考虑:

  1. 分级权限:不同成员有不同的访问权限
  2. 权限可视化:权限标签清晰展示
  3. 权限审核:新成员需要审核才能获得权限
  4. 权限追溯:权限变更记录日志

这些措施确保权限管理的安全性。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐