...
 
Commits (2)
    https://gitcode.net/O2OA/o2oa-flutter/-/commit/043d7ea73dd76320c0968a6fe2c5905375b5c1bc 注册功能 2024-05-11T15:01:39+08:00 fancy fancylou@outlook.com https://gitcode.net/O2OA/o2oa-flutter/-/commit/8e95f7d0612b224178ed84e908f015ce99c59c86 注册多语言文件 2024-05-11T15:10:29+08:00 fancy fancylou@outlook.com
import 'dart:io';
import 'package:get/get.dart';
......@@ -14,28 +10,107 @@ import '../utils/index.dart';
///组织人员服务
///
class OrganizationPersonalService extends GetxService {
static OrganizationPersonalService get to => Get.find();
//
String baseUrl() {
return O2ApiManager.instance.getModuleBaseUrl(
O2DistributeModuleEnum.x_organization_assemble_personal) ?? '';
O2DistributeModuleEnum.x_organization_assemble_personal) ??
'';
}
/// 注册配置
///
/// @return value = disable 没有启用注册 ; value = captcha 验证码注册 ; value = code 短信验证注册
Future<ValueStringData?> registerMode() async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/regist/mode');
return ValueStringData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('注册配置获取失败', err, stackTrace);
}
return null;
}
///
///获取图片验证码
///
Future<CaptchaImgData?> getRegisterCaptchaImgData(int width, int height) async {
try {
ApiResponse response = await O2HttpClient.instance.get('${baseUrl()}jaxrs/regist/captcha/width/$width/height/$height', needToken: false);
CaptchaImgData mode = CaptchaImgData.fromJson(response.data);
return mode;
} catch (err, stackTrace) {
OLogger.e('获取图片验证码失败', err, stackTrace);
}
return null;
}
/// 发送注册短信
Future<ValueBoolData?> getRegisterCode(String mobile) async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/regist/code/mobile/$mobile');
return ValueBoolData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('注册获取失败', err, stackTrace);
}
return null;
}
/// 用户名是否已经注册
Future<ValueBoolData?> checkRegisterUserName(String username) async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/regist/check/name/$username');
return ValueBoolData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('用户名是否已经注册失败', err, stackTrace);
}
return null;
}
/// 手机号码是否已经注册
Future<ValueBoolData?> checkRegisterMobile(String mobile) async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/regist/check/mobile/$mobile');
return ValueBoolData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('手机号码是否已经注册失败', err, stackTrace);
}
return null;
}
///
/// 注册人员
///
Future<ValueBoolData?> register(Map<String, String> form) async {
try {
ApiResponse response = await O2HttpClient.instance
.post('${baseUrl()}jaxrs/regist', form);
return ValueBoolData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('注册人员失败', err, stackTrace);
}
return null;
}
///
/// 会议管理的配置文件
///
///
Future<MeetingConfigModel?> meetingConfig() async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/definition/meetingConfig');
if (response.data != null && response.data is String) {
SharedPreferenceService.to.putString(SharedPreferenceService.meetingConfigKey, response.data);
return MeetingConfigModel.fromJson(O2Utils.parseStringToJson(response.data));
SharedPreferenceService.to
.putString(SharedPreferenceService.meetingConfigKey, response.data);
return MeetingConfigModel.fromJson(
O2Utils.parseStringToJson(response.data));
}
} catch (err, stackTrace) {
OLogger.e(' 会议管理的配置文件获取失败', err, stackTrace);
......@@ -45,11 +120,11 @@ class OrganizationPersonalService extends GetxService {
///
/// 获取当前用户信息
///
///
Future<O2Person?> person() async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/person');
ApiResponse response =
await O2HttpClient.instance.get('${baseUrl()}jaxrs/person');
O2Person idData = O2Person.fromJson(response.data);
return idData;
} catch (err, stackTrace) {
......@@ -78,7 +153,8 @@ class OrganizationPersonalService extends GetxService {
///
Future<ValueBoolData?> updateAvatar(File file) async {
try {
ApiResponse response = await O2HttpClient.instance.putUploadFile('${baseUrl()}jaxrs/person/icon', file);
ApiResponse response = await O2HttpClient.instance
.putUploadFile('${baseUrl()}jaxrs/person/icon', file);
ValueBoolData valueBoolData = ValueBoolData.fromJson(response.data);
return valueBoolData;
} catch (err, stackTrace) {
......@@ -90,7 +166,8 @@ class OrganizationPersonalService extends GetxService {
///
/// 登录
///
Future<ValueBoolData?> updateLoginPassword(UpdateLoginPasswordForm form) async {
Future<ValueBoolData?> updateLoginPassword(
UpdateLoginPasswordForm form) async {
try {
ApiResponse response = await O2HttpClient.instance
.put('${baseUrl()}jaxrs/person/password', form.toJson());
......@@ -104,11 +181,11 @@ class OrganizationPersonalService extends GetxService {
///
/// 获取个性化数据
///
///
Future<String?> getMyCustomData(String name) async {
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/custom/$name');
try {
ApiResponse response =
await O2HttpClient.instance.get('${baseUrl()}jaxrs/custom/$name');
if (response.data != null && response.data is String) {
return response.data;
}
......@@ -120,9 +197,10 @@ class OrganizationPersonalService extends GetxService {
///
/// 保存个性化数据
///
Future<IdData?> saveMyCustomData(String name, Map<String, dynamic> data) async {
try {
///
Future<IdData?> saveMyCustomData(
String name, Map<String, dynamic> data) async {
try {
ApiResponse response = await O2HttpClient.instance
.put('${baseUrl()}jaxrs/custom/$name', data);
IdData idData = IdData.fromJson(response.data);
......@@ -135,8 +213,9 @@ class OrganizationPersonalService extends GetxService {
/// 我的委托
Future<List<EmpowerData>?> myEmpowerList() async {
try {
ApiResponse response = await O2HttpClient.instance.get('${baseUrl()}jaxrs/empower/list/currentperson');
try {
ApiResponse response = await O2HttpClient.instance
.get('${baseUrl()}jaxrs/empower/list/currentperson');
final list = response.data == null ? [] : response.data as List;
return list.map((group) => EmpowerData.fromJson(group)).toList();
} catch (err, stackTrace) {
......@@ -144,10 +223,12 @@ class OrganizationPersonalService extends GetxService {
}
return null;
}
/// 收到的委托
Future<List<EmpowerData>?> empowerToMeList() async {
try {
ApiResponse response = await O2HttpClient.instance.get('${baseUrl()}jaxrs/empower/list/to');
try {
ApiResponse response =
await O2HttpClient.instance.get('${baseUrl()}jaxrs/empower/list/to');
final list = response.data == null ? [] : response.data as List;
return list.map((group) => EmpowerData.fromJson(group)).toList();
} catch (err, stackTrace) {
......@@ -155,24 +236,28 @@ class OrganizationPersonalService extends GetxService {
}
return null;
}
/// 删除委托
Future<ValueBoolData?> empowerDelete(String id) async {
try {
ApiResponse response = await O2HttpClient.instance.delete('${baseUrl()}jaxrs/empower/$id');
try {
ApiResponse response =
await O2HttpClient.instance.delete('${baseUrl()}jaxrs/empower/$id');
return ValueBoolData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('删除委托失败', err, stackTrace);
}
return null;
}
/// 创建委托
Future<IdData?> empowerCreate(EmpowerData body) async {
try {
ApiResponse response = await O2HttpClient.instance.post('${baseUrl()}jaxrs/empower', body.toJson());
try {
ApiResponse response = await O2HttpClient.instance
.post('${baseUrl()}jaxrs/empower', body.toJson());
return IdData.fromJson(response.data);
} catch (err, stackTrace) {
OLogger.e('创建委托失败', err, stackTrace);
}
return null;
}
}
\ No newline at end of file
}
......@@ -682,4 +682,15 @@ const Map<String, String> en_US = {
'account_safe_gesture_unlock_error_setup_not_match': 'The passwords entered twice are inconsistent',
'account_safe_gesture_unlock_error_check_pwd': 'Password error, please re-enter',
'account_safe_gesture_unlock_toast_success': 'Password set successfully!',
'login_to_register': 'Go register',
'register': 'register',
'register_to_login': 'Go log in',
'register_success_to_login': 'Registration successful, please log in!',
'login_form_register_user_name': 'user name',
'login_form_user_password_repeat': 'Confirm password',
'login_form_user_password_repeat_not_empty': 'Confirm password cannot be empty',
'login_form_user_password_repeat_not_equals': 'The passwords entered twice are inconsistent',
'login_form_register_phone': 'mobile phone',
'login_form_register_phone_not_empty': 'Mobile phone number cannot be empty',
'login_form_register_email': 'mailbox',
};
......@@ -682,4 +682,15 @@ const Map<String, String> es_ES = {
'account_safe_gesture_unlock_error_setup_not_match': 'La contraseña introducida dos veces es inconsistente',
'account_safe_gesture_unlock_error_check_pwd': 'Contraseña incorrecta, vuelva a ingresar',
'account_safe_gesture_unlock_toast_success': '¡La configuración de la contraseña fue exitosa!',
'login_to_register': 'Ir a registrarse',
'register': 'Registro',
'register_to_login': 'Ir a iniciar sesión',
'register_success_to_login': '¡El registro fue exitoso, ¡ por favor, inicie sesión!',
'login_form_register_user_name': 'Nombre de usuario',
'login_form_user_password_repeat': 'Confirmar contraseña',
'login_form_user_password_repeat_not_empty': 'La contraseña de confirmación no puede estar vacía',
'login_form_user_password_repeat_not_equals': 'La contraseña introducida dos veces es inconsistente',
'login_form_register_phone': 'Teléfono móvil',
'login_form_register_phone_not_empty': 'El número de teléfono móvil no puede estar vacío',
'login_form_register_email': 'Buzón',
};
......@@ -682,4 +682,15 @@ const Map<String, String> zh_HK = {
'account_safe_gesture_unlock_error_setup_not_match': '兩次輸入的密碼不一致',
'account_safe_gesture_unlock_error_check_pwd': '密碼錯誤,請重新輸入',
'account_safe_gesture_unlock_toast_success': '密碼設定成功!',
'login_to_register': '去注册',
'register': '注册',
'register_to_login': '去登入',
'register_success_to_login': '注册成功,請登入!',
'login_form_register_user_name': '用戶名',
'login_form_user_password_repeat': '確認密碼',
'login_form_user_password_repeat_not_empty': '確認密碼不能為空',
'login_form_user_password_repeat_not_equals': '兩次輸入的密碼不一致',
'login_form_register_phone': '手機',
'login_form_register_phone_not_empty': '手機號碼不能為空',
'login_form_register_email': '郵箱',
};
......@@ -104,10 +104,21 @@ const Map<String, String> zh_Hans = {
// login
'login': '登录',
'login_to_register': '去注册',
'register': '注册',
'register_to_login': '去登录',
'register_success_to_login': '注册成功,请登录!',
'login_form_user_name': '用户名或手机号码',
'login_form_register_user_name': '用户名',
'login_form_user_name_not_empty': '用户名不能为空',
'login_form_user_password': '密码',
'login_form_user_password_not_empty': '密码不能为空',
'login_form_user_password_repeat': '确认密码',
'login_form_user_password_repeat_not_empty': '确认密码不能为空',
'login_form_user_password_repeat_not_equals': '两次输入的密码不一致',
'login_form_register_phone': '手机',
'login_form_register_phone_not_empty': '手机号码不能为空',
'login_form_register_email': '邮箱',
'login_form_user_code': '验证码',
'login_form_user_code_not_empty': '验证码不能为空',
'login_form_code_btn_send': '发送验证码',
......
......@@ -5,6 +5,7 @@ export './o2_app_update_info.dart';
export './echo_data.dart';
export './jpush_device.dart';
export './value_data_bool.dart';
export './value_data_string.dart';
export './id_data.dart';
export './o2_api_response.dart';
export './server/index.dart';
......
class ValueStringData {
String? value;
ValueStringData({this.value});
ValueStringData.fromJson(Map<String, dynamic> jsonMap) {
value = jsonMap['value'];
}
Map<String, dynamic> toJson() => {
"value": value,
};
}
\ No newline at end of file
......@@ -72,6 +72,7 @@ import '../../pages/home/settings/my_profile/index.dart';
import '../../pages/home/settings/settings_common/index.dart';
import '../../pages/home/settings/skin/index.dart';
import '../../pages/login/index.dart';
import '../../pages/login/register/index.dart';
import '../../pages/login/server_info/index.dart';
import '../../pages/splash/index.dart';
import 'routes.dart';
......@@ -90,6 +91,10 @@ class O2OAPages {
name: O2OARoutes.bind,
page: () => const BindPage(),
binding: BindBinding()),
GetPage(
name: O2OARoutes.register,
page: () => const RegisterPage(),
binding: RegisterBinding()),
GetPage(
name: O2OARoutes.login,
page: () => const LoginPage(),
......
......@@ -47,6 +47,7 @@ class O2OARoutes {
static const String login = '/login'; // 登录页面
static const String loginServerInfo = '/login/server/info'; // 服务器信息配置
static const String register = '/register'; // 注册页面
static const String demoLogin = '/login/demo'; // 演示版本登录
static const String processWebview = '/process/webview'; // webview页面
......
......@@ -18,6 +18,11 @@ class O2 {
// 隐私政策 地址
static const String privacyPolicyUrl = 'https://www.o2oa.net/secret.html';
/// 注册模式
static const String registerModeDisable = 'disable';
static const String registerModeCaptcha= 'captcha';
static const String registerModeCode= 'code';
// 极光推送appKey
static const String jPushAppKey = "9aca7cc20fe0cc987cd913ca";
static const String jPushAppChannel = "o2oa_flutter_channel";
......
......@@ -36,8 +36,6 @@ class LoginController extends GetxController {
// 登录加密
RSAPublicKeyData? _publicKeyData;
///
/// 登录加密服务
///
......@@ -64,6 +62,17 @@ class LoginController extends GetxController {
}
}
/// 是否能注册
Future<void> loadRegisterMode() async {
ValueStringData? data = await OrganizationPersonalService.to.registerMode();
OLogger.d("注册模式:${data?.value} ");
if (data != null &&
data.value?.isNotEmpty == true &&
data.value != O2.registerModeDisable) {
state.registerEnable = true;
}
}
///
/// 获取图片验证码
///
......@@ -117,7 +126,7 @@ class LoginController extends GetxController {
/// 登录
///
void login() async {
if (state.isVisibleAgree && !state.isAgree) {
if (state.isVisibleAgree && !state.isAgree) {
Loading.showError('privacy_policy_bind_disagree_alert'.tr);
return;
}
......@@ -196,8 +205,10 @@ class LoginController extends GetxController {
if (context == null) {
return;
}
O2UI.showConfirm(context, 'login_form_rebind_confirm_message'.tr, okPressed: () => _rebindExecute()) ;
O2UI.showConfirm(context, 'login_form_rebind_confirm_message'.tr,
okPressed: () => _rebindExecute());
}
_rebindExecute() async {
await O2ApiManager.instance.cleanO2UnitAndSp();
Get.offNamed(O2OARoutes.splash);
......@@ -229,6 +240,10 @@ class LoginController extends GetxController {
InnerWebviewPage.open(O2.privacyPolicyUrl);
}
void gotoRegister() {
Get.offAllNamed(O2OARoutes.register);
}
/// 在 onInit() 之后调用 1 帧。这是进入的理想场所
@override
void onReady() {
......@@ -236,6 +251,7 @@ class LoginController extends GetxController {
// O2UI.hideStatusBar();
loadRSAPublicKey();
loadLoginMode();
loadRegisterMode();
state.year = '${DateTime.now().year}';
super.onReady();
}
......@@ -245,5 +261,4 @@ class LoginController extends GetxController {
// O2UI.showStatusBar();
super.onClose();
}
}
import 'package:get/get.dart';
import 'controller.dart';
class RegisterBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<RegisterController>(() => RegisterController());
}
}
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../common/api/index.dart';
import '../../../common/models/index.dart';
import '../../../common/routers/index.dart';
import '../../../common/utils/index.dart';
import '../../../common/values/index.dart';
import '../../../environment_config.dart';
import '../../common/inner_webview/view.dart';
import 'index.dart';
class RegisterController extends GetxController {
RegisterController();
final state = RegisterState();
// 注册用户名的控制器
final TextEditingController userNameController = TextEditingController();
// 密码的控制器
final TextEditingController passwordController = TextEditingController();
// 第二次密码的控制器
final TextEditingController repeatPasswordController =
TextEditingController();
// 邮箱的控制器
final TextEditingController emailController = TextEditingController();
// 手机号码的控制器
final TextEditingController phoneController = TextEditingController();
// 图片验证码的控制器
final TextEditingController captchaController = TextEditingController();
// 验证码的控制器
final TextEditingController codeController = TextEditingController();
final FocusNode passwordNode = FocusNode();
final FocusNode repeatPasswordNode = FocusNode();
final FocusNode emailNode = FocusNode();
final FocusNode phoneNode = FocusNode();
final FocusNode codeNode = FocusNode();
final FocusNode captchaNode = FocusNode();
// 图片验证码对象
CaptchaImgData? _captchaImgData;
/// 在 onInit() 之后调用 1 帧。这是进入的理想场所
@override
void onReady() {
state.isVisibleAgree = EnvironmentConfig.needCheckPrivacyAgree();
loadRegisterMode();
super.onReady();
}
/// 在 [onDelete] 方法之前调用。
@override
void onClose() {
super.onClose();
}
Future<void> loadRegisterMode() async {
ValueStringData? data = await OrganizationPersonalService.to.registerMode();
if (data != null && data.value?.isNotEmpty == true) {
if (data.value == O2.registerModeDisable) {
OLogger.e('错误,注册已经关闭! ${data.value}');
Get.back();
return;
}
state.isCaptcha = (data.value == O2.registerModeCaptcha);
if (state.isCaptcha) {
getCaptchaImageData();
}
OLogger.d("注册模式:${data.value} ");
}
}
///
/// 获取图片验证码
///
Future<void> getCaptchaImageData() async {
_captchaImgData =
await OrganizationPersonalService.to.getRegisterCaptchaImgData(100, 50);
if (_captchaImgData != null) {
captchaController.clear();
state.captchaBase64String = _captchaImgData?.image ?? '';
} else {
OLogger.e('获取图片验证码失败!');
}
}
///
/// 解析图片验证码
///
Uint8List parseCaptchaImg() {
return base64Decode(state.captchaBase64String);
}
/// 检查手机号码
bool onCheckMobile() {
var phone = phoneController.value.text;
if (phone.isEmpty) {
Loading.toast('login_form_register_phone_not_empty'.tr);
return false;
}
return true;
}
/// 发送短信验证码
Future<void> sendSmsCode() async {
var mobile = phoneController.value.text;
if (mobile.isEmpty) {
Loading.toast('login_form_register_phone_not_empty'.tr);
return;
}
var res = await OrganizationPersonalService.to.getRegisterCode(mobile);
if (res != null && res.value == true) {
if (Get.context != null) {
FocusScope.of(Get.context!).requestFocus(codeNode);
Loading.toast('bind_send_code_success'.tr);
}
}
}
Future<bool> checkUserName(String username) async {
final res =
await OrganizationPersonalService.to.checkRegisterUserName(username);
return (res != null && res.value != null && res.value == true);
}
Future<void> register() async {
final username = userNameController.value.text;
if (username.isEmpty) {
Loading.toast('login_form_user_name_not_empty'.tr);
return;
}
final checkName = await checkUserName(username);
if (!checkName) {
return;
}
final password = passwordController.value.text;
if (password.isEmpty) {
Loading.toast('login_form_user_password_not_empty'.tr);
return;
}
final repeatPassword = repeatPasswordController.value.text;
if (repeatPassword.isEmpty) {
Loading.toast('login_form_user_password_repeat_not_empty'.tr);
return;
}
if (password != repeatPassword) {
Loading.toast('login_form_user_password_repeat_not_equals'.tr);
return;
}
final mobile = phoneController.value.text;
if (mobile.isEmpty) {
Loading.toast('login_form_register_phone_not_empty'.tr);
return;
}
Map<String, String> post = {};
post['name'] = username;
post['password'] = password;
post['mobile'] = mobile;
if (state.isCaptcha) {
final captchaInput = captchaController.value.text;
if (captchaInput.isEmpty) {
Loading.toast('login_form_user_code_not_empty'.tr);
return;
}
// 图片验证码注册
post['captchaAnswer'] = captchaInput;
post['captcha'] = _captchaImgData?.id ?? '';
} else {
final codeInput = codeController.value.text;
if (codeInput.isEmpty) {
Loading.toast('login_form_user_code_not_empty'.tr);
return;
}
// 短信验证码
post['codeAnswer'] = codeInput;
}
post['mail'] = emailController.value.text;
post['genderType'] = 'd';
final result = await OrganizationPersonalService.to.register(post);
if (result != null && result.value == true) {
Loading.toast('register_success_to_login'.tr);
gotoLogin();
} else {
if (state.isCaptcha) {
getCaptchaImageData();
}
}
}
void gotoLogin() {
Get.offAllNamed(O2OARoutes.login);
}
/// 同意协议
void changeAgree(bool? v) {
state.isAgree = v == true;
}
/// 打开用户协议
void openUserAgreement() {
InnerWebviewPage.open(O2.userAgreementUrl);
}
/// 打开隐私政策
void openPrivacyPolicy() {
InnerWebviewPage.open(O2.privacyPolicyUrl);
}
}
library register;
export './state.dart';
export './controller.dart';
export './bindings.dart';
export './view.dart';
import 'package:get/get.dart';
class RegisterState {
// title
final _title = "注册".obs;
set title(value) => _title.value = value;
get title => _title.value;
// 当前年份
final _year = "2024".obs;
set year(value) => _year.value = value;
get year => _year.value;
/// 图片验证码是否启用
final _isCaptcha = false.obs;
set isCaptcha(value) => _isCaptcha.value = value;
get isCaptcha => _isCaptcha.value;
final _captchaBase64String = ''.obs;
set captchaBase64String(value) => _captchaBase64String.value = value;
get captchaBase64String => _captchaBase64String.value;
// 是否显示 同意协议
final _isVisibleAgree = false.obs;
set isVisibleAgree(bool value) => _isVisibleAgree.value = value;
bool get isVisibleAgree => _isVisibleAgree.value;
// 是否同意协议
final _isAgree = false.obs;
set isAgree(bool value) => _isAgree.value = value;
bool get isAgree => _isAgree.value;
}
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../common/widgets/index.dart';
import 'index.dart';
class RegisterPage extends GetView<RegisterController> {
const RegisterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetBuilder<RegisterController>(
builder: (_) {
return Scaffold(
body: PageScrollContentWidget(
contentWidget: Column(
children: <Widget>[
_buildInputForm(context),
const Spacer(),
_buildBottom(),
],
),
));
},
);
}
// 底部copyright
Widget _buildBottom() {
return Obx(() => Container(
margin: const EdgeInsets.only(bottom: 10),
child: Align(
alignment: Alignment.center,
child: Text(
'copy_right'.trArgs(['appName'.tr, controller.state.year])),
),
));
}
// 表单
Widget _buildInputForm(BuildContext context) {
return Obx(() => Container(
width: 295,
margin: const EdgeInsets.only(top: 49),
child: Column(children: [
// 账号输入框
TextField(
maxLines: 1,
autofocus: true,
style: Theme.of(context).textTheme.bodyMedium,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
controller: controller.userNameController,
onEditingComplete: () {
FocusScope.of(context).requestFocus(controller.passwordNode);
},
decoration: InputDecoration(
labelText: 'login_form_register_user_name'.tr,
prefixIcon: Icon(Icons.person,
color: Theme.of(context).colorScheme.secondary),
),
),
const SizedBox(
height: 16,
),
TextField(
maxLines: 1,
obscureText: true,
style: Theme.of(context).textTheme.bodyMedium,
focusNode: controller.passwordNode,
controller: controller.passwordController,
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context)
.requestFocus(controller.repeatPasswordNode);
},
decoration: InputDecoration(
labelText: 'login_form_user_password'.tr,
prefixIcon: Icon(Icons.lock,
color: Theme.of(context).colorScheme.secondary),
),
),
const SizedBox(
height: 16,
),
TextField(
maxLines: 1,
obscureText: true,
style: Theme.of(context).textTheme.bodyMedium,
focusNode: controller.repeatPasswordNode,
controller: controller.repeatPasswordController,
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(controller.phoneNode);
},
decoration: InputDecoration(
labelText: 'login_form_user_password_repeat'.tr,
prefixIcon: Icon(Icons.lock,
color: Theme.of(context).colorScheme.secondary),
),
),
const SizedBox(
height: 16,
),
TextField(
maxLines: 1,
style: Theme.of(context).textTheme.bodyMedium,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
focusNode: controller.phoneNode,
controller: controller.phoneController,
onEditingComplete: () {
FocusScope.of(context).requestFocus(controller.emailNode);
},
decoration: InputDecoration(
labelText: 'login_form_register_phone'.tr,
prefixIcon: Icon(Icons.phone_android,
color: Theme.of(context).colorScheme.secondary),
),
),
const SizedBox(
height: 16,
),
TextField(
maxLines: 1,
style: Theme.of(context).textTheme.bodyMedium,
textInputAction: TextInputAction.next,
focusNode: controller.emailNode,
controller: controller.emailController,
onEditingComplete: () {
if (controller.state.isCaptcha) {
FocusScope.of(context).requestFocus(controller.captchaNode);
} else {
FocusScope.of(context).requestFocus(controller.codeNode);
}
},
decoration: InputDecoration(
labelText: 'login_form_register_email'.tr,
prefixIcon: Icon(Icons.email,
color: Theme.of(context).colorScheme.secondary),
),
),
const SizedBox(
height: 16,
),
// 密码或短信验证码 输入框
controller.state.isCaptcha
? _captchaInput(context)
: _codeModeTextFormField(context),
const SizedBox(
height: 16,
),
SizedBox(
width: double.infinity,
height: 42,
child: O2ElevatedButton(
() {
controller.register();
},
Text('register'.tr),
),
),
const SizedBox(
height: 16,
),
Visibility(
visible: controller.state.isVisibleAgree,
child: Row(
children: [
Obx(() => Checkbox(
value: controller.state.isAgree,
onChanged: (value) => controller.changeAgree(value),
)),
Expanded(
flex: 1,
child: RichText(
maxLines: 2,
softWrap: true,
overflow: TextOverflow.ellipsis,
text: TextSpan(
text: 'privacy_policy_bind_content_part1'.tr,
style: Theme.of(context).textTheme.bodySmall,
children: [
TextSpan(
text: 'user_agreement_book_mark'.tr,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontSize: 12),
recognizer: TapGestureRecognizer()
..onTap =
() => controller.openUserAgreement()),
TextSpan(
text:
'privacy_policy_dialog_content_part2'.tr,
style: Theme.of(context).textTheme.bodySmall,
),
TextSpan(
text: 'privacy_policy_book_mark'.tr,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontSize: 12),
recognizer: TapGestureRecognizer()
..onTap =
() => controller.openPrivacyPolicy()),
]),
))
],
)),
const SizedBox(
height: 16,
),
TextButton(
onPressed: () => controller.gotoLogin(),
child: Text('register_to_login'.tr,
style: Theme.of(context).textTheme.bodySmall)),
]),
));
}
Widget _captchaInput(BuildContext context) {
return Row(
children: [
Expanded(
flex: 1,
child: TextField(
maxLines: 1,
style: Theme.of(context).textTheme.bodyMedium,
keyboardType: TextInputType.number,
focusNode: controller.captchaNode,
controller: controller.captchaController,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
labelText: 'login_form_user_code'.tr,
prefixIcon: Icon(Icons.lock,
color: Theme.of(context).colorScheme.secondary),
),
)),
controller.state.captchaBase64String.isEmpty
? TextButton(
onPressed: () {
controller.getCaptchaImageData();
},
child: const Text('点击刷新'))
: InkWell(
onTap: () {
controller.getCaptchaImageData();
},
child: Image.memory(
controller.parseCaptchaImg(),
width: 100,
height: 50,
fit: BoxFit.cover,
),
)
],
);
}
///
/// 短信验证码登录
///
Widget _codeModeTextFormField(BuildContext context) {
return Row(
children: [
Expanded(
flex: 2,
child: TextField(
maxLines: 1,
obscureText: true,
style: Theme.of(context).textTheme.bodyMedium,
keyboardType: TextInputType.text,
controller: controller.codeController,
focusNode: controller.codeNode,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
labelText: 'login_form_user_code'.tr,
prefixIcon: Icon(Icons.lock,
color: Theme.of(context).colorScheme.secondary),
),
),
),
Expanded(
flex: 1,
child: CountDownButton(() {
return controller.onCheckMobile();
}, () {
controller.sendSmsCode();
}))
],
);
}
}
......@@ -11,6 +11,10 @@ class LoginState {
set year(value) => _year.value = value;
get year => _year.value;
/// 是否能注册
final _registerEnable = false.obs;
set registerEnable(value) => _registerEnable.value = value;
get registerEnable => _registerEnable.value;
/// 密码登录模式
final _isPasswordLogin = true.obs;
......
......@@ -149,12 +149,18 @@ class LoginPage extends GetView<LoginController> {
style: Theme.of(context).textTheme.bodySmall))),
),
Expanded(
child: Visibility(
visible: !EnvironmentConfig.isDirectConnectMode(),
child: TextButton(
child: EnvironmentConfig.isDirectConnectMode()
? Visibility(
visible: controller.state.registerEnable,
child: TextButton(
onPressed: () => controller.gotoRegister(),
child: Text('login_to_register'.tr,
style:
Theme.of(context).textTheme.bodySmall)))
: TextButton(
onPressed: () => controller.rebind(),
child: Text('login_form_rebind'.tr,
style: Theme.of(context).textTheme.bodySmall))))
style: Theme.of(context).textTheme.bodySmall)))
],
),
const SizedBox(
......@@ -283,7 +289,7 @@ class LoginPage extends GetView<LoginController> {
style: Theme.of(context).textTheme.bodyMedium,
focusNode: controller.passwordNode,
controller: controller.passwordController,
textInputAction: TextInputAction.next,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
labelText: 'login_form_user_password'.tr,
prefixIcon: Icon(Icons.lock,
......