add
This commit is contained in:
@@ -1,101 +1,82 @@
|
|||||||
|
import 'package:asset_assistant/pages/home_page.dart';
|
||||||
import 'package:asset_assistant/pages/login_page.dart';
|
import 'package:asset_assistant/pages/login_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
runApp(const MyApp());
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final userId = prefs.getString('user_id');
|
||||||
|
debugPrint('初始化路由,用户ID: $userId');
|
||||||
|
runApp(MyApp(initialRoute: userId != null ? '/home' : '/login'));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
final String initialRoute;
|
||||||
|
const MyApp({super.key, required this.initialRoute});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// 金融风格暗夜主题
|
|
||||||
final darkTheme = ThemeData(
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
primaryColor: const Color(0xFF0F3460), // 主色调:深蓝色
|
|
||||||
colorScheme: ColorScheme.dark(
|
|
||||||
primary: const Color(0xFF0F3460),
|
|
||||||
secondary: const Color(0xFFD4AF37),
|
|
||||||
surface: const Color(0xFF121212), // 页面主背景
|
|
||||||
surfaceContainerHighest: const Color(0xFF1E1E1E), // 卡片背景(分层色)
|
|
||||||
onPrimary: Colors.white,
|
|
||||||
onSecondary: Colors.black,
|
|
||||||
onSurface: Colors.white70, // 所有表面的默认文本色
|
|
||||||
),
|
|
||||||
// 文本样式(继承 onSurface 颜色,增强可读性)
|
|
||||||
textTheme: TextTheme(
|
|
||||||
bodyLarge: TextStyle(color: Colors.white70, fontSize: 16, height: 1.5),
|
|
||||||
bodyMedium: TextStyle(color: Colors.white60, fontSize: 14, height: 1.5),
|
|
||||||
headlineLarge: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
headlineMedium: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 输入框样式
|
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderSide: const BorderSide(color: Color(0xFF333333)),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
enabledBorder: OutlineInputBorder(
|
|
||||||
borderSide: const BorderSide(color: Color(0xFF333333)),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderSide: const BorderSide(color: Color(0xFFD4AF37), width: 2),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
labelStyle: const TextStyle(color: Colors.white60),
|
|
||||||
prefixIconColor: Colors.white60,
|
|
||||||
hintStyle: const TextStyle(color: Colors.white38),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
vertical: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 按钮样式
|
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: const Color(0xFF0F3460),
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
||||||
textStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
|
||||||
elevation: 2,
|
|
||||||
shadowColor: Colors.black54,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 文本按钮样式(忘记密码)
|
|
||||||
textButtonTheme: TextButtonThemeData(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
foregroundColor: const Color(0xFFD4AF37), // 金色文本,符合辅助色
|
|
||||||
textStyle: const TextStyle(fontSize: 14),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 卡片样式
|
|
||||||
cardTheme: CardThemeData(
|
|
||||||
color: const Color(0xFF1E1E1E),
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
side: const BorderSide(color: Color(0xFF333333)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 去除页面默认边距
|
|
||||||
scaffoldBackgroundColor: const Color(0xFF121212),
|
|
||||||
);
|
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: '资产助手',
|
title: '资产助手',
|
||||||
theme: darkTheme,
|
debugShowCheckedModeBanner: false, // 移除 debug 标签
|
||||||
home: const LoginPage(),
|
initialRoute: initialRoute,
|
||||||
|
routes: {
|
||||||
|
'/login': (context) => const LoginPage(),
|
||||||
|
'/home': (context) => const HomePage(),
|
||||||
|
},
|
||||||
|
theme: ThemeData(
|
||||||
|
// 金融暗夜风格主题配置
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
colorScheme: ColorScheme.dark(
|
||||||
|
primary: const Color(0xFF0070F3), // 主色调:深蓝色
|
||||||
|
secondary: const Color(0xFF64FFDA), // 辅助色:亮青色
|
||||||
|
// 将 background 替换为 surface
|
||||||
|
surface: const Color(0xFF0F172A), // 背景色:深灰蓝
|
||||||
|
// 使用 surfaceContainerHighest 替代 deprecated 的 surfaceVariant
|
||||||
|
surfaceContainerHighest: const Color(0xFF1E293B), // 表面色:中灰蓝
|
||||||
|
onPrimary: Colors.white,
|
||||||
|
onSecondary: Colors.black87,
|
||||||
|
// 将 onBackground 替换为 onSurface
|
||||||
|
onSurface: Colors.white,
|
||||||
|
onSurfaceVariant: Colors.white70,
|
||||||
|
),
|
||||||
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
filled: true,
|
||||||
|
fillColor: const Color(0xFF1E293B),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(color: Color(0xFF334155)),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(color: Color(0xFF0070F3), width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
hintStyle: const TextStyle(color: Color(0xFF94A3B8)),
|
||||||
|
labelStyle: const TextStyle(color: Color(0xFFCBD5E1)),
|
||||||
|
),
|
||||||
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF0070F3),
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
textButtonTheme: TextButtonThemeData(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: const Color(0xFF94A3B8),
|
||||||
|
textStyle: const TextStyle(fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
home: const LoginPage(), // 初始显示登录页
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import 'package:asset_assistant/pages/home_page.dart';
|
import 'package:asset_assistant/pages/home_page.dart';
|
||||||
import 'package:asset_assistant/utils/host_manager.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:dio/dio.dart';
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
// 登录页面
|
// 登录页面
|
||||||
@@ -39,30 +37,36 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 构建请求URL
|
// 构建请求URL
|
||||||
final url = HostManager().getUriHostByPath("/user/login");
|
const baseUrl = 'https://api.fishestlife.com';
|
||||||
debugPrint('url is: $url');
|
const path = '/user/login';
|
||||||
|
final url = '$baseUrl$path';
|
||||||
|
debugPrint('请求URL: $url');
|
||||||
|
|
||||||
|
// 初始化Dio实例
|
||||||
|
final dio = Dio();
|
||||||
|
|
||||||
// 发送POST请求
|
// 发送POST请求
|
||||||
final response = await http.post(
|
final response = await dio.post(
|
||||||
url,
|
url,
|
||||||
headers: {'Content-Type': 'application/json'},
|
data: {'account': account, 'password': password},
|
||||||
body: json.encode({'account': account, 'password': password}),
|
options: Options(
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
responseType: ResponseType.json,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 解析响应
|
// 解析响应
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final result = json.decode(response.body);
|
final result = response.data;
|
||||||
// 打印后端返回的完整数据,确认code和状态
|
// 打印后端返回的完整数据,确认code和状态
|
||||||
debugPrint('登录响应:$result');
|
debugPrint('登录响应:$result');
|
||||||
|
|
||||||
if (result['success'] == true) {
|
if (result['success'] == true) {
|
||||||
debugPrint('登录成功,准备跳转');
|
debugPrint('登录成功,准备跳转');
|
||||||
|
|
||||||
// 保存token和用户信息到本地存储
|
// 保存token和用户信息到本地存储
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setString(
|
await prefs.setString('user_id', result['data']['user_id']); // 保存用户ID
|
||||||
'user_id',
|
|
||||||
result['data']['user_id'],
|
|
||||||
); // 保存用户ID。
|
|
||||||
debugPrint('保存的用户ID: ${result['data']['user_id']}');
|
debugPrint('保存的用户ID: ${result['data']['user_id']}');
|
||||||
|
|
||||||
// 延迟后再检查上下文是否仍有效
|
// 延迟后再检查上下文是否仍有效
|
||||||
@@ -80,8 +84,27 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
_showDialog('错误', '服务器响应异常: ${response.statusCode}');
|
_showDialog('错误', '服务器响应异常: ${response.statusCode}');
|
||||||
debugPrint('服务器响应异常: ${response.statusCode}');
|
debugPrint('服务器响应异常: ${response.statusCode}');
|
||||||
}
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
// 处理Dio异常
|
||||||
|
String errorMessage = '网络请求失败';
|
||||||
|
if (e.response != null) {
|
||||||
|
errorMessage =
|
||||||
|
'请求失败: ${e.response?.statusCode} - ${e.response?.statusMessage}';
|
||||||
|
debugPrint('响应数据: ${e.response?.data}');
|
||||||
|
} else if (e.type == DioExceptionType.connectionTimeout) {
|
||||||
|
errorMessage = '连接超时,请检查网络';
|
||||||
|
} else if (e.type == DioExceptionType.receiveTimeout) {
|
||||||
|
errorMessage = '接收数据超时';
|
||||||
|
} else if (e.type == DioExceptionType.sendTimeout) {
|
||||||
|
errorMessage = '发送数据超时';
|
||||||
|
} else if (e.type == DioExceptionType.connectionError) {
|
||||||
|
errorMessage = '网络连接错误,请检查网络设置';
|
||||||
|
}
|
||||||
|
|
||||||
|
_showDialog('错误', errorMessage);
|
||||||
|
debugPrint('详细错误信息: ${e.toString()}');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_showDialog('错误', '网络请求失败: $e');
|
_showDialog('错误', '发生未知错误: $e');
|
||||||
debugPrint('详细错误信息: ${e.toString()}');
|
debugPrint('详细错误信息: ${e.toString()}');
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class HostManager {
|
|
||||||
// 单例实例
|
|
||||||
static final HostManager _instance = HostManager._internal();
|
|
||||||
|
|
||||||
// 工厂构造函数,确保保证只有一个实例
|
|
||||||
factory HostManager() => _instance;
|
|
||||||
|
|
||||||
// 私有构造函数
|
|
||||||
HostManager._internal();
|
|
||||||
|
|
||||||
// 判断是否为开发环境
|
|
||||||
bool get isDebug => const bool.fromEnvironment('dart.vm.product') == false;
|
|
||||||
|
|
||||||
Uri getUriHostByPath(String path) {
|
|
||||||
final host = HostManager().getHostByPath(path);
|
|
||||||
final url = Uri.parse(host);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据传入的path返回对应的host
|
|
||||||
// 可根据实际需求扩展path与host的映射关系
|
|
||||||
String getHostByPath(String path) {
|
|
||||||
debugPrint('path is:$path');
|
|
||||||
String host = "";
|
|
||||||
if (!isDebug) {
|
|
||||||
debugPrint('release model');
|
|
||||||
host = "https://api.fishestlife.com";
|
|
||||||
} else {
|
|
||||||
debugPrint('debug model');
|
|
||||||
if (path.startsWith('/user')) {
|
|
||||||
host = "https://api.fishestlife.com";
|
|
||||||
} else {
|
|
||||||
host = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debugPrint('url is:$host$path');
|
|
||||||
return host + path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,7 @@ import 'package:asset_assistant/main.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
// Build our app and trigger a frame.
|
// Build our app and trigger a frame.
|
||||||
await tester.pumpWidget(const MyApp());
|
await tester.pumpWidget(const MyApp(initialRoute: ''));
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
// Verify that our counter starts at 0.
|
||||||
expect(find.text('0'), findsOneWidget);
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
|||||||
Reference in New Issue
Block a user