Selaa lähdekoodia

Merge branch 'afan_local_1215' of afan/flutter_app_android into develop

刘清 1 kuukausi sitten
vanhempi
commit
1d6d063acd

+ 1
- 6
lib/presentation/navigation/app_router.dart Näytä tiedosto

@@ -32,12 +32,7 @@ class AppRouter {
32 32
         return MaterialPageRoute(builder: (_) => const ServicesScreen());
33 33
       
34 34
       case RouteConstants.profile:
35
-        return MaterialPageRoute(
36
-          builder: (_) => ProtectedRoute(
37
-            routeName: RouteConstants.profile,
38
-            child: const ProfileScreen(),
39
-          ),
40
-        );
35
+        return MaterialPageRoute(builder: (_) => const ProfileScreen());
41 36
       
42 37
       case RouteConstants.profileDetail:
43 38
         return MaterialPageRoute(

+ 1
- 10
lib/presentation/navigation/bottom_nav_bar.dart Näytä tiedosto

@@ -1,7 +1,5 @@
1 1
 import 'package:flutter/material.dart';
2
-import 'package:provider/provider.dart';
3 2
 import '../../core/constants/route_constants.dart';
4
-import '../../presentation/providers/auth_provider.dart';
5 3
 
6 4
 class BottomNavBar extends StatefulWidget {
7 5
   final int initialIndex;
@@ -25,13 +23,6 @@ class _BottomNavBarState extends State<BottomNavBar> {
25 23
   }
26 24
   
27 25
   void _onItemTapped(int index) {
28
-    final authProvider = Provider.of<AuthProvider>(context, listen: false);
29
-    
30
-    // 如果点击"我的"但未登录,跳转到登录页
31
-    if (index == 3 && !authProvider.isAuthenticated) {
32
-      Navigator.of(context).pushNamed(RouteConstants.login);
33
-      return;
34
-    }
35 26
     
36 27
     setState(() {
37 28
       _selectedIndex = index;
@@ -73,7 +64,7 @@ class _BottomNavBarState extends State<BottomNavBar> {
73 64
         BottomNavigationBarItem(
74 65
           icon: Icon(Icons.newspaper_outlined),
75 66
           activeIcon: Icon(Icons.newspaper),
76
-          label: '资讯',
67
+          label: '推荐',
77 68
         ),
78 69
         BottomNavigationBarItem(
79 70
           icon: Icon(Icons.work_outline),

+ 5
- 0
lib/presentation/providers/auth_provider.dart Näytä tiedosto

@@ -112,4 +112,9 @@ class AuthProvider with ChangeNotifier {
112 112
     _error = null;
113 113
     notifyListeners();
114 114
   }
115
+
116
+  void updateUser(User? user) {
117
+    _user = user;
118
+    notifyListeners();
119
+  }
115 120
 }

+ 5
- 0
lib/presentation/providers/user_provider.dart Näytä tiedosto

@@ -59,4 +59,9 @@ class UserProvider with ChangeNotifier {
59 59
     _error = null;
60 60
     notifyListeners();
61 61
   }
62
+
63
+  void updateUser(User? user) {
64
+    _user = user;
65
+    notifyListeners();
66
+  }
62 67
 }

+ 5
- 0
lib/presentation/screens/auth/login_screen.dart Näytä tiedosto

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
2 2
 import 'package:provider/provider.dart';
3 3
 import '../../providers/auth_provider.dart';
4 4
 import '../../../core/constants/route_constants.dart';
5
+import '../../providers/user_provider.dart';
5 6
 import '../../widgets/common/app_button.dart';
6 7
 import '../../widgets/common/app_text_field.dart';
7 8
 import '../../widgets/common/loading_indicator.dart';
@@ -120,6 +121,10 @@ class _LoginScreenState extends State<LoginScreen> {
120 121
                           _passwordController.text,
121 122
                         );
122 123
                         if (authProvider.isAuthenticated) {
124
+                          // ✅ 同时更新 userProvider
125
+                          final userProvider = Provider.of<UserProvider>(context, listen: false);
126
+                          userProvider.updateUser(authProvider.user);
127
+
123 128
                           // widget.onSuccess?.call();
124 129
                           Navigator.of(context).pushReplacementNamed(RouteConstants.home);
125 130
                           // Navigator.of(context).pushNamedAndRemoveUntil(RouteConstants.home);

+ 7
- 24
lib/presentation/screens/home/home_screen.dart Näytä tiedosto

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
2 2
 import 'package:provider/provider.dart';
3 3
 import '../../navigation/bottom_nav_bar.dart';
4 4
 import '../../providers/auth_provider.dart';
5
-import '../../widgets/common/app_button.dart';
6 5
 
7 6
 class HomeScreen extends StatelessWidget {
8 7
   const HomeScreen({super.key});
@@ -18,7 +17,10 @@ class HomeScreen extends StatelessWidget {
18 17
           if (authProvider.isAuthenticated)
19 18
             IconButton(
20 19
               icon: const Icon(Icons.notifications_none),
21
-              onPressed: () {},
20
+              onPressed: () {
21
+                // 进入消息中心界面
22
+                // Navigator.of(context).pushNamed('/login');
23
+              },
22 24
             ),
23 25
         ],
24 26
       ),
@@ -42,16 +44,6 @@ class HomeScreen extends StatelessWidget {
42 44
                     children: [
43 45
                       Row(
44 46
                         children: [
45
-                          CircleAvatar(
46
-                            radius: 30,
47
-                            backgroundColor: Colors.blue[100],
48
-                            child: Icon(
49
-                              Icons.person,
50
-                              size: 30,
51
-                              color: Colors.blue,
52
-                            ),
53
-                          ),
54
-                          const SizedBox(width: 16),
55 47
                           Expanded(
56 48
                             child: Column(
57 49
                               crossAxisAlignment: CrossAxisAlignment.start,
@@ -68,7 +60,7 @@ class HomeScreen extends StatelessWidget {
68 60
                                 const SizedBox(height: 4),
69 61
                                 Text(
70 62
                                   authProvider.isAuthenticated
71
-                                      ? '欢迎回来!'
63
+                                      ? '这里会展示一些有趣的东西!'
72 64
                                       : '请登录以使用完整功能',
73 65
                                   style: TextStyle(
74 66
                                     fontSize: 14,
@@ -80,16 +72,7 @@ class HomeScreen extends StatelessWidget {
80 72
                           ),
81 73
                         ],
82 74
                       ),
83
-                      const SizedBox(height: 20),
84
-                      if (!authProvider.isAuthenticated)
85
-                        AppButton(
86
-                          text: '立即登录',
87
-                          onPressed: () {
88
-                            Navigator.of(context).pushNamed('/login');
89
-                          },
90
-                          backgroundColor: Colors.blue,
91
-                          height: 45,
92
-                        ),
75
+                      const SizedBox(height: 100),
93 76
                     ],
94 77
                   ),
95 78
                 ),
@@ -113,7 +96,7 @@ class HomeScreen extends StatelessWidget {
113 96
                 children: [
114 97
                   _buildFeatureCard(
115 98
                     icon: Icons.newspaper,
116
-                    title: '资讯',
99
+                    title: '推荐',
117 100
                     color: Colors.green,
118 101
                     onTap: () {
119 102
                       Navigator.of(context).pushNamed('/news');

+ 80
- 52
lib/presentation/screens/news/news_screen.dart Näytä tiedosto

@@ -1,5 +1,6 @@
1 1
 import 'package:flutter/material.dart';
2 2
 import '../../navigation/bottom_nav_bar.dart';
3
+import '../../widgets/common/app_search_bar.dart';
3 4
 
4 5
 class NewsScreen extends StatelessWidget {
5 6
   const NewsScreen({super.key});
@@ -8,20 +9,41 @@ class NewsScreen extends StatelessWidget {
8 9
   Widget build(BuildContext context) {
9 10
     return Scaffold(
10 11
       appBar: AppBar(
11
-        title: const Text('资讯'),
12
-        actions: [
13
-          IconButton(
14
-            icon: const Icon(Icons.search),
15
-            onPressed: () {},
16
-          ),
17
-        ],
12
+        title: const Text('推荐'),
18 13
       ),
19
-      body: ListView.builder(
20
-        padding: const EdgeInsets.all(16),
21
-        itemCount: 10,
22
-        itemBuilder: (context, index) {
23
-          return _buildNewsCard(index);
24
-        },
14
+      body: SingleChildScrollView(
15
+        padding: const EdgeInsets.all(20),
16
+        child: Column(
17
+          crossAxisAlignment: CrossAxisAlignment.start,
18
+          children: [
19
+            // 使用 StatefulWidget 搜索框
20
+            SearchBarCustom(
21
+              hintText: '搜索...',
22
+              onSearch: (query) {
23
+                // 处理搜索逻辑
24
+                // print('搜索: $query');
25
+              },
26
+              onChanged: (query) {
27
+                // 实时搜索
28
+                // print('输入变化: $query');
29
+              },
30
+              onClear: () {
31
+                // print('清除搜索');
32
+              },
33
+            ),
34
+            const SizedBox(height: 24),
35
+
36
+            // 推荐列表
37
+            ListView.builder(
38
+              shrinkWrap: true,
39
+              physics: const NeverScrollableScrollPhysics(),
40
+              itemCount: 10,
41
+              itemBuilder: (context, index) {
42
+                return _buildNewsCard(index);
43
+              },
44
+            ),
45
+          ],
46
+        ),
25 47
       ),
26 48
       bottomNavigationBar: const BottomNavBar(initialIndex: 1),
27 49
     );
@@ -29,42 +51,42 @@ class NewsScreen extends StatelessWidget {
29 51
   
30 52
   Widget _buildNewsCard(int index) {
31 53
     final titles = [
32
-      'Flutter 3.0 新特性详解',
33
-      'Dart 语言最新更新',
34
-      '移动开发趋势分析',
35
-      '前端框架对比',
36
-      '用户体验设计原则',
37
-      '后端架构最佳实践',
38
-      '数据库性能优化',
39
-      '云原生技术解析',
40
-      '人工智能在移动端的应用',
41
-      '跨平台开发方案比较',
54
+      '体彩 大乐透 20260001期',
55
+      '福彩 双色球 20260002期',
56
+      '福彩 双色球 20260003期',
57
+      '体彩 大乐透 20260004期',
58
+      '福彩 双色球 20260005期',
59
+      '福彩 双色球 20260007期',
60
+      '体彩 大乐透 20260006期',
61
+      '福彩 双色球 20260008期',
62
+      '福彩 双色球 20260009期',
63
+      '福彩 快乐八 20260010期',
42 64
     ];
43 65
     
44 66
     final subtitles = [
45
-      '深入了解Flutter最新版本的重要更新和改进',
46
-      'Dart语言的最新特性和优化方向',
47
-      '2024年移动开发的重要趋势和技术方向',
48
-      '主流前端框架的优缺点对比分析',
49
-      '提升应用用户体验的关键设计原则',
50
-      '构建高性能后端服务的最佳实践',
51
-      '数据库查询优化和性能调优技巧',
52
-      '云原生技术在微服务中的应用',
53
-      'AI技术在移动应用中的创新应用',
54
-      '各种跨平台开发方案的对比和选择',
67
+      '预测号码:4 5 8 6 25 8 9 6',
68
+      '预测号码:4 5 8 6 25 8 9 6',
69
+      '预测号码:4 5 8 6 25 8 9 6',
70
+      '预测号码:4 5 8 6 25 8 9 6',
71
+      '预测号码:4 5 8 6 25 8 9 6',
72
+      '预测号码:4 5 8 6 25 8 9 6',
73
+      '预测号码:4 5 8 6 25 8 9 6',
74
+      '预测号码:4 5 8 6 25 8 9 6',
75
+      '预测号码:4 5 8 6 25 8 9 6',
76
+      '预测号码:4 5 8 6 25 8 9 6',
55 77
     ];
56 78
     
57 79
     final times = [
58
-      '2小时前',
59
-      '5小时前',
60
-      '昨天',
61
-      '2天前',
62
-      '3天前',
63
-      '1周前',
64
-      '1周前',
65
-      '2周前',
66
-      '2周前',
67
-      '1个月前',
80
+      '2小时前 :aaa',
81
+      '5小时前 :aaa',
82
+      '昨天 :aaa',
83
+      '2天前 :aaa',
84
+      '3天前 :aaa',
85
+      '1周前 :aaa',
86
+      '1周前 :aaa',
87
+      '2周前 :aaa',
88
+      '2周前 :aaa',
89
+      '1个月前 :aaa',
68 90
     ];
69 91
     
70 92
     return Card(
@@ -73,7 +95,9 @@ class NewsScreen extends StatelessWidget {
73 95
         borderRadius: BorderRadius.circular(12),
74 96
       ),
75 97
       child: InkWell(
76
-        onTap: () {},
98
+        onTap: () {
99
+          print(index);
100
+        },
77 101
         borderRadius: BorderRadius.circular(12),
78 102
         child: Padding(
79 103
           padding: const EdgeInsets.all(16),
@@ -91,7 +115,7 @@ class NewsScreen extends StatelessWidget {
91 115
                     ),
92 116
                     child: Center(
93 117
                       child: Text(
94
-                        '新闻',
118
+                        '推号',
95 119
                         style: TextStyle(
96 120
                           color: Colors.white,
97 121
                           fontWeight: FontWeight.bold,
@@ -107,7 +131,7 @@ class NewsScreen extends StatelessWidget {
107 131
                         Text(
108 132
                           titles[index],
109 133
                           style: const TextStyle(
110
-                            fontSize: 16,
134
+                            fontSize: 18,
111 135
                             fontWeight: FontWeight.bold,
112 136
                           ),
113 137
                           maxLines: 2,
@@ -117,7 +141,7 @@ class NewsScreen extends StatelessWidget {
117 141
                         Text(
118 142
                           subtitles[index],
119 143
                           style: TextStyle(
120
-                            fontSize: 14,
144
+                            fontSize: 16,
121 145
                             color: Colors.grey[600],
122 146
                           ),
123 147
                           maxLines: 2,
@@ -128,19 +152,19 @@ class NewsScreen extends StatelessWidget {
128 152
                   ),
129 153
                 ],
130 154
               ),
131
-              const SizedBox(height: 12),
155
+              const SizedBox(height: 4),
132 156
               Row(
133 157
                 children: [
134 158
                   Icon(
135 159
                     Icons.schedule,
136
-                    size: 14,
160
+                    size: 16,
137 161
                     color: Colors.grey[500],
138 162
                   ),
139 163
                   const SizedBox(width: 4),
140 164
                   Text(
141 165
                     times[index],
142 166
                     style: TextStyle(
143
-                      fontSize: 12,
167
+                      fontSize: 14,
144 168
                       color: Colors.grey[500],
145 169
                     ),
146 170
                   ),
@@ -150,7 +174,9 @@ class NewsScreen extends StatelessWidget {
150 174
                       Icons.bookmark_border,
151 175
                       color: Colors.grey[500],
152 176
                     ),
153
-                    onPressed: () {},
177
+                    onPressed: () {
178
+                      // 添加书签
179
+                    },
154 180
                     iconSize: 20,
155 181
                   ),
156 182
                   IconButton(
@@ -158,7 +184,9 @@ class NewsScreen extends StatelessWidget {
158 184
                       Icons.share,
159 185
                       color: Colors.grey[500],
160 186
                     ),
161
-                    onPressed: () {},
187
+                    onPressed: () {
188
+                      // 分享
189
+                    },
162 190
                     iconSize: 20,
163 191
                   ),
164 192
                 ],

+ 9
- 2
lib/presentation/screens/profile/profile_detail_screen.dart Näytä tiedosto

@@ -1,6 +1,7 @@
1 1
 import 'package:flutter/material.dart';
2 2
 import 'package:provider/provider.dart';
3 3
 import '../../../data/models/user.dart';
4
+import '../../providers/auth_provider.dart';
4 5
 import '../../providers/user_provider.dart';
5 6
 import '../../widgets/common/app_button.dart';
6 7
 import '../../widgets/common/app_text_field.dart';
@@ -24,7 +25,7 @@ class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
24 25
     super.initState();
25 26
     final userProvider = Provider.of<UserProvider>(context, listen: false);
26 27
     _currentUser = userProvider.user ?? User(id: -1, email: '', username: '', createdAt: DateTime.now());
27
-    _nameController = TextEditingController(text: _currentUser.username);
28
+    _nameController = TextEditingController(text: _currentUser.fullName);
28 29
     _emailController = TextEditingController(text: _currentUser.email);
29 30
     _phoneController = TextEditingController(text: _currentUser.phone ?? '');
30 31
   }
@@ -183,13 +184,19 @@ class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
183 184
                     
184 185
                     await userProvider.updateUserProfile(updatedUser);
185 186
                     
186
-                    if (userProvider.error == null) {
187
+                    if (userProvider.error == null && mounted) {
188
+                      // ✅ 同时更新 AuthProvider
189
+                      final authProvider = Provider.of<AuthProvider>(context, listen: false);
190
+                      authProvider.updateUser(userProvider.user);  // 使用接口返回的完整用户数据
191
+
187 192
                       ScaffoldMessenger.of(context).showSnackBar(
188 193
                         const SnackBar(
189 194
                           content: Text('个人信息已更新'),
190 195
                           duration: Duration(seconds: 2),
191 196
                         ),
192 197
                       );
198
+
199
+                      // ✅ 直接返回 - 数据已同步更新
193 200
                       Navigator.of(context).pop();
194 201
                     }
195 202
                   }

+ 272
- 206
lib/presentation/screens/profile/profile_screen.dart Näytä tiedosto

@@ -2,10 +2,9 @@ import 'package:flutter/material.dart';
2 2
 import 'package:provider/provider.dart';
3 3
 import '../../../core/constants/route_constants.dart';
4 4
 import '../../providers/auth_provider.dart';
5
-import '../../providers/user_provider.dart';
6 5
 import '../../navigation/bottom_nav_bar.dart';
6
+import '../../widgets/common/app_button.dart';
7 7
 import 'profile_detail_screen.dart';
8
-import '../../widgets/custom/protected_widget.dart';
9 8
 
10 9
 class ProfileScreen extends StatelessWidget {
11 10
   const ProfileScreen({super.key});
@@ -23,19 +22,18 @@ class _ProfileContent extends StatefulWidget {
23 22
 }
24 23
 
25 24
 class _ProfileContentState extends State<_ProfileContent> {
26
-  @override
27
-  void initState() {
28
-    super.initState();
29
-    WidgetsBinding.instance.addPostFrameCallback((_) {
30
-      final userProvider = Provider.of<UserProvider>(context, listen: false);
31
-      userProvider.loadUserProfile();
32
-    });
33
-  }
25
+  // @override
26
+  // void initState() {
27
+  //   super.initState();
28
+  //   WidgetsBinding.instance.addPostFrameCallback((_) {
29
+  //     final userProvider = Provider.of<UserProvider>(context, listen: false);
30
+  //     userProvider.loadUserProfile();
31
+  //   });
32
+  // }
34 33
 
35 34
   @override
36 35
   Widget build(BuildContext context) {
37 36
     final authProvider = Provider.of<AuthProvider>(context);
38
-    // final userProvider = Provider.of<UserProvider>(context);
39 37
     
40 38
     return Scaffold(
41 39
       appBar: AppBar(
@@ -52,162 +50,229 @@ class _ProfileContentState extends State<_ProfileContent> {
52 50
       body: SingleChildScrollView(
53 51
         child: Column(
54 52
           children: [
55
-            // 用户信息卡片
56
-            Card(
57
-              margin: const EdgeInsets.all(16),
58
-              shape: RoundedRectangleBorder(
59
-                borderRadius: BorderRadius.circular(16),
60
-              ),
61
-              elevation: 2,
62
-              child: Padding(
63
-                padding: const EdgeInsets.all(20),
64
-                child: Column(
65
-                  children: [
66
-                    GestureDetector(
67
-                      onTap: () {
68
-                        // 点击头像
69
-                      },
70
-                      child: Stack(
53
+            if (!authProvider.isAuthenticated) ...[
54
+              // 欢迎区域
55
+              Card(
56
+                margin: const EdgeInsets.all(16),
57
+                shape: RoundedRectangleBorder(
58
+                  borderRadius: BorderRadius.circular(16),
59
+                ),
60
+                // color: Colors.blue[50],
61
+                elevation: 2,
62
+                child: Padding(
63
+                  padding: const EdgeInsets.all(20),
64
+                  child: Column(
65
+                    crossAxisAlignment: CrossAxisAlignment.start,
66
+                    children: [
67
+                      Row(
71 68
                         children: [
72 69
                           CircleAvatar(
73
-                            radius: 50,
70
+                            radius: 30,
74 71
                             backgroundColor: Colors.blue[100],
75
-                            backgroundImage: authProvider.user?.avatar != null
76
-                                ? NetworkImage(authProvider.user!.avatar!)
77
-                                : null,
78
-                            child: authProvider.user?.avatar == null
79
-                                ? const Icon(
80
-                                    Icons.person,
81
-                                    size: 60,
82
-                                    color: Colors.blue,
83
-                                  )
84
-                                : null,
72
+                            child: Icon(
73
+                              Icons.person,
74
+                              size: 30,
75
+                              color: Colors.blue,
76
+                            ),
85 77
                           ),
86
-                          Positioned(
87
-                            bottom: 0,
88
-                            right: 0,
89
-                            child: Container(
90
-                              padding: const EdgeInsets.all(6),
91
-                              decoration: BoxDecoration(
92
-                                color: Colors.blue,
93
-                                borderRadius: BorderRadius.circular(20),
94
-                                border: Border.all(
95
-                                  color: Colors.white,
96
-                                  width: 2,
78
+                          const SizedBox(width: 16),
79
+                          Expanded(
80
+                            child: Column(
81
+                              crossAxisAlignment: CrossAxisAlignment.start,
82
+                              children: [
83
+                                Text(
84
+                                  authProvider.isAuthenticated
85
+                                      ? '您好,${authProvider.user?.fullName}'
86
+                                      : '您好,游客',
87
+                                  style: const TextStyle(
88
+                                    fontSize: 18,
89
+                                    fontWeight: FontWeight.bold,
90
+                                  ),
97 91
                                 ),
98
-                              ),
99
-                              child: const Icon(
100
-                                Icons.edit,
101
-                                size: 16,
102
-                                color: Colors.white,
103
-                              ),
92
+                                const SizedBox(height: 4),
93
+                                Text(
94
+                                  authProvider.isAuthenticated
95
+                                      ? '欢迎回来!'
96
+                                      : '请登录以使用完整功能',
97
+                                  style: TextStyle(
98
+                                    fontSize: 14,
99
+                                    color: Colors.grey[600],
100
+                                  ),
101
+                                ),
102
+                              ],
104 103
                             ),
105 104
                           ),
106 105
                         ],
107 106
                       ),
108
-                    ),
109
-                    const SizedBox(height: 16),
110
-                    Text(
111
-                      authProvider.user?.fullName ?? '用户',
112
-                      style: const TextStyle(
113
-                        fontSize: 22,
114
-                        fontWeight: FontWeight.bold,
107
+                      const SizedBox(height: 20),
108
+                      if (!authProvider.isAuthenticated)
109
+                        AppButton(
110
+                          text: '立即登录',
111
+                          onPressed: () {
112
+                            Navigator.of(context).pushNamed('/login');
113
+                          },
114
+                          backgroundColor: Colors.blue,
115
+                          height: 45,
116
+                        ),
117
+                    ],
118
+                  ),
119
+                ),
120
+              ),
121
+            ] else ...[
122
+              // 用户信息卡片
123
+              Card(
124
+                margin: const EdgeInsets.all(16),
125
+                shape: RoundedRectangleBorder(
126
+                  borderRadius: BorderRadius.circular(16),
127
+                ),
128
+                // color: Colors.blue[50],
129
+                elevation: 2,
130
+                child: Padding(
131
+                  padding: const EdgeInsets.all(20),
132
+                  child: Column(
133
+                    children: [
134
+                      GestureDetector(
135
+                        onTap: () {
136
+                          // 点击头像
137
+                        },
138
+                        child: Stack(
139
+                          children: [
140
+                            CircleAvatar(
141
+                              radius: 50,
142
+                              backgroundColor: Colors.blue[100],
143
+                              backgroundImage: authProvider.user?.avatar != null
144
+                                  ? NetworkImage(authProvider.user!.avatar!)
145
+                                  : null,
146
+                              child: authProvider.user?.avatar == null
147
+                                  ? const Icon(
148
+                                      Icons.person,
149
+                                      size: 60,
150
+                                      color: Colors.blue,
151
+                                    )
152
+                                  : null,
153
+                            ),
154
+                            Positioned(
155
+                              bottom: 0,
156
+                              right: 0,
157
+                              child: Container(
158
+                                padding: const EdgeInsets.all(6),
159
+                                decoration: BoxDecoration(
160
+                                  color: Colors.blue,
161
+                                  borderRadius: BorderRadius.circular(20),
162
+                                  border: Border.all(
163
+                                    color: Colors.white,
164
+                                    width: 2,
165
+                                  ),
166
+                                ),
167
+                              ),
168
+                            ),
169
+                          ],
170
+                        ),
115 171
                       ),
116
-                    ),
117
-                    const SizedBox(height: 8),
118
-                    Text(
119
-                      authProvider.user?.email ?? '',
120
-                      style: TextStyle(
121
-                        fontSize: 14,
122
-                        color: Colors.grey[600],
172
+                      const SizedBox(height: 16),
173
+                      Text(
174
+                        authProvider.user?.fullName ?? '用户',
175
+                        style: const TextStyle(
176
+                          fontSize: 22,
177
+                          fontWeight: FontWeight.bold,
178
+                        ),
123 179
                       ),
124
-                    ),
125
-                    if (authProvider.user?.phone != null)
126
-                      Padding(
127
-                        padding: const EdgeInsets.only(top: 4),
128
-                        child: Text(
129
-                          authProvider.user!.phone!,
130
-                          style: TextStyle(
131
-                            fontSize: 14,
132
-                            color: Colors.grey[600],
180
+                      const SizedBox(height: 8),
181
+                      Text(
182
+                        authProvider.user?.email ?? '',
183
+                        style: TextStyle(
184
+                          fontSize: 14,
185
+                          color: Colors.grey[600],
186
+                        ),
187
+                      ),
188
+                      if (authProvider.user?.phone != null)
189
+                        Padding(
190
+                          padding: const EdgeInsets.only(top: 4),
191
+                          child: Text(
192
+                            authProvider.user!.phone!,
193
+                            style: TextStyle(
194
+                              fontSize: 14,
195
+                              color: Colors.grey[600],
196
+                            ),
133 197
                           ),
134 198
                         ),
199
+                      const SizedBox(height: 16),
200
+                      Row(
201
+                        mainAxisAlignment: MainAxisAlignment.center,
202
+                        children: [
203
+                          _buildStatItem('关注', '0'),
204
+                          _buildVerticalDivider(),
205
+                          _buildStatItem('粉丝', '0'),
206
+                          _buildVerticalDivider(),
207
+                          _buildStatItem('积分', '0'),
208
+                        ],
135 209
                       ),
136
-                    const SizedBox(height: 16),
137
-                    Row(
138
-                      mainAxisAlignment: MainAxisAlignment.center,
139
-                      children: [
140
-                        _buildStatItem('关注', '128'),
141
-                        _buildVerticalDivider(),
142
-                        _buildStatItem('粉丝', '256'),
143
-                        _buildVerticalDivider(),
144
-                        _buildStatItem('积分', '1024'),
145
-                      ],
146
-                    ),
147
-                  ],
210
+                    ],
211
+                  ),
148 212
                 ),
149 213
               ),
150
-            ),
151
-            
214
+            ],
152 215
             // 菜单项
153 216
             Padding(
154 217
               padding: const EdgeInsets.symmetric(horizontal: 16),
155 218
               child: Column(
156 219
                 children: [
157
-                  _buildMenuCard(
158
-                    title: '账户设置',
159
-                    items: [
160
-                      _buildMenuItem(
161
-                        icon: Icons.person_outline,
162
-                        title: '个人信息',
163
-                        subtitle: '查看和编辑个人信息',
164
-                        onTap: () {
165
-                          Navigator.of(context).push(
166
-                            MaterialPageRoute(
167
-                              builder: (_) => const ProfileDetailScreen(),
168
-                            ),
169
-                          );
170
-                        },
171
-                      ),
172
-                      _buildMenuItem(
173
-                        icon: Icons.lock_outline,
174
-                        title: '账号安全',
175
-                        subtitle: '修改密码和安全设置',
176
-                        onTap: () {},
177
-                      ),
178
-                      _buildMenuItem(
179
-                        icon: Icons.notifications_none,
180
-                        title: '消息通知',
181
-                        subtitle: '管理通知偏好设置',
182
-                        onTap: () {},
183
-                      ),
184
-                    ],
185
-                  ),
186
-                  const SizedBox(height: 16),
187
-                  _buildMenuCard(
188
-                    title: '我的内容',
189
-                    items: [
190
-                      _buildMenuItem(
191
-                        icon: Icons.bookmark_border,
192
-                        title: '我的收藏',
193
-                        subtitle: '查看收藏的内容',
194
-                        onTap: () {},
195
-                      ),
196
-                      _buildMenuItem(
197
-                        icon: Icons.history,
198
-                        title: '浏览历史',
199
-                        subtitle: '查看最近浏览记录',
200
-                        onTap: () {},
201
-                      ),
202
-                      _buildMenuItem(
203
-                        icon: Icons.download,
204
-                        title: '我的下载',
205
-                        subtitle: '管理下载的文件',
206
-                        onTap: () {},
207
-                      ),
208
-                    ],
209
-                  ),
210
-                  const SizedBox(height: 16),
220
+                  if (authProvider.isAuthenticated) ... [
221
+                    _buildMenuCard(
222
+                      title: '账户设置',
223
+                      items: [
224
+                        _buildMenuItem(
225
+                          icon: Icons.person_outline,
226
+                          title: '个人信息',
227
+                          subtitle: '查看和编辑个人信息',
228
+                          onTap: () {
229
+                            Navigator.of(context).push(
230
+                              MaterialPageRoute(
231
+                                builder: (_) => const ProfileDetailScreen(),
232
+                              ),
233
+                            );
234
+                          },
235
+                        ),
236
+                        _buildMenuItem(
237
+                          icon: Icons.lock_outline,
238
+                          title: '账号安全',
239
+                          subtitle: '修改密码和安全设置',
240
+                          onTap: () {},
241
+                        ),
242
+                        _buildMenuItem(
243
+                          icon: Icons.notifications_none,
244
+                          title: '消息通知',
245
+                          subtitle: '管理通知偏好设置',
246
+                          onTap: () {},
247
+                        ),
248
+                      ],
249
+                    ),
250
+                    const SizedBox(height: 16),
251
+                    _buildMenuCard(
252
+                      title: '我的内容',
253
+                      items: [
254
+                        _buildMenuItem(
255
+                          icon: Icons.bookmark_border,
256
+                          title: '我的收藏',
257
+                          subtitle: '查看收藏的内容',
258
+                          onTap: () {},
259
+                        ),
260
+                        _buildMenuItem(
261
+                          icon: Icons.history,
262
+                          title: '浏览历史',
263
+                          subtitle: '查看最近浏览记录',
264
+                          onTap: () {},
265
+                        ),
266
+                        _buildMenuItem(
267
+                          icon: Icons.download,
268
+                          title: '我的下载',
269
+                          subtitle: '管理下载的文件',
270
+                          onTap: () {},
271
+                        ),
272
+                      ],
273
+                    ),
274
+                    const SizedBox(height: 16),
275
+                  ],
211 276
                   _buildMenuCard(
212 277
                     title: '其他',
213 278
                     items: [
@@ -223,72 +288,73 @@ class _ProfileContentState extends State<_ProfileContent> {
223 288
                         subtitle: '了解应用信息',
224 289
                         onTap: () {},
225 290
                       ),
226
-                      _buildMenuItem(
227
-                        icon: Icons.logout,
228
-                        title: '退出登录',
229
-                        subtitle: '安全退出当前账号',
230
-                        onTap: () async {
231
-                          // 防止重复点击
232
-                          if (authProvider.isLoading) return;
291
+                      if (authProvider.isAuthenticated) ... [
292
+                        _buildMenuItem(
293
+                          icon: Icons.logout,
294
+                          title: '退出登录',
295
+                          subtitle: '安全退出当前账号',
296
+                          onTap: () async {
297
+                            // 防止重复点击
298
+                            if (authProvider.isLoading) return;
233 299
 
234
-                          final shouldLogout = await showDialog<bool>(
235
-                            context: context,
236
-                            builder: (context) {
237
-                              final isIOS = Theme.of(context).platform == TargetPlatform.iOS;
238
-                              
239
-                              if (isIOS) {
240
-                                // iOS风格:确定在右边,取消在左边
241
-                                return AlertDialog(
242
-                                  title: const Text('确认退出'),
243
-                                  content: const Text('确定要退出登录吗?'),
244
-                                  actionsAlignment: MainAxisAlignment.spaceBetween,
245
-                                  actions: [
246
-                                    TextButton(
247
-                                      onPressed: () => Navigator.of(context).pop(true),
248
-                                      child: const Text('确定'),
249
-                                    ),
250
-                                    TextButton(
251
-                                      onPressed: () => Navigator.of(context).pop(false),
252
-                                      child: const Text('取消'),
253
-                                    ),
254
-                                  ],
255
-                                );
256
-                              } else {
257
-                                // Android/Material风格:取消在左边,确定在右边
258
-                                return AlertDialog(
259
-                                  title: const Text('确认退出'),
260
-                                  content: const Text('确定要退出登录吗?'),
261
-                                  actionsAlignment: MainAxisAlignment.spaceBetween,
262
-                                  actions: [
263
-                                    TextButton(
264
-                                      onPressed: () => Navigator.of(context).pop(false),
265
-                                      child: const Text('取消'),
266
-                                    ),
267
-                                    TextButton(
268
-                                      onPressed: () => Navigator.of(context).pop(true),
269
-                                      child: const Text('确定'),
270
-                                    ),
271
-                                  ],
272
-                                );
273
-                              }
274
-                            },
275
-                          );
276
-                          
277
-                          if (shouldLogout == true) {
278
-                            await authProvider.logout();
300
+                            final shouldLogout = await showDialog<bool>(
301
+                              context: context,
302
+                              builder: (context) {
303
+                                final isIOS = Theme.of(context).platform == TargetPlatform.iOS;
304
+                                
305
+                                if (isIOS) {
306
+                                  // iOS风格:确定在右边,取消在左边
307
+                                  return AlertDialog(
308
+                                    title: const Text('确认退出'),
309
+                                    content: const Text('确定要退出登录吗?'),
310
+                                    actionsAlignment: MainAxisAlignment.spaceBetween,
311
+                                    actions: [
312
+                                      TextButton(
313
+                                        onPressed: () => Navigator.of(context).pop(true),
314
+                                        child: const Text('确定'),
315
+                                      ),
316
+                                      TextButton(
317
+                                        onPressed: () => Navigator.of(context).pop(false),
318
+                                        child: const Text('取消'),
319
+                                      ),
320
+                                    ],
321
+                                  );
322
+                                } else {
323
+                                  // Android/Material风格:取消在左边,确定在右边
324
+                                  return AlertDialog(
325
+                                    title: const Text('确认退出'),
326
+                                    content: const Text('确定要退出登录吗?'),
327
+                                    actionsAlignment: MainAxisAlignment.spaceBetween,
328
+                                    actions: [
329
+                                      TextButton(
330
+                                        onPressed: () => Navigator.of(context).pop(false),
331
+                                        child: const Text('取消'),
332
+                                      ),
333
+                                      TextButton(
334
+                                        onPressed: () => Navigator.of(context).pop(true),
335
+                                        child: const Text('确定'),
336
+                                      ),
337
+                                    ],
338
+                                  );
339
+                                }
340
+                              },
341
+                            );
342
+                            
343
+                            if (shouldLogout == true) {
344
+                              await authProvider.logout();
279 345
 
280
-                            // 登出后,确保在组件仍然存在时进行导航
281
-                            if (mounted) {
282
-                              // 使用pushReplacementNamed清空导航栈
283
-                              Navigator.of(context).pushReplacementNamed(RouteConstants.home);
346
+                              // 登出后,确保在组件仍然存在时进行导航
347
+                              if (mounted) {
348
+                                // 使用pushReplacementNamed清空导航栈
349
+                                Navigator.of(context).pushReplacementNamed(RouteConstants.home);
350
+                              }
284 351
                             }
285
-                          }
286
-                        },
287
-                      ),
352
+                          },
353
+                        ),
354
+                      ],
288 355
                     ],
289 356
                   ),
290 357
                   const SizedBox(height: 20),
291
-                  
292 358
                   // 版本信息
293 359
                   Padding(
294 360
                     padding: const EdgeInsets.symmetric(vertical: 20),

+ 0
- 20
lib/presentation/screens/services/services_screen.dart Näytä tiedosto

@@ -15,26 +15,6 @@ class ServicesScreen extends StatelessWidget {
15 15
         child: Column(
16 16
           crossAxisAlignment: CrossAxisAlignment.start,
17 17
           children: [
18
-            // 搜索框
19
-            Container(
20
-              decoration: BoxDecoration(
21
-                color: Colors.grey[100],
22
-                borderRadius: BorderRadius.circular(25),
23
-              ),
24
-              child: TextField(
25
-                decoration: InputDecoration(
26
-                  hintText: '搜索服务...',
27
-                  border: InputBorder.none,
28
-                  prefixIcon: const Icon(Icons.search),
29
-                  contentPadding: const EdgeInsets.symmetric(
30
-                    vertical: 15,
31
-                    horizontal: 20,
32
-                  ),
33
-                ),
34
-              ),
35
-            ),
36
-            const SizedBox(height: 30),
37
-            
38 18
             // 服务分类
39 19
             const Text(
40 20
               '服务分类',

+ 72
- 0
lib/presentation/widgets/common/app_search_bar.dart Näytä tiedosto

@@ -0,0 +1,72 @@
1
+// 独立的搜索框组件
2
+import 'package:flutter/material.dart';
3
+
4
+class SearchBarCustom extends StatefulWidget {
5
+  final ValueChanged<String>? onSearch;
6
+  final ValueChanged<String>? onChanged;
7
+  final VoidCallback? onClear;
8
+  final String hintText;
9
+  
10
+  const SearchBarCustom({
11
+    super.key,
12
+    this.onSearch,
13
+    this.onChanged,
14
+    this.onClear,
15
+    this.hintText = '搜索...',
16
+  });
17
+  
18
+  @override
19
+  State<SearchBarCustom> createState() => _SearchBarCustomState();
20
+}
21
+
22
+class _SearchBarCustomState extends State<SearchBarCustom> {
23
+  final TextEditingController _controller = TextEditingController();
24
+  final FocusNode _focusNode = FocusNode();
25
+  
26
+  @override
27
+  void dispose() {
28
+    _controller.dispose();
29
+    _focusNode.dispose();
30
+    super.dispose();
31
+  }
32
+  
33
+  @override
34
+  Widget build(BuildContext context) {
35
+    return Container(
36
+      decoration: BoxDecoration(
37
+        color: Colors.grey[100],
38
+        borderRadius: BorderRadius.circular(15),
39
+      ),
40
+      child: TextField(
41
+        controller: _controller,
42
+        focusNode: _focusNode,
43
+        decoration: InputDecoration(
44
+          hintText: widget.hintText,
45
+          border: InputBorder.none,
46
+          prefixIcon: const Icon(Icons.search),
47
+          suffixIcon: _controller.text.isNotEmpty
48
+              ? IconButton(
49
+                  icon: const Icon(Icons.clear),
50
+                  onPressed: () {
51
+                    _controller.clear();
52
+                    widget.onClear?.call();
53
+                  },
54
+                )
55
+              : null,
56
+          contentPadding: const EdgeInsets.symmetric(
57
+            vertical: 15,
58
+            horizontal: 20,
59
+          ),
60
+        ),
61
+        onChanged: (value) {
62
+          setState(() {}); // 更新清除按钮显示
63
+          widget.onChanged?.call(value);
64
+        },
65
+        onSubmitted: (value) {
66
+          widget.onSearch?.call(value);
67
+          _focusNode.unfocus();
68
+        },
69
+      ),
70
+    );
71
+  }
72
+}