Commit 35fee5c6 authored by 张宏's avatar 张宏

111

parent cf1809a5
This diff is collapsed.
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# claude code # claude code
.claude/ .claude/
.trae/ .trae/
.idea/
.dart_tool/ .dart_tool/
build/ build/
......
This diff is collapsed.
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<library name="Flutter Plugins" type="FlutterPluginsLibraryType"> <library name="Flutter Plugins" type="FlutterPluginsLibraryType">
<CLASSES> <CLASSES>
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_usbcamera-0.0.1" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/share_plus-12.0.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_android-2.3.1" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_android-2.3.1" />
...@@ -14,22 +16,21 @@ ...@@ -14,22 +16,21 @@
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher-6.3.2" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher-6.3.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/jni_flutter-1.0.1" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/jni_flutter-1.0.1" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus-12.4.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_ios-6.4.1" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_ios-6.4.1" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider-2.1.5" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider-2.1.6" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/permission_handler-11.4.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/vibration-3.1.8" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences-2.5.5" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences-2.5.5" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.23" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.23" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/jni-1.0.0" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/jni-1.0.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.3+5" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4" /> <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/share_plus-12.0.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus-12.4.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/permission_handler-11.4.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.3+5" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/vibration-3.2.0" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
......
{ {
"APP_ENV": "dev", "APP_ENV": "dev",
"SERVICE_URL": "http://121.41.57.178:9090" "SERVICE_URL": "http://121.41.173.189/laki-merchant-service"
} }
{ {
"APP_ENV": "test", "APP_ENV": "test",
"SERVICE_URL": "http://localhost:8080" "SERVICE_URL": "http://121.41.173.189/laki-merchant-service"
} }
...@@ -27,11 +27,17 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> { ...@@ -27,11 +27,17 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(AuthLoading()); emit(AuthLoading());
try { try {
await _authService.login(event.username, event.password); // 新接口在登录响应中直接返回用户信息
final loginModel =
await _authService.login(event.phone, event.smsCode);
// 登录成功后获取用户信息 if (loginModel.user != null) {
emit(AuthSuccess(loginModel.user!));
} else {
// 如果登录响应中没有用户信息,则单独请求
final userInfo = await _authService.getUserInfo(); final userInfo = await _authService.getUserInfo();
emit(AuthSuccess(userInfo)); emit(AuthSuccess(userInfo));
}
} catch (e) { } catch (e) {
emit(AuthFailure(e.toString())); emit(AuthFailure(e.toString()));
} }
...@@ -45,6 +51,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> { ...@@ -45,6 +51,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
if (state is AuthTokenExpired || state is AuthLoggedOut) return; if (state is AuthTokenExpired || state is AuthLoggedOut) return;
await _storageService.deleteToken(); await _storageService.deleteToken();
await _storageService.deleteRefreshToken();
await _storageService.deleteUserInfo(); await _storageService.deleteUserInfo();
await _storageService.deleteClientId(); await _storageService.deleteClientId();
emit(const AuthTokenExpired()); emit(const AuthTokenExpired());
...@@ -60,6 +67,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> { ...@@ -60,6 +67,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
// 即使接口调用失败也继续执行本地登出 // 即使接口调用失败也继续执行本地登出
} }
await _storageService.deleteToken(); await _storageService.deleteToken();
await _storageService.deleteRefreshToken();
await _storageService.deleteUserInfo(); await _storageService.deleteUserInfo();
await _storageService.deleteClientId(); await _storageService.deleteClientId();
emit(const AuthLoggedOut()); emit(const AuthLoggedOut());
......
...@@ -8,16 +8,16 @@ abstract class AuthEvent extends Equatable { ...@@ -8,16 +8,16 @@ abstract class AuthEvent extends Equatable {
} }
class AuthLoginRequested extends AuthEvent { class AuthLoginRequested extends AuthEvent {
final String username; final String phone;
final String password; final String smsCode;
const AuthLoginRequested({ const AuthLoginRequested({
required this.username, required this.phone,
required this.password, required this.smsCode,
}); });
@override @override
List<Object?> get props => [username, password]; List<Object?> get props => [phone, smsCode];
} }
class AuthTokenExpiredEvent extends AuthEvent { class AuthTokenExpiredEvent extends AuthEvent {
......
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:laki_icu_app/models/bo/user_info_bo.dart'; import 'package:laki_icu_app/models/bo/user_model.dart';
abstract class AuthState extends Equatable { abstract class AuthState extends Equatable {
const AuthState(); const AuthState();
...@@ -13,7 +13,7 @@ class AuthInitial extends AuthState {} ...@@ -13,7 +13,7 @@ class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {} class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState { class AuthSuccess extends AuthState {
final UserInfoBO userInfo; final UserModel userInfo;
const AuthSuccess(this.userInfo); const AuthSuccess(this.userInfo);
......
import 'package:equatable/equatable.dart';
import 'user_model.dart';
class LoginModel extends Equatable {
final String? accessToken;
final String? refreshToken;
final UserModel? user;
const LoginModel({
this.accessToken,
this.refreshToken,
this.user,
});
factory LoginModel.fromJson(Map<String, dynamic> json) {
return LoginModel(
accessToken: json['accessToken'] as String?,
refreshToken: json['refreshToken'] as String?,
user: UserModel.fromJson(json),
);
}
@override
List<Object?> get props => [accessToken, refreshToken, user];
}
import 'package:equatable/equatable.dart';
class UserModel extends Equatable {
final int id;
final String? nickname;
final String? phone;
final String? avatar;
final int? type;
final dynamic canControlDevice;
final dynamic canViewOperation;
final dynamic hospitalId;
final String? hospitalName;
const UserModel({
required this.id,
this.nickname,
this.phone,
this.avatar,
this.type,
this.canControlDevice,
this.canViewOperation,
this.hospitalId,
this.hospitalName,
});
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'] as int? ?? 0,
nickname: json['nickname'] as String?,
phone: json['phone'] as String?,
avatar: json['avatar'] as String?,
type: json['type'] as int?,
canControlDevice: json['canControlDevice'],
canViewOperation: json['canViewOperation'],
hospitalId: json['hospitalId'],
hospitalName: json['hospitalName'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'nickname': nickname,
'phone': phone,
'avatar': avatar,
'type': type,
'canControlDevice': canControlDevice,
'canViewOperation': canViewOperation,
'hospitalId': hospitalId,
'hospitalName': hospitalName,
};
}
@override
List<Object?> get props => [
id,
nickname,
phone,
avatar,
type,
canControlDevice,
canViewOperation,
hospitalId,
hospitalName,
];
}
import '../utils/constants.dart'; import '../utils/constants.dart';
import '../utils/http/response_model.dart'; import '../utils/http/response_model.dart';
import '../utils/http/dio_request.dart'; import '../utils/http/dio_request.dart';
import '../models/bo/login_bo.dart'; import '../models/bo/login_model.dart';
import '../models/bo/user_info_bo.dart'; import '../models/bo/user_model.dart';
import 'mock/auth_mock_data.dart'; import 'mock/auth_mock_data.dart';
class AuthRepository { class AuthRepository {
Future<ResponseModel<LoginBO>> login(Map<String, dynamic> params) { Future<ResponseModel<LoginModel>> login(
String phone, String smsCode) {
if (Constants.useMockData) { if (Constants.useMockData) {
return _mockLogin(); return _mockLogin();
} }
return DioRequest.instance.post<LoginBO>( return DioRequest.instance.post<LoginModel>(
'/app/auth/login/password', '/merchant/account/sms-login',
data: params, data: {'phone': phone, 'smsCode': smsCode},
fromJsonT: (data) => LoginBO.fromJson(data as Map<String, dynamic>), fromJsonT: (data) => LoginModel.fromJson(data as Map<String, dynamic>),
); );
} }
Future<ResponseModel<UserInfoBO>> getUserInfo() { Future<ResponseModel<UserModel>> getUserInfo() {
if (Constants.useMockData) { if (Constants.useMockData) {
return _mockGetUserInfo(); return _mockGetUserInfo();
} }
return DioRequest.instance.get<UserInfoBO>( return DioRequest.instance.get<UserModel>(
'/app/auth/user-info', '/app/auth/user-info',
fromJsonT: (data) => UserInfoBO.fromJson(data as Map<String, dynamic>), fromJsonT: (data) => UserModel.fromJson(data as Map<String, dynamic>),
); );
} }
...@@ -36,26 +37,26 @@ class AuthRepository { ...@@ -36,26 +37,26 @@ class AuthRepository {
// ==================== Mock 实现 ==================== // ==================== Mock 实现 ====================
Future<ResponseModel<LoginBO>> _mockLogin() async { Future<ResponseModel<LoginModel>> _mockLogin() async {
// 模拟网络延迟,便于测试 loading 状态 // 模拟网络延迟,便于测试 loading 状态
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
final loginBO = AuthMockData.mockLogin(); final loginModel = AuthMockData.mockLogin();
return ResponseModel<LoginBO>( return ResponseModel<LoginModel>(
code: 200, code: 200,
msg: '登录成功(mock)', msg: '登录成功(mock)',
data: loginBO, data: loginModel,
uuid: 'mock_uuid_${DateTime.now().millisecondsSinceEpoch}', uuid: 'mock_uuid_${DateTime.now().millisecondsSinceEpoch}',
success: true, success: true,
timestamp: DateTime.now().millisecondsSinceEpoch, timestamp: DateTime.now().millisecondsSinceEpoch,
); );
} }
Future<ResponseModel<UserInfoBO>> _mockGetUserInfo() async { Future<ResponseModel<UserModel>> _mockGetUserInfo() async {
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
final userInfo = AuthMockData.mockUserInfo(); final userInfo = AuthMockData.mockUserInfo();
return ResponseModel<UserInfoBO>( return ResponseModel<UserModel>(
code: 200, code: 200,
msg: '获取用户信息成功(mock)', msg: '获取用户信息成功(mock)',
data: userInfo, data: userInfo,
......
import '../../models/bo/login_bo.dart'; import '../../models/bo/login_model.dart';
import '../../models/bo/user_info_bo.dart'; import '../../models/bo/user_model.dart';
/// Auth 模块本地 mock 数据。 /// Auth 模块本地 mock 数据。
/// ///
...@@ -9,31 +9,24 @@ import '../../models/bo/user_info_bo.dart'; ...@@ -9,31 +9,24 @@ import '../../models/bo/user_info_bo.dart';
class AuthMockData { class AuthMockData {
AuthMockData._(); AuthMockData._();
/// Mock 登录响应 - 直接构造 LoginBO 实例 /// Mock 登录响应 - 直接构造 LoginModel 实例
static LoginBO mockLogin() { static LoginModel mockLogin() {
return const LoginBO( return LoginModel(
scope: 'server',
openid: 'mock_openid_abc123',
accessToken: 'mock_access_token_eyJhbGciOiJIUzI1NiJ9', accessToken: 'mock_access_token_eyJhbGciOiJIUzI1NiJ9',
refreshToken: 'mock_refresh_token_xyz789', refreshToken: 'mock_refresh_token_xyz789',
expireIn: 86400, user: mockUserInfo(),
refreshExpireIn: 604800,
clientId: 'mock_client_id_001',
); );
} }
/// Mock 用户信息响应 - 直接构造 UserInfoBO 实例 /// Mock 用户信息响应 - 直接构造 UserModel 实例
static UserInfoBO mockUserInfo() { static UserModel mockUserInfo() {
return const UserInfoBO( return const UserModel(
userId: 10001, id: 1,
userName: 'admin', nickname: '张老师',
nickName: '管理员', phone: '138****0001',
phonenumber: '13800138000', avatar:
email: 'admin@laki-icu.com', 'https://qi-ai.oss-cn-hangzhou.aliyuncs.com/upload/2026/05/30/0f79ec34-ae2e-462b-a80e-2e8d46ebc145.jpg',
sex: '1', type: 1,
avatarUrl: 'https://qialg.com/avatar/default.png',
deptName: '技术部',
tenantId: 'tenant_001',
); );
} }
} }
import '../models/bo/login_bo.dart'; import '../models/bo/login_model.dart';
import '../models/bo/user_info_bo.dart'; import '../models/bo/user_model.dart';
import '../repositories/auth_repository.dart'; import '../repositories/auth_repository.dart';
import '../utils/constants.dart'; import '../utils/constants.dart';
import '../utils/storage/storage_service.dart'; import '../utils/storage/storage_service.dart';
...@@ -14,29 +14,31 @@ class AuthService { ...@@ -14,29 +14,31 @@ class AuthService {
}) : _authRepository = authRepository, }) : _authRepository = authRepository,
_storageService = storageService; _storageService = storageService;
Future<LoginBO> login(String username, String password) async { Future<LoginModel> login(String phone, String smsCode) async {
final result = await _authRepository.login({ final result = await _authRepository.login(phone, smsCode);
'username': username,
'password': password,
});
if (result.success && result.data != null) { if (result.success && result.data != null) {
final loginBO = result.data!; final loginModel = result.data!;
if (loginBO.accessToken != null && loginBO.accessToken!.isNotEmpty) { if (loginModel.accessToken != null &&
loginModel.accessToken!.isNotEmpty) {
await _storageService.saveToken( await _storageService.saveToken(
loginBO.accessToken!, loginModel.accessToken!,
expiryHours: Constants.tokenExpiryHours, expiryHours: Constants.tokenExpiryHours,
); );
} }
if (loginBO.clientId != null && loginBO.clientId!.isNotEmpty) { if (loginModel.refreshToken != null &&
await _storageService.saveClientId(loginBO.clientId!); loginModel.refreshToken!.isNotEmpty) {
await _storageService.saveRefreshToken(loginModel.refreshToken!);
} }
return loginBO; if (loginModel.user != null) {
await _storageService.saveUserInfo(loginModel.user!);
}
return loginModel;
} }
throw Exception(result.msg); throw Exception(result.msg);
} }
Future<UserInfoBO> getUserInfo() async { Future<UserModel> getUserInfo() async {
final result = await _authRepository.getUserInfo(); final result = await _authRepository.getUserInfo();
if (result.success && result.data != null) { if (result.success && result.data != null) {
final userInfo = result.data!; final userInfo = result.data!;
...@@ -46,7 +48,7 @@ class AuthService { ...@@ -46,7 +48,7 @@ class AuthService {
throw Exception(result.msg); throw Exception(result.msg);
} }
Future<UserInfoBO?> getStoredUserInfo() async { Future<UserModel?> getStoredUserInfo() async {
return _storageService.getUserInfo(); return _storageService.getUserInfo();
} }
......
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:laki_icu_app/models/bo/user_info_bo.dart'; import 'package:laki_icu_app/models/bo/user_model.dart';
class StorageService { class StorageService {
static const String _keyToken = 'auth_token'; static const String _keyToken = 'auth_token';
static const String _keyTokenExpiry = 'auth_token_expiry'; static const String _keyTokenExpiry = 'auth_token_expiry';
static const String _keyRememberUsername = 'remember_username'; static const String _keyRefreshToken = 'auth_refresh_token';
static const String _keyRememberPassword = 'remember_password'; static const String _keyRememberPhone = 'remember_phone';
static const String _keyRememberSmsCode = 'remember_sms_code';
static const String _keyRememberEnabled = 'remember_enabled'; static const String _keyRememberEnabled = 'remember_enabled';
static const String _keyUserInfo = 'user_info'; static const String _keyUserInfo = 'user_info';
static const String _keyClientId = 'client_id'; static const String _keyClientId = 'client_id';
...@@ -51,29 +52,43 @@ class StorageService { ...@@ -51,29 +52,43 @@ class StorageService {
return token != null && token.isNotEmpty; return token != null && token.isNotEmpty;
} }
// ==================== RefreshToken 相关 ====================
Future<void> saveRefreshToken(String refreshToken) async {
await _storage.write(key: _keyRefreshToken, value: refreshToken);
}
Future<String?> getRefreshToken() async {
return await _storage.read(key: _keyRefreshToken);
}
Future<void> deleteRefreshToken() async {
await _storage.delete(key: _keyRefreshToken);
}
// ==================== 用户信息相关 ==================== // ==================== 用户信息相关 ====================
Future<void> saveUserInfo(UserInfoBO userInfo) async { Future<void> saveUserInfo(UserModel userInfo) async {
final jsonStr = final jsonStr =
'${userInfo.userId}|${userInfo.userName}|${userInfo.nickName}|${userInfo.phonenumber}|${userInfo.email}|${userInfo.sex}|${userInfo.avatarUrl}|${userInfo.deptName}|${userInfo.tenantId}'; '${userInfo.id}|${userInfo.nickname ?? ''}|${userInfo.phone ?? ''}|${userInfo.avatar ?? ''}|${userInfo.type ?? ''}|${userInfo.canControlDevice ?? ''}|${userInfo.canViewOperation ?? ''}|${userInfo.hospitalId ?? ''}|${userInfo.hospitalName ?? ''}';
await _storage.write(key: _keyUserInfo, value: jsonStr); await _storage.write(key: _keyUserInfo, value: jsonStr);
} }
Future<UserInfoBO?> getUserInfo() async { Future<UserModel?> getUserInfo() async {
final value = await _storage.read(key: _keyUserInfo); final value = await _storage.read(key: _keyUserInfo);
if (value == null || value.isEmpty) return null; if (value == null || value.isEmpty) return null;
final parts = value.split('|'); final parts = value.split('|');
if (parts.length < 9) return null; if (parts.length < 9) return null;
return UserInfoBO( return UserModel(
userId: int.tryParse(parts[0]) ?? 0, id: int.tryParse(parts[0]) ?? 0,
userName: parts[1], nickname: parts[1].isEmpty ? null : parts[1],
nickName: parts[2], phone: parts[2].isEmpty ? null : parts[2],
phonenumber: parts[3], avatar: parts[3].isEmpty ? null : parts[3],
email: parts[4], type: parts[4].isEmpty ? null : int.tryParse(parts[4]),
sex: parts[5], canControlDevice: parts[5].isEmpty ? null : parts[5],
avatarUrl: parts[6], canViewOperation: parts[6].isEmpty ? null : parts[6],
deptName: parts[7], hospitalId: parts[7].isEmpty ? null : parts[7],
tenantId: parts[8], hospitalName: parts[8].isEmpty ? null : parts[8],
); );
} }
...@@ -98,27 +113,27 @@ class StorageService { ...@@ -98,27 +113,27 @@ class StorageService {
// ==================== 记住密码相关 ==================== // ==================== 记住密码相关 ====================
Future<void> saveRememberCredentials({ Future<void> saveRememberCredentials({
required String username, required String phone,
required String password, required String smsCode,
}) async { }) async {
await _storage.write(key: _keyRememberUsername, value: username); await _storage.write(key: _keyRememberPhone, value: phone);
await _storage.write(key: _keyRememberPassword, value: password); await _storage.write(key: _keyRememberSmsCode, value: smsCode);
await _storage.write(key: _keyRememberEnabled, value: 'true'); await _storage.write(key: _keyRememberEnabled, value: 'true');
} }
Future<Map<String, String?>> getRememberCredentials() async { Future<Map<String, String?>> getRememberCredentials() async {
final enabled = await _storage.read(key: _keyRememberEnabled); final enabled = await _storage.read(key: _keyRememberEnabled);
if (enabled != 'true') { if (enabled != 'true') {
return {'username': null, 'password': null}; return {'phone': null, 'smsCode': null};
} }
final username = await _storage.read(key: _keyRememberUsername); final phone = await _storage.read(key: _keyRememberPhone);
final password = await _storage.read(key: _keyRememberPassword); final smsCode = await _storage.read(key: _keyRememberSmsCode);
return {'username': username, 'password': password}; return {'phone': phone, 'smsCode': smsCode};
} }
Future<void> clearRememberCredentials() async { Future<void> clearRememberCredentials() async {
await _storage.delete(key: _keyRememberUsername); await _storage.delete(key: _keyRememberPhone);
await _storage.delete(key: _keyRememberPassword); await _storage.delete(key: _keyRememberSmsCode);
await _storage.delete(key: _keyRememberEnabled); await _storage.delete(key: _keyRememberEnabled);
} }
......
...@@ -175,11 +175,13 @@ class _HomeIndexContentState extends State<HomeIndexContent> { ...@@ -175,11 +175,13 @@ class _HomeIndexContentState extends State<HomeIndexContent> {
// 监控画面模块(2/3宽度、100%高度) // 监控画面模块(2/3宽度、100%高度)
Expanded( Expanded(
flex: 2, flex: 2,
child: MonitoringScreen( child: Text("1234")
onRefresh: () => _homeIndexCubit.refreshData(),
onSnapshot: () {}, // MonitoringScreen(
onRecord: () {}, // onRefresh: () => _homeIndexCubit.refreshData(),
), // onSnapshot: () {},
// onRecord: () {},
// ),
), ),
SizedBox(width: 24.w), SizedBox(width: 24.w),
// 右侧(1/3宽度):患者信息卡片 + 告警信息卡片 // 右侧(1/3宽度):患者信息卡片 + 告警信息卡片
......
...@@ -38,33 +38,33 @@ class LoginCubit extends Cubit<LoginState> { ...@@ -38,33 +38,33 @@ class LoginCubit extends Cubit<LoginState> {
} }
void login({ void login({
required String username, required String phone,
required String password, required String smsCode,
bool rememberPassword = false, bool rememberPassword = false,
}) { }) {
if (rememberPassword) { if (rememberPassword) {
storageService.saveRememberCredentials( storageService.saveRememberCredentials(
username: username, phone: phone,
password: password, smsCode: smsCode,
); );
} else { } else {
storageService.clearRememberCredentials(); storageService.clearRememberCredentials();
} }
authBloc.add(AuthLoginRequested( authBloc.add(AuthLoginRequested(
username: username, phone: phone,
password: password, smsCode: smsCode,
)); ));
} }
Future<void> loadRememberCredentials() async { Future<void> loadRememberCredentials() async {
final credentials = await storageService.getRememberCredentials(); final credentials = await storageService.getRememberCredentials();
if (isClosed) return; if (isClosed) return;
if (credentials['username'] != null) { if (credentials['phone'] != null) {
emit(state.copyWith( emit(state.copyWith(
rememberPassword: true, rememberPassword: true,
savedUsername: credentials['username'], savedPhone: credentials['phone'],
savedPassword: credentials['password'], savedSmsCode: credentials['smsCode'],
)); ));
} }
} }
......
...@@ -4,30 +4,30 @@ class LoginState extends Equatable { ...@@ -4,30 +4,30 @@ class LoginState extends Equatable {
final bool rememberPassword; final bool rememberPassword;
final bool isLoading; final bool isLoading;
final String? error; final String? error;
final String? savedUsername; final String? savedPhone;
final String? savedPassword; final String? savedSmsCode;
const LoginState({ const LoginState({
this.rememberPassword = false, this.rememberPassword = false,
this.isLoading = false, this.isLoading = false,
this.error, this.error,
this.savedUsername, this.savedPhone,
this.savedPassword, this.savedSmsCode,
}); });
LoginState copyWith({ LoginState copyWith({
bool? rememberPassword, bool? rememberPassword,
bool? isLoading, bool? isLoading,
String? error, String? error,
String? savedUsername, String? savedPhone,
String? savedPassword, String? savedSmsCode,
}) { }) {
return LoginState( return LoginState(
rememberPassword: rememberPassword ?? this.rememberPassword, rememberPassword: rememberPassword ?? this.rememberPassword,
isLoading: isLoading ?? this.isLoading, isLoading: isLoading ?? this.isLoading,
error: error, error: error,
savedUsername: savedUsername ?? this.savedUsername, savedPhone: savedPhone ?? this.savedPhone,
savedPassword: savedPassword ?? this.savedPassword, savedSmsCode: savedSmsCode ?? this.savedSmsCode,
); );
} }
...@@ -36,7 +36,7 @@ class LoginState extends Equatable { ...@@ -36,7 +36,7 @@ class LoginState extends Equatable {
rememberPassword, rememberPassword,
isLoading, isLoading,
error, error,
savedUsername, savedPhone,
savedPassword, savedSmsCode,
]; ];
} }
...@@ -19,8 +19,8 @@ class LoginView extends StatelessWidget { ...@@ -19,8 +19,8 @@ class LoginView extends StatelessWidget {
LoginView({super.key}); LoginView({super.key});
final _frmGlobalKey = GlobalKey<FormState>(); final _frmGlobalKey = GlobalKey<FormState>();
final _txtUserNameController = TextEditingController(); final _txtPhoneController = TextEditingController();
final _txtPwdController = TextEditingController(); final _txtSmsCodeController = TextEditingController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -64,11 +64,11 @@ class LoginView extends StatelessWidget { ...@@ -64,11 +64,11 @@ class LoginView extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
final cubit = context.read<LoginCubit>(); final cubit = context.read<LoginCubit>();
if (state.savedUsername != null) { if (state.savedPhone != null) {
_txtUserNameController.text = state.savedUsername!; _txtPhoneController.text = state.savedPhone!;
} }
if (state.savedPassword != null) { if (state.savedSmsCode != null) {
_txtPwdController.text = state.savedPassword!; _txtSmsCodeController.text = state.savedSmsCode!;
} }
return Column( return Column(
...@@ -126,11 +126,11 @@ class LoginView extends StatelessWidget { ...@@ -126,11 +126,11 @@ class LoginView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
UsernameField( UsernameField(
controller: _txtUserNameController, controller: _txtPhoneController,
), ),
SizedBox(height: 20.h), SizedBox(height: 20.h),
PasswordField( PasswordField(
controller: _txtPwdController, controller: _txtSmsCodeController,
), ),
SizedBox(height: 30.h), SizedBox(height: 30.h),
RememberPasswordRow( RememberPasswordRow(
...@@ -162,10 +162,10 @@ class LoginView extends StatelessWidget { ...@@ -162,10 +162,10 @@ class LoginView extends StatelessWidget {
if (_frmGlobalKey.currentState! if (_frmGlobalKey.currentState!
.validate()) { .validate()) {
cubit.login( cubit.login(
username: _txtUserNameController.text phone: _txtPhoneController.text
.trim(), .trim(),
password: smsCode:
_txtPwdController.text.trim(), _txtSmsCodeController.text.trim(),
rememberPassword: rememberPassword:
state.rememberPassword, state.rememberPassword,
); );
......
...@@ -7,12 +7,16 @@ ...@@ -7,12 +7,16 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin");
flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
flutter_secure_storage_linux flutter_secure_storage_linux
flutter_webrtc
url_launcher_linux url_launcher_linux
) )
......
...@@ -7,6 +7,7 @@ import Foundation ...@@ -7,6 +7,7 @@ import Foundation
import device_info_plus import device_info_plus
import flutter_secure_storage_macos import flutter_secure_storage_macos
import flutter_webrtc
import share_plus import share_plus
import shared_preferences_foundation import shared_preferences_foundation
import url_launcher_macos import url_launcher_macos
...@@ -14,6 +15,7 @@ import url_launcher_macos ...@@ -14,6 +15,7 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
......
...@@ -52,6 +52,7 @@ dependencies: ...@@ -52,6 +52,7 @@ dependencies:
permission_handler: ^11.3.1 permission_handler: ^11.3.1
flutter_usbcamera: ^0.0.1 flutter_usbcamera: ^0.0.1
path_provider: ^2.1.2 path_provider: ^2.1.2
flutter_webrtc: 1.4.1
# flutter_usbcamera: ^0.0.1 # flutter_usbcamera: ^0.0.1
# fl_chart: ^0.71.0 # fl_chart: ^0.71.0
# fl_chart: ^1.1.0 # fl_chart: ^1.1.0
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h> #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h> #include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
...@@ -14,6 +15,8 @@ ...@@ -14,6 +15,8 @@
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FlutterSecureStorageWindowsPluginRegisterWithRegistrar( FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
FlutterWebRTCPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterWebRTCPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar( SharePlusWindowsPluginCApiRegisterWithRegistrar(
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
flutter_secure_storage_windows flutter_secure_storage_windows
flutter_webrtc
permission_handler_windows permission_handler_windows
share_plus share_plus
url_launcher_windows url_launcher_windows
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment