alroyso 1 год назад
Родитель
Сommit
6cfff37717

+ 5 - 0
lib/app/common/constants.dart

@@ -0,0 +1,5 @@
+
+
+const kSysConfig = "/api/client/v3/getconfig";
+const kLogin = "/api/client/v3/login";
+const kNode = '';

+ 1 - 0
lib/app/component/connection_status.dart

@@ -0,0 +1 @@
+enum ConnectionStatus { disconnected, connecting, stopped }

+ 105 - 0
lib/app/component/connection_widget.dart

@@ -0,0 +1,105 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+import 'connection_status.dart';
+
+class ConnectionWidget extends StatefulWidget {
+
+  final ConnectionStatus status;
+  final Function(ConnectionStatus) onStatusChange;
+  const ConnectionWidget({super.key, required this.status, required this.onStatusChange});
+
+  @override
+  _ConnectionWidgetState createState() => _ConnectionWidgetState();
+}
+
+class _ConnectionWidgetState extends State<ConnectionWidget> {
+
+  ConnectionStatus _currentStatus = ConnectionStatus.disconnected;
+  late String currentImage;
+
+  @override
+  void initState() {
+    super.initState();
+    _updateImage();
+  }
+
+  void _updateStatus() {
+    setState(() {
+      switch (_currentStatus) {
+        case ConnectionStatus.disconnected:
+          _currentStatus = ConnectionStatus.connecting;
+          Future.delayed(const Duration(seconds: 5), () {
+            if (mounted) { // 确保Widget仍然在Widget树中
+              setState(() {
+                _currentStatus = ConnectionStatus.stopped;
+                _updateImage();
+              });
+            }
+          });
+          break;
+        case ConnectionStatus.connecting:
+        // 在"connecting"状态时加入延迟
+
+        //_currentStatus = ConnectionStatus.stopped;
+          break;
+        case ConnectionStatus.stopped:
+          _currentStatus = ConnectionStatus.disconnected;
+          break;
+      }
+      _updateImage();
+    });
+  }
+
+  @override
+  void didUpdateWidget(ConnectionWidget oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    _updateImage();
+  }
+
+  void _updateImage() {
+    switch (_currentStatus) {
+      case ConnectionStatus.disconnected:
+        currentImage = 'images/main/disconnected.gif';
+        break;
+      case ConnectionStatus.connecting:
+        currentImage = 'images/main/connecting.gif';
+        break;
+      case ConnectionStatus.stopped:
+        currentImage = 'images/main/stopped.gif';
+        break;
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Stack(
+      alignment: Alignment.center,
+      children: <Widget>[
+        // Gif作为背景
+        Image.asset(currentImage, fit: BoxFit.cover,width: 300,height: 300,),
+
+        // 圆形透明按钮
+        ClipOval(
+          child: Material(
+            color: Colors.transparent,
+            child: GestureDetector(
+              onTap: _updateStatus,
+              child: Container(
+                width: 100,  // 按钮宽度
+                height: 100, // 按钮高度
+                decoration: const BoxDecoration(
+                  shape: BoxShape.circle,
+                  color: Colors.transparent,
+                ),
+              ),
+            ),
+          ),
+        ),
+      ],
+    );
+
+
+
+  }
+}

+ 21 - 0
lib/app/data/model/LocalUser.dart

@@ -0,0 +1,21 @@
+class LocalUser {
+  String? email;
+  String? password;
+  String? accessToken;
+
+  LocalUser({this.email, this.password, this.accessToken});
+
+  LocalUser.fromJson(Map<String, dynamic> json) {
+    email = json['email'];
+    password = json['password'];
+    accessToken = json['access_token'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['email'] = this.email;
+    data['password'] = this.password;
+    data['accessToken'] = this.accessToken;
+    return data;
+  }
+}

+ 52 - 0
lib/app/data/model/LoginMode.dart

@@ -0,0 +1,52 @@
+import 'UserMode.dart';
+
+class LoginMode {
+  String? accessToken;
+  User? user;
+  String? tutorial;
+  String? swoftdownload;
+  String? affurl;
+  String? userLoginUrl;
+  String? userBuy;
+  String? userTicket;
+  String? clashConfig;
+
+  LoginMode(
+      {this.accessToken,
+        this.user,
+        this.tutorial,
+        this.swoftdownload,
+        this.affurl,
+        this.userLoginUrl,
+        this.userBuy,
+        this.userTicket,
+        this.clashConfig});
+
+  LoginMode.fromJson(Map<String, dynamic> json) {
+    accessToken = json['access_token'];
+    user = json['user'] != null ? User.fromJson(json['user']) : null;
+    tutorial = json['tutorial'];
+    swoftdownload = json['swoftdownload'];
+    affurl = json['affurl'];
+    userLoginUrl = json['user_login_url'];
+    userBuy = json['user_buy'];
+    userTicket = json['user_ticket'];
+    clashConfig = json['clash_config'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['access_token'] = this.accessToken;
+    if (this.user != null) {
+      data['user'] = this.user!.toJson();
+    }
+    data['tutorial'] = this.tutorial;
+    data['swoftdownload'] = this.swoftdownload;
+    data['affurl'] = this.affurl;
+    data['user_login_url'] = this.userLoginUrl;
+    data['user_buy'] = this.userBuy;
+    data['user_ticket'] = this.userTicket;
+    data['clash_config'] = this.clashConfig;
+    return data;
+  }
+}

+ 108 - 0
lib/app/data/model/UserMode.dart

@@ -0,0 +1,108 @@
+class User {
+  int? id;
+  String? nickname;
+  String? account;
+  int? port;
+  String? passwd;
+  String? uuid;
+  int? transferEnable;
+  String? unusedTraffic;
+  int? u;
+  int? d;
+  int? t;
+  int? enable;
+  int? speedLimit;
+  int? credit;
+  String? expiredAt;
+  Null? banTime;
+  String? level;
+  Null? group;
+  int? lastLogin;
+  Null? resetTime;
+  int? inviteNum;
+  Null? userGroupId;
+  int? status;
+  String? code;
+
+  User(
+      {this.id,
+        this.nickname,
+        this.account,
+        this.port,
+        this.passwd,
+        this.uuid,
+        this.transferEnable,
+        this.unusedTraffic,
+        this.u,
+        this.d,
+        this.t,
+        this.enable,
+        this.speedLimit,
+        this.credit,
+        this.expiredAt,
+        this.banTime,
+        this.level,
+        this.group,
+        this.lastLogin,
+        this.resetTime,
+        this.inviteNum,
+        this.userGroupId,
+        this.status,
+        this.code});
+
+  User.fromJson(Map<String, dynamic> json) {
+    id = json['id'];
+    nickname = json['nickname'];
+    account = json['account'];
+    port = json['port'];
+    passwd = json['passwd'];
+    uuid = json['uuid'];
+    transferEnable = json['transfer_enable'];
+    unusedTraffic = json['unusedTraffic'];
+    u = json['u'];
+    d = json['d'];
+    t = json['t'];
+    enable = json['enable'];
+    speedLimit = json['speed_limit'];
+    credit = json['credit'];
+    expiredAt = json['expired_at'];
+    banTime = json['ban_time'];
+    level = json['level'];
+    group = json['group'];
+    lastLogin = json['last_login'];
+    resetTime = json['reset_time'];
+    inviteNum = json['invite_num'];
+    userGroupId = json['user_group_id'];
+    status = json['status'];
+    code = json['code'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['id'] = this.id;
+    data['nickname'] = this.nickname;
+    data['account'] = this.account;
+    data['port'] = this.port;
+    data['passwd'] = this.passwd;
+    data['uuid'] = this.uuid;
+    data['transfer_enable'] = this.transferEnable;
+    data['unusedTraffic'] = this.unusedTraffic;
+    data['u'] = this.u;
+    data['d'] = this.d;
+    data['t'] = this.t;
+    data['enable'] = this.enable;
+    data['speed_limit'] = this.speedLimit;
+    data['credit'] = this.credit;
+    data['expired_at'] = this.expiredAt;
+    data['ban_time'] = this.banTime;
+    data['level'] = this.level;
+    data['group'] = this.group;
+    data['last_login'] = this.lastLogin;
+    data['reset_time'] = this.resetTime;
+    data['invite_num'] = this.inviteNum;
+    data['user_group_id'] = this.userGroupId;
+    data['status'] = this.status;
+    data['code'] = this.code;
+    return data;
+  }
+}

+ 19 - 6
lib/app/modules/home/controllers/home_controller.dart

@@ -1,11 +1,17 @@
 import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
-
 import '../../../common/LogHelper.dart';
 import '../../../common/SharedPreferencesUtil.dart';
 import '../../../data/model/SysConfig.dart';
 import '../../../network/api_service.dart';
 
+enum ImageType {
+  CUSTOMER,
+  PROMOTION,
+  TUTORIAL,
+  RENEWAL,
+}
+
 class HomeController extends GetxController {
   //TODO: Implement HomeController
 
@@ -13,9 +19,19 @@ class HomeController extends GetxController {
   var sysConfig = SysConfig().obs;
   var errorMsg = ''.obs;
 
+  final Map<ImageType, String> imageMap = {
+    ImageType.CUSTOMER: "images/main/customer.png",
+    ImageType.PROMOTION: "images/main/promotion.png",
+    ImageType.TUTORIAL: "images/main/tutorial.png",
+    ImageType.RENEWAL: "images/main/renewal.png",
+  };
+
+  void onImageTap(ImageType type) {
+    LogHelper().d("${imageMap[type]} tapped as ${type.toString().split('.').last}");
+  }
+
   Future<void> fetchSysConfig() async {
     try {
-      isLoading.value = true;
       Map<String, dynamic>? data  = await SharedPreferencesUtil().getObject("sysconfig");
       if(data  != null){
         sysConfig.value = SysConfig.fromJson(data);
@@ -24,16 +40,14 @@ class HomeController extends GetxController {
     } catch (e) {
       errorMsg.value = e.toString();
     } finally {
-      isLoading.value = false;
     }
   }
 
   final count = 0.obs;
   @override
   void onInit() {
-
     super.onInit();
-    //fetchSysConfig();
+    fetchSysConfig();
   }
 
   @override
@@ -46,5 +60,4 @@ class HomeController extends GetxController {
     super.onClose();
   }
 
-  void increment() => count.value++;
 }

+ 117 - 69
lib/app/modules/home/views/home_view.dart

@@ -6,10 +6,14 @@ import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/component/sys_app_bar.dart';
 import 'package:window_manager/window_manager.dart';
+import '../../../component/connection_status.dart';
+import '../../../component/connection_widget.dart';
 
 import '../controllers/home_controller.dart';
 
+
 class HomeView extends GetView<HomeController> {
+
   const HomeView({Key? key}) : super(key: key);
 
   @override
@@ -17,99 +21,143 @@ class HomeView extends GetView<HomeController> {
     return Container(
       decoration: const BoxDecoration(
         image: DecorationImage(
-          image: AssetImage("images/login/login.png"),
+          image: AssetImage("images/main/main.png"),
           fit: BoxFit.fill,
         ),
       ),
       child: Scaffold(
           backgroundColor: Colors.transparent,
-          appBar: const SysAppBar(title: Text("登录"),),
+          appBar: const SysAppBar(title: Text("首页"),),
 
           body: Obx(() {
-            return LoginScreen(isLoading: controller.isLoading.value,
-                onLogin: (username, password) {
-                  controller.fetchSysConfig();
-                  // 在这里处理登录逻辑,例如调用API
-                  print('Username: $username');
-                  print('Password: $password');
-                });
+            return Column(
+              children: [
+                UserStatusWidget(isActive: true,isLoading: controller.isLoading.value,username:"",expiryDate: "",userTraffic:"",onRefresh: () async {
+                  // 这里插入刷新操作代码
+                  //await Future.delayed(Duration(seconds: 2));
+                },),
+                Padding(
+                    padding: const EdgeInsets.fromLTRB(20, 20, 0, 0),
+                    child: Row(
+                      children: controller.imageMap.entries.expand((entry) {
+                        return [
+                          GestureDetector(
+                            onTap: () => controller.onImageTap(entry.key),
+                            child: Image(
+                              image: AssetImage(entry.value),
+                              width: 60,
+                              height: 60,
+                            ),
+                          ),
+                          //Spacer(), // 平均分配间隔
+                          const SizedBox(width: 30),
+                        ];
+                      }).toList()
+                        ..removeLast(), // 删除最后一个Spacer
+                    )
+
+                ),
+                const SizedBox(height: 35,),
+                const Padding(
+                  padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
+                  child: Row(
+                    children: [
+
+                      Text("http://127.0.0.1:5336"),
+                      Spacer(),
+                      Text("socks://127.0.0.1:5337"),
+                    ],
+                  ),
+                ),
+                ConnectionWidget(
+                  status: ConnectionStatus.disconnected, onStatusChange: (con) {
+
+                },)
+              ],
+            );
           })
       ),
     );
   }
 }
 
-class LoginScreen extends StatefulWidget {
-  final Function(String username, String password) onLogin;
-  final bool isLoading;
+class UserStatusWidget extends StatefulWidget {
 
-  LoginScreen({required this.isLoading, required this.onLogin});
+  final Future<void> Function() onRefresh; // 新增的回调
+  final bool isActive;
+  final bool isLoading; // 新增的变量
+  final String username;
+  final String userTraffic;
+  final String expiryDate;
+  const UserStatusWidget({Key? key, required this.isActive, required this.isLoading,required this.username, required this.userTraffic, required this.expiryDate, required this.onRefresh}) : super(key: key);
 
   @override
-  _LoginScreenState createState() => _LoginScreenState();
+  _UserStatusWidgetState createState() => _UserStatusWidgetState();
 }
 
-class _LoginScreenState extends State<LoginScreen> {
-  final _usernameController = TextEditingController();
-  final _passwordController = TextEditingController();
-
+class _UserStatusWidgetState extends State<UserStatusWidget> {
   @override
   Widget build(BuildContext context) {
-    return Padding(
-      padding: const EdgeInsets.only(bottom: 30),
-      child: Center(
-        child: Padding(
-          padding: const EdgeInsets.fromLTRB(55, 0, 55, 0),
-          child: Column(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              TextField(
-                controller: _usernameController,
-                decoration: const InputDecoration(
-                  labelText: '用户名',
-                  hintText: '请输入用户名',
-                  border: InputBorder.none,
-                ),
-              ),
-              const SizedBox(height: 16),
-              TextField(
-                controller: _passwordController,
-                decoration: const InputDecoration(
-                  labelText: '密码',
-                  hintText: '输入密码',
-                  border: InputBorder.none,
+    String imagePath = widget.isActive
+        ? "images/main/userstatus.png"
+        : "images/main/userstatusoff.png";
+
+    return Align(
+      alignment: Alignment.topCenter,
+      child: Padding(
+        padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 10.0),
+        child:
+        Row(
+          children: [
+            const SizedBox(
+              width: 80,
+              height: 20,
+            ),
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.start, // 这将使子组件从左边开始对齐
+              children: [
+                Row(
+                  children: [
+                    Text(widget.username),
+                    const SizedBox(width: 10,),
+                    Image(
+                      image: AssetImage(imagePath),
+                      width: 100,
+                      height: 30,
+                    ),
+                    const SizedBox(width: 10,),
+                    IconButton(
+                      icon: widget.isLoading ? const CircularProgressIndicator() : Image.asset("images/main/refresh.png"),
+                      onPressed: () {
+                        // 刷新操作
+                        if(!widget.isLoading){
+                          widget.onRefresh();
+                        }
+                      },
+                    )
+                  ],
                 ),
-                obscureText: true,
-
-              ),
-              const SizedBox(height: 20),
-              SizedBox(
-                width: 200,
-                height: 40,
-                child: ElevatedButton(
-                  onPressed: () {
-                    if (!widget.isLoading) {
-                      final username = _usernameController.text;
-                      final password = _passwordController.text;
-                      widget.onLogin(username, password);
-                    }
-                  },
-                  child: widget.isLoading ? const CircularProgressIndicator(
-                    color: Colors.white,
-                  ) : const Text('登录'),
+                 Text(
+                  widget.expiryDate,
+                  style: const TextStyle(
+                    fontSize: 8.0, // 设置字体大小为20像素
+                  ),
                 ),
-              ),
-            ],
-          ),
+                Text(
+                  widget.userTraffic,
+                  style: const TextStyle(
+                    fontSize: 8.0, // 设置字体大小为20像素
+                  ),
+                )
+              ],
+            ),
+          ],
         ),
+        // const SizedBox(height: 10,),  // 可调整间隔
       ),
     );
   }
+}
+
+
 
-  @override
-  void dispose() {
-    _usernameController.dispose();
-    _passwordController.dispose();
-    super.dispose();
-  }
-}

+ 12 - 0
lib/app/modules/login/bindings/login_binding.dart

@@ -0,0 +1,12 @@
+import 'package:get/get.dart';
+
+import '../controllers/login_controller.dart';
+
+class LoginBinding extends Bindings {
+  @override
+  void dependencies() {
+    Get.lazyPut<LoginController>(
+      () => LoginController(),
+    );
+  }
+}

+ 72 - 0
lib/app/modules/login/controllers/login_controller.dart

@@ -0,0 +1,72 @@
+import 'package:get/get.dart';
+import 'package:naiyouwl/app/common/constants.dart';
+import 'package:naiyouwl/app/data/model/LoginMode.dart';
+
+import '../../../common/LogHelper.dart';
+import '../../../common/SharedPreferencesUtil.dart';
+import '../../../data/model/LocalUser.dart';
+import '../../../network/api_service.dart';
+import '../../../routes/app_pages.dart';
+
+class LoginController extends GetxController {
+
+  final count = 0.obs;
+  var isLoading = false.obs;
+  var loginModes = LoginMode().obs;
+  var localUsers = LocalUser().obs;
+  var errorMsg = ''.obs;
+
+  Future<void> fetchLogin(username,password) async {
+    try {
+      isLoading.value = true;
+      loginModes.value = await ApiService().login(kLogin,data: {"email":username,"password":password});
+
+      if(loginModes.value.accessToken != null){
+        await SharedPreferencesUtil().setString("token", loginModes.value.accessToken.toString());
+        var userModes = LocalUser(email: username,password: password,accessToken: loginModes.value.accessToken.toString());
+        await SharedPreferencesUtil().setObject("localUser", userModes.toJson());
+      }
+      Get.offNamed(Routes.HOME,arguments: loginModes.value);
+
+    } catch (e) {
+      errorMsg.value = e.toString();
+    } finally {
+      isLoading.value = false;
+    }
+  }
+
+  Future<void> fetchLocalUser() async {
+    try {
+      Map<String, dynamic>? data  = await SharedPreferencesUtil().getObject("localUser");
+      if(data  != null){
+        localUsers.value = LocalUser.fromJson(data);
+        LogHelper().d(localUsers.value.toJson());
+      }
+    } catch (e) {
+      errorMsg.value = e.toString();
+    } finally {
+      isLoading.value = false;
+    }
+  }
+  @override
+  void onInit() {
+    super.onInit();
+    fetchLocalUser();
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+  }
+
+  void increment() => count.value++;
+
+  String username() => localUsers.value.email.toString();
+  String password() => localUsers.value.password.toString();
+  String accToken() => localUsers.value.accessToken.toString();
+}

+ 118 - 0
lib/app/modules/login/views/login_view.dart

@@ -0,0 +1,118 @@
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../../../component/sys_app_bar.dart';
+import '../controllers/login_controller.dart';
+
+class LoginView extends GetView<LoginController> {
+  const LoginView({Key? key}) : super(key: key);
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      decoration: const BoxDecoration(
+        image: DecorationImage(
+          image: AssetImage("images/login/login.png"),
+          fit: BoxFit.fill,
+        ),
+      ),
+      child: Scaffold(
+          backgroundColor: Colors.transparent,
+          appBar: const SysAppBar(title: Text("登录"),),
+
+          body: Obx(() {
+            if(controller.errorMsg.isNotEmpty){
+              WidgetsBinding.instance.addPostFrameCallback((_) {
+                ScaffoldMessenger.of(context).showSnackBar(
+                    SnackBar(content: Text(controller.errorMsg.value))
+                );
+              });
+            }
+            return LoginScreen(isLoading: controller.isLoading.value,
+                username: controller.username(),
+                password: controller.password(),
+                onLogin: (username, password) {
+                  // 在这里处理登录逻辑,例如调用API
+                  controller.fetchLogin(username,password);
+                });
+          })
+      ),
+    );
+  }
+}
+
+class LoginScreen extends StatefulWidget {
+  final Function(String username, String password) onLogin;
+  final bool isLoading;
+  final String username;
+  final String password;
+  LoginScreen({required this.isLoading, required this.onLogin, required this.username, required this.password});
+
+  @override
+  _LoginScreenState createState() => _LoginScreenState();
+}
+
+class _LoginScreenState extends State<LoginScreen> {
+  final _usernameController = TextEditingController();
+  final _passwordController = TextEditingController();
+
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: const EdgeInsets.only(bottom: 30),
+      child: Center(
+        child: Padding(
+          padding: const EdgeInsets.fromLTRB(55, 0, 55, 0),
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              TextField(
+                controller: _usernameController,
+                decoration: const InputDecoration(
+                  labelText: '用户名',
+                  hintText: '请输入用户名',
+                  border: InputBorder.none,
+                ),
+              ),
+              const SizedBox(height: 16),
+              TextField(
+                controller: _passwordController,
+                decoration: const InputDecoration(
+                  labelText: '密码',
+                  hintText: '输入密码',
+                  border: InputBorder.none,
+                ),
+                obscureText: true,
+
+              ),
+              const SizedBox(height: 20),
+              SizedBox(
+                width: 200,
+                height: 40,
+                child: ElevatedButton(
+                  onPressed: () {
+                    if (!widget.isLoading) {
+                      final username = _usernameController.text;
+                      final password = _passwordController.text;
+                      widget.onLogin(username, password);
+                    }
+                  },
+                  child: widget.isLoading ? const CircularProgressIndicator(
+                    color: Colors.white,
+                  ) : const Text('登录'),
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
+  @override
+  void dispose() {
+    _usernameController.dispose();
+    _passwordController.dispose();
+    super.dispose();
+  }
+}

+ 9 - 2
lib/app/modules/welcome/controllers/welcome_controller.dart

@@ -1,5 +1,6 @@
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/common/SharedPreferencesUtil.dart';
+import 'package:naiyouwl/app/common/constants.dart';
 
 import '../../../data/model/SysConfig.dart';
 import '../../../network/api_service.dart';
@@ -13,10 +14,16 @@ class WelcomeController extends GetxController {
   Future<void> fetchSysConfig() async {
     try {
       isLoading.value = true;
-      sysConfig.value = await ApiService().fetchSysConfig("/api/client/v3/getconfig");
+      sysConfig.value = await ApiService().fetchSysConfig(kSysConfig);
       await SharedPreferencesUtil().setObject("sysconfig", sysConfig.value.toJson());
 
-      Get.offNamed(Routes.HOME);
+      var token = await SharedPreferencesUtil().getString("token");
+      if(token != null){
+        Get.offNamed(Routes.HOME);
+      }else {
+        Get.offNamed(Routes.LOGIN);
+      }
+
 
     } catch (e) {
       errorMsg.value = e.toString();

+ 27 - 6
lib/app/network/api_service.dart

@@ -1,3 +1,6 @@
+import 'package:dio/dio.dart';
+import 'package:naiyouwl/app/data/model/LoginMode.dart';
+
 import '../data/model/SysConfig.dart';
 import 'dio_client.dart';
 
@@ -11,12 +14,16 @@ class ApiService {
 
 
   Future<SysConfig> fetchSysConfig(String path) async {
-    try {
-      final Map<String, dynamic> data = await _dioClient.get(path);
-      return SysConfig.fromJson(data);
-    } catch (e) {
-      throw Exception('Failed to fetch user: $e');
-    }
+    final Map<String, dynamic> data = await _requestWrapper(() => _dioClient.get(path));
+    return SysConfig.fromJson(data);
+
+  }
+
+  Future<LoginMode> login(String path, {Map<String, dynamic>? data}) async {
+
+      final Map<String, dynamic> retData =await _requestWrapper(() => _dioClient.post(path,data: data));
+      return LoginMode.fromJson(retData);
+
   }
 
   Future<Map<String, dynamic>> fetchData(String path, {Map<String, dynamic>? queryParameters}) async {
@@ -34,4 +41,18 @@ class ApiService {
   Future<void> downloadFile(String urlPath, String savePath) async {
     await _dioClient.download(urlPath, savePath);
   }
+
+
+  Future<Map<String, dynamic>> _requestWrapper(Future<Map<String, dynamic>> Function() apiCall) async {
+    try {
+      return await apiCall();
+    } catch (e) {
+      if (e is DioError && e.error is AppException) {
+        throw e.error; // 抛出自定义的AppException
+      } else {
+        throw Exception('API request failed: $e');
+      }
+    }
+  }
+
 }

+ 7 - 0
lib/app/routes/app_pages.dart

@@ -2,6 +2,8 @@ import 'package:get/get.dart';
 
 import '../modules/home/bindings/home_binding.dart';
 import '../modules/home/views/home_view.dart';
+import '../modules/login/bindings/login_binding.dart';
+import '../modules/login/views/login_view.dart';
 import '../modules/welcome/bindings/welcome_binding.dart';
 import '../modules/welcome/views/welcome_view.dart';
 
@@ -23,5 +25,10 @@ class AppPages {
       page: () => const WelcomeView(),
       binding: WelcomeBinding(),
     ),
+    GetPage(
+      name: _Paths.LOGIN,
+      page: () => const LoginView(),
+      binding: LoginBinding(),
+    ),
   ];
 }

+ 2 - 0
lib/app/routes/app_routes.dart

@@ -5,10 +5,12 @@ abstract class Routes {
   Routes._();
   static const HOME = _Paths.HOME;
   static const WELCOME = _Paths.WELCOME;
+  static const LOGIN = _Paths.LOGIN;
 }
 
 abstract class _Paths {
   _Paths._();
   static const HOME = '/home';
   static const WELCOME = '/welcome';
+  static const LOGIN = '/login';
 }