| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- import 'package:flutter/material.dart';
- import 'package:go_router/go_router.dart';
- import 'package:provider/provider.dart';
- import '../../auth/models/user_model.dart';
- import '../../auth/services/auth_provider.dart';
- import '../../../config/app_routes.dart';
-
- /// 个人中心页面(对应 Issue #79:个人中心)
- ///
- /// 展示当前登录用户信息 + 功能菜单(个人信息/消息/设置/帮助/关于)+ 退出登录。
- class ProfilePage extends StatelessWidget {
- const ProfilePage({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(title: const Text('个人中心')),
- body: Consumer<AuthProvider>(
- builder: (context, auth, _) {
- final user = auth.currentUser;
- return ListView(
- children: [
- _UserHeader(user: user),
- const SizedBox(height: 8),
- _MenuGroup(items: const [
- _MenuItem(icon: Icons.person_outline, title: '个人信息'),
- _MenuItem(icon: Icons.notifications_outlined, title: '我的消息'),
- _MenuItem(icon: Icons.settings_outlined, title: '设置'),
- ]),
- const SizedBox(height: 8),
- _MenuGroup(items: const [
- _MenuItem(icon: Icons.help_outline, title: '帮助与反馈'),
- _MenuItem(icon: Icons.info_outline, title: '关于'),
- ]),
- const SizedBox(height: 16),
- _LogoutButton(onLogout: () => _handleLogout(context, auth)),
- const SizedBox(height: 24),
- ],
- );
- },
- ),
- );
- }
-
- Future<void> _handleLogout(BuildContext context, AuthProvider auth) async {
- final confirmed = await showDialog<bool>(
- context: context,
- builder: (ctx) => AlertDialog(
- title: const Text('退出登录'),
- content: const Text('确定要退出当前账号吗?'),
- actions: [
- TextButton(onPressed: () => Navigator.of(ctx).pop(false), child: const Text('取消')),
- TextButton(
- onPressed: () => Navigator.of(ctx).pop(true),
- child: const Text('退出', style: TextStyle(color: Colors.red)),
- ),
- ],
- ),
- );
- if (confirmed == true) {
- await auth.logout();
- // 登出后跳转登录页(go_router 守卫也会拦截,这里显式跳转)
- if (context.mounted) {
- GoRouter.of(context).go(AppRoutes.login);
- }
- }
- }
- }
-
- /// 用户信息头部(头像 + 姓名 + 角色/部门)
- class _UserHeader extends StatelessWidget {
- final UserModel? user;
- const _UserHeader({this.user});
-
- @override
- Widget build(BuildContext context) {
- final name = user?.name ?? '未登录';
- final role = user?.role ?? '';
- final department = user?.department;
- final phone = user?.phone;
-
- return Container(
- width: double.infinity,
- padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
- color: Theme.of(context).colorScheme.primary,
- child: Column(
- children: [
- CircleAvatar(
- radius: 40,
- backgroundColor: Colors.white24,
- child: _buildAvatar(user, name),
- ),
- const SizedBox(height: 12),
- Text(name, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white)),
- if (role.isNotEmpty) ...[
- const SizedBox(height: 4),
- Text(_roleLabel(role), style: const TextStyle(color: Colors.white70)),
- ],
- if (department != null || phone != null) ...[
- const SizedBox(height: 4),
- Text(
- [department, phone].whereType<String>().join(' · '),
- style: const TextStyle(color: Colors.white60, fontSize: 13),
- ),
- ],
- ],
- ),
- );
- }
-
- String _roleLabel(String role) {
- const map = {'admin': '管理员', 'inspector': '巡检员', 'operator': '操作员'};
- return map[role] ?? role;
- }
-
- /// 头像:有 avatar 用网络图,否则取姓名首字
- Widget _buildAvatar(UserModel? user, String name) {
- final avatar = user?.avatar;
- if (avatar != null && avatar.isNotEmpty) {
- return ClipOval(child: Image.network(avatar, width: 80, height: 80, fit: BoxFit.cover));
- }
- return Text(
- name.isNotEmpty ? name.substring(0, 1) : '?',
- style: const TextStyle(fontSize: 32, color: Colors.white),
- );
- }
- }
-
- /// 菜单组(带卡片容器)
- class _MenuGroup extends StatelessWidget {
- final List<_MenuItem> items;
- const _MenuGroup({required this.items});
-
- @override
- Widget build(BuildContext context) {
- return Card(
- margin: const EdgeInsets.symmetric(horizontal: 12),
- child: Column(
- children: [
- for (int i = 0; i < items.length; i++) ...[
- items[i],
- if (i < items.length - 1) const Divider(height: 1, indent: 56),
- ],
- ],
- ),
- );
- }
- }
-
- /// 单个菜单项(占位 onTap,待后续接入具体页面)
- class _MenuItem extends StatelessWidget {
- final IconData icon;
- final String title;
- final VoidCallback? onTap;
-
- const _MenuItem({required this.icon, required this.title, this.onTap});
-
- @override
- Widget build(BuildContext context) {
- return ListTile(
- leading: Icon(icon, color: Theme.of(context).colorScheme.primary),
- title: Text(title),
- trailing: const Icon(Icons.chevron_right, color: Colors.grey),
- onTap: onTap ?? () => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('$title(待实现)'))),
- );
- }
- }
-
- /// 退出登录按钮
- class _LogoutButton extends StatelessWidget {
- final VoidCallback onLogout;
- const _LogoutButton({required this.onLogout});
-
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12),
- child: OutlinedButton.icon(
- onPressed: onLogout,
- icon: const Icon(Icons.logout, color: Colors.red),
- label: const Text('退出登录', style: TextStyle(color: Colors.red)),
- style: OutlinedButton.styleFrom(
- minimumSize: const Size(double.infinity, 48),
- side: const BorderSide(color: Colors.red),
- shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
- ),
- ),
- );
- }
- }
|