Browse Source

新增:离线登录

dev
徐振升 2 weeks ago
parent
commit
1397875a11
  1. 2
      README.md
  2. 12
      lib/app/routes/app_pages.dart
  3. 1
      lib/app/routes/app_routes.dart
  4. 38
      lib/data/providers/user_provider.dart
  5. 0
      lib/data/repositories/auth_repository.dart
  6. 17
      lib/modules/my/bingdings/change_password_binding.dart
  7. 57
      lib/modules/my/controllers/change_password_controller.dart
  8. 166
      lib/modules/my/views/change_password.dart
  9. 11
      lib/modules/my/views/my_page.dart
  10. 4
      lib/modules/problem/views/problem_page.dart
  11. 2
      lib/modules/problem/views/problem_upload_page.dart
  12. 0
      lib/modules/problem/views/widgets/custom_button.dart
  13. 0
      lib/modules/problem/views/widgets/date_picker_button.dart
  14. 2
      lib/modules/problem/views/widgets/problem_card.dart
  15. 2
      macos/Flutter/GeneratedPluginRegistrant.swift
  16. 56
      pubspec.lock
  17. 1
      pubspec.yaml
  18. 3
      windows/flutter/generated_plugin_registrant.cc
  19. 1
      windows/flutter/generated_plugins.cmake

2
README.md

@ -1,5 +1,7 @@
# problem_check_system # problem_check_system
系统架构为MVVM + 仓库模式
这个应用需要实现以下功能: 这个应用需要实现以下功能:
离线登录系统 离线登录系统

12
lib/app/routes/app_pages.dart

@ -3,6 +3,8 @@ import 'package:problem_check_system/modules/home/bindings/home_binding.dart';
import 'package:problem_check_system/modules/home/views/home_page.dart'; import 'package:problem_check_system/modules/home/views/home_page.dart';
import 'package:problem_check_system/modules/auth/bindings/auth_binding.dart'; import 'package:problem_check_system/modules/auth/bindings/auth_binding.dart';
import 'package:problem_check_system/modules/auth/views/login_page.dart'; import 'package:problem_check_system/modules/auth/views/login_page.dart';
import 'package:problem_check_system/modules/my/bingdings/change_password_binding.dart';
import 'package:problem_check_system/modules/my/views/change_password.dart';
import 'app_routes.dart'; import 'app_routes.dart';
@ -20,11 +22,11 @@ abstract class AppPages {
page: () => const LoginPage(), page: () => const LoginPage(),
binding: AuthBinding(), binding: AuthBinding(),
), ),
// GetPage( GetPage(
// name: AppRoutes.my, name: AppRoutes.changePassword,
// page: () => const MyPage(), page: () => const ChangePasswordPage(),
// binding: null, binding: ChangePasswordBinding(),
// ), ),
// // Problem // // Problem
// GetPage( // GetPage(
// name: AppRoutes.problem, // app_routes.dart // name: AppRoutes.problem, // app_routes.dart

1
lib/app/routes/app_routes.dart

@ -4,4 +4,5 @@ abstract class AppRoutes {
static const login = '/login'; static const login = '/login';
static const problem = '/problem'; static const problem = '/problem';
static const my = '/my'; static const my = '/my';
static const changePassword = '/changePassword';
} }

38
lib/data/providers/user_provider.dart

@ -0,0 +1,38 @@
import 'package:dio/dio.dart';
class UserProvider {
final Dio _dio;
// Dio
UserProvider({required Dio dio}) : _dio = dio;
/// API
///
/// @param newPassword
Future<Response> changePassword(String newPassword) async {
try {
final response = await _dio.post(
'/api/change_password', //
data: {
'new_password': newPassword,
},
);
return response;
} on DioException catch (e) {
// DioException 便
throw e;
}
}
/// API
///
///
Future<Response> getUserInfo() async {
try {
final response = await _dio.get('/api/user_info'); //
return response;
} on DioException catch (e) {
throw e;
}
}
}

0
lib/data/repositories/auth_repository.dart

17
lib/modules/my/bingdings/change_password_binding.dart

@ -0,0 +1,17 @@
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:problem_check_system/modules/my/controllers/change_password_controller.dart';
import 'package:problem_check_system/data/providers/user_provider.dart'; // Provider
class ChangePasswordBinding implements Bindings {
@override
void dependencies() {
// ChangePasswordController UserProvider
final dio = Get.find<Dio>();
Get.lazyPut<UserProvider>(() => UserProvider(dio: dio));
Get.lazyPut<ChangePasswordController>(
//
() => ChangePasswordController(userProvider: Get.find()),
);
}
}

57
lib/modules/my/controllers/change_password_controller.dart

@ -0,0 +1,57 @@
import 'package:get/get.dart';
import 'package:problem_check_system/data/providers/user_provider.dart'; // Provider
class ChangePasswordController extends GetxController {
//
var newPassword = ''.obs;
var confirmPassword = ''.obs;
var isLoading = false.obs;
// UserProvider API
final UserProvider _userProvider;
ChangePasswordController({required UserProvider userProvider})
: _userProvider = userProvider;
//
void updateNewPassword(String value) {
newPassword.value = value;
}
//
void updateConfirmPassword(String value) {
confirmPassword.value = value;
}
//
Future<void> changePassword() async {
//
if (newPassword.value.isEmpty || confirmPassword.value.isEmpty) {
Get.snackbar('错误', '密码不能为空');
return;
}
if (newPassword.value != confirmPassword.value) {
Get.snackbar('错误', '两次输入的密码不一致');
return;
}
isLoading.value = true;
try {
// TODO: API
// final response = await _userProvider.changePassword(newPassword.value);
// if (response.statusCode == 200) {
// Get.back();
// Get.snackbar('成功', '密码修改成功');
// } else {
// Get.snackbar('失败', '密码修改失败,请重试');
// }
//
await Future.delayed(const Duration(seconds: 2));
Get.back();
Get.snackbar('成功', '密码修改成功', snackbarStatus: (status) {});
} catch (e) {
Get.snackbar('错误', '修改密码失败: ${e.toString()}');
} finally {
isLoading.value = false;
}
}
}

166
lib/modules/my/views/change_password.dart

@ -0,0 +1,166 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:problem_check_system/modules/my/controllers/change_password_controller.dart';
class ChangePasswordPage extends StatelessWidget {
const ChangePasswordPage({super.key});
@override
Widget build(BuildContext context) {
//
final ChangePasswordController controller = Get.find<ChangePasswordController>();
return Scaffold(
appBar: _buildAppBar(),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Column(
children: [
SizedBox(height: 16.h),
_buildInputField(
label: '新密码',
hintText: '请输入新密码',
onChanged: controller.updateNewPassword,
obscureText: true,
),
SizedBox(height: 24.h),
_buildInputField(
label: '确认新密码',
hintText: '请再次输入新密码',
onChanged: controller.updateConfirmPassword,
obscureText: true,
),
const Spacer(), //
_buildButtons(controller),
SizedBox(height: 50.h),
],
),
),
);
}
/// AppBar
AppBar _buildAppBar() {
return AppBar(
backgroundColor: const Color(0xFFF1F7FF),
elevation: 0,
centerTitle: true,
title: const Text(
'修改密码',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () => Get.back(),
),
);
}
///
Widget _buildInputField({
required String label,
required String hintText,
required Function(String) onChanged,
bool obscureText = false,
}) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
SizedBox(height: 8.h),
TextField(
onChanged: onChanged,
obscureText: obscureText,
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 14.sp,
),
border: InputBorder.none, // 线
isDense: true,
contentPadding: EdgeInsets.zero,
),
),
],
),
);
}
///
Widget _buildButtons(ChangePasswordController controller) {
return Row(
children: [
//
Expanded(
child: OutlinedButton(
onPressed: () => Get.back(),
style: OutlinedButton.styleFrom(
minimumSize: Size(160.w, 48.h),
side: const BorderSide(color: Color(0xFF5695FD)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text(
'取消',
style: TextStyle(
fontSize: 16.sp,
color: const Color(0xFF5695FD),
),
),
),
),
SizedBox(width: 16.w),
//
Expanded(
child: ElevatedButton(
onPressed: () {
//
controller.changePassword();
},
style: ElevatedButton.styleFrom(
minimumSize: Size(160.w, 48.h),
backgroundColor: const Color(0xFF5695FD),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text(
'确定',
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
),
),
),
),
],
);
}
}

11
lib/modules/my/views/my_page.dart

@ -4,6 +4,8 @@ import 'package:get/get.dart';
import 'package:problem_check_system/modules/my/controllers/my_controller.dart'; import 'package:problem_check_system/modules/my/controllers/my_controller.dart';
import 'package:problem_check_system/modules/auth/controllers/auth_controller.dart'; import 'package:problem_check_system/modules/auth/controllers/auth_controller.dart';
import '../../../app/routes/app_routes.dart';
class MyPage extends StatelessWidget { class MyPage extends StatelessWidget {
const MyPage({super.key}); const MyPage({super.key});
@ -40,7 +42,7 @@ class MyPage extends StatelessWidget {
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
colors: [ colors: [
const Color(0xFFE4F0FF), const Color(0xFFE4F0FF),
const Color(0xFFF1F7FF).withOpacity(0.0), const Color(0xFFF1F7FF).withValues(alpha: 25.5),
], ],
), ),
), ),
@ -77,7 +79,7 @@ class MyPage extends StatelessWidget {
borderRadius: BorderRadius.circular(15.r), borderRadius: BorderRadius.circular(15.r),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.grey.withOpacity(0.1), color: Colors.grey.withValues(alpha: 25.5),
spreadRadius: 2, spreadRadius: 2,
blurRadius: 5, blurRadius: 5,
offset: const Offset(0, 3), offset: const Offset(0, 3),
@ -94,7 +96,7 @@ class MyPage extends StatelessWidget {
color: Colors.grey[200], color: Colors.grey[200],
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: Colors.grey.withOpacity(0.4), color: Colors.grey.withValues(alpha: 102),
width: 1.w, width: 1.w,
), ),
), ),
@ -136,8 +138,7 @@ class MyPage extends StatelessWidget {
_buildActionButton( _buildActionButton(
label: '修改密码', label: '修改密码',
onTap: () { onTap: () {
// TODO: Get.toNamed(AppRoutes.changePassword);
// Get.toNamed(AppRoutes.changePassword);
}, },
), ),
SizedBox(height: 15.h), SizedBox(height: 15.h),

4
lib/modules/problem/views/problem_page.dart

@ -3,8 +3,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:problem_check_system/modules/problem/controllers/problem_controller.dart'; import 'package:problem_check_system/modules/problem/controllers/problem_controller.dart';
import 'package:problem_check_system/data/models/problem_model.dart'; import 'package:problem_check_system/data/models/problem_model.dart';
import 'package:problem_check_system/shared/widgets/date_picker_button.dart'; import 'package:problem_check_system/modules/problem/views/widgets/date_picker_button.dart';
import 'package:problem_check_system/modules/problem/components/problem_card.dart'; import 'package:problem_check_system/modules/problem/views/widgets/problem_card.dart';
import 'package:problem_check_system/modules/problem/views/problem_form_page.dart'; import 'package:problem_check_system/modules/problem/views/problem_form_page.dart';
class ProblemPage extends StatelessWidget { class ProblemPage extends StatelessWidget {

2
lib/modules/problem/views/problem_upload_page.dart

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:problem_check_system/modules/problem/controllers/problem_upload_controller.dart'; import 'package:problem_check_system/modules/problem/controllers/problem_upload_controller.dart';
import 'package:problem_check_system/modules/problem/components/problem_card.dart'; import 'package:problem_check_system/modules/problem/views/widgets/problem_card.dart';
class ProblemUploadPage extends StatelessWidget { class ProblemUploadPage extends StatelessWidget {
ProblemUploadPage({super.key}); ProblemUploadPage({super.key});

0
lib/shared/widgets/custom_button.dart → lib/modules/problem/views/widgets/custom_button.dart

0
lib/shared/widgets/date_picker_button.dart → lib/modules/problem/views/widgets/date_picker_button.dart

2
lib/modules/problem/components/problem_card.dart → lib/modules/problem/views/widgets/problem_card.dart

@ -3,7 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:problem_check_system/data/models/problem_model.dart'; import 'package:problem_check_system/data/models/problem_model.dart';
import 'package:problem_check_system/shared/widgets/custom_button.dart'; import 'package:problem_check_system/modules/problem/views/widgets/custom_button.dart';
import 'package:problem_check_system/modules/problem/views/problem_form_page.dart'; import 'package:problem_check_system/modules/problem/views/problem_form_page.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart';

2
macos/Flutter/GeneratedPluginRegistrant.swift

@ -5,12 +5,14 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import connectivity_plus
import file_selector_macos import file_selector_macos
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
import sqflite_darwin import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

56
pubspec.lock

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.7.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -41,6 +49,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.19.1" version: "1.19.1"
connectivity_plus:
dependency: "direct main"
description:
name: connectivity_plus
sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.5"
connectivity_plus_platform_interface:
dependency: transitive
description:
name: connectivity_plus_platform_interface
sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
cross_file: cross_file:
dependency: transitive dependency: transitive
description: description:
@ -57,6 +81,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.6" version: "3.0.6"
dbus:
dependency: transitive
description:
name: dbus
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.11"
dio: dio:
dependency: "direct main" dependency: "direct main"
description: description:
@ -368,6 +400,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
nm:
dependency: transitive
description:
name: nm
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.0"
path: path:
dependency: "direct main" dependency: "direct main"
description: description:
@ -488,6 +528,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.1" version: "0.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -733,6 +781,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.6.1"
sdks: sdks:
dart: ">=3.8.1 <4.0.0" dart: ">=3.8.1 <4.0.0"
flutter: ">=3.29.0" flutter: ">=3.29.0"

1
pubspec.yaml

@ -7,6 +7,7 @@ environment:
sdk: ^3.8.1 sdk: ^3.8.1
dependencies: dependencies:
connectivity_plus: ^6.1.5
dio: ^5.9.0 dio: ^5.9.0
flutter: flutter:
sdk: flutter sdk: flutter

3
windows/flutter/generated_plugin_registrant.cc

@ -6,10 +6,13 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <file_selector_windows/file_selector_windows.h> #include <file_selector_windows/file_selector_windows.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
FileSelectorWindowsRegisterWithRegistrar( FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows")); registry->GetRegistrarForPlugin("FileSelectorWindows"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(

1
windows/flutter/generated_plugins.cmake

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
file_selector_windows file_selector_windows
permission_handler_windows permission_handler_windows
) )

Loading…
Cancel
Save