| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- import 'dart:io';
- import 'package:dio/dio.dart';
- import '../../../core/network/api_response.dart';
- import '../../../core/utils/device_fingerprint_service.dart';
- /// 注册前 `/uc/check-account` 的语义结果(与 Web checkAccountForRegister 一致):
- /// 业务成功 code=0 表示可申请注册;占用由非 0 与异常文案体现;掩码「用户名或密码错误」放行可继续注册。
- enum CheckAccountForRegisterResult {
- /// 账号已占用(如接口返回「已注册」等文案)
- alreadyRegistered,
- /// 可申请注册(成功或掩码「用户名或密码错误」)
- available,
- }
- /// 登录响应数据
- class LoginResult {
- final String token;
- final String? uid;
- final String? email;
- const LoginResult({required this.token, this.uid, this.email});
- factory LoginResult.fromJson(Map<String, dynamic> json) {
- return LoginResult(
- token: json['token'] as String? ?? '',
- uid: json['id']?.toString(),
- email: json['email'] as String?,
- );
- }
- }
- /// 认证 API 服务(无状态,只封装 HTTP 调用)
- ///
- /// 所有接口使用 form-urlencoded 格式提交
- class AuthService {
- const AuthService(this._dio);
- final Dio _dio;
- /// form-urlencoded 请求选项
- static final _formOptions = Options(
- contentType: 'application/x-www-form-urlencoded',
- );
- /// 设备类型:1=iOS,2=Android,5=PC/其他
- static int get _deviceType {
- if (Platform.isIOS) return 1;
- if (Platform.isAndroid) return 2;
- return 5;
- }
- /// 与 Web 一致的掩码文案:账号不存在时接口不落真实原因
- static bool isRegisterAvailabilityMaskMessage(String message) {
- return message.contains('用户名或密码错误');
- }
- /// 与 Web `checkAccountForRegister` 一致:接口用业务异常文案表示「已占用」
- static bool isAccountAlreadyRegisteredHint(String message) {
- if (message.contains('已注册')) {
- return true;
- }
- if (message.contains('已存在')) {
- return true;
- }
- if (message.contains('已被使用')) {
- return true;
- }
- return RegExp(
- r'already\s+(exists|registered)',
- caseSensitive: false,
- ).hasMatch(message);
- }
- // ── 登录发码前校验密码(与 Web `/uc/check-password` 一致)────────
- Future<void> checkLoginPassword({
- required String username,
- required String password,
- }) async {
- await _dio.post<dynamic>(
- 'uc/check-password',
- data: {'username': username.trim(), 'password': password},
- options: _formOptions,
- );
- }
- // ── 注册发码前校验账号是否已存在(与 Web `/uc/check-account` 一致)──
- Future<CheckAccountForRegisterResult> checkAccountForRegister(
- String username,
- ) async {
- try {
- await _dio.post<dynamic>(
- 'uc/check-account',
- data: {'username': username.trim()},
- options: _formOptions,
- );
- return CheckAccountForRegisterResult.available;
- } on DioException catch (e) {
- final err = e.error;
- if (err is ApiException) {
- final msg = err.message;
- if (isAccountAlreadyRegisteredHint(msg)) {
- return CheckAccountForRegisterResult.alreadyRegistered;
- }
- if (isRegisterAvailabilityMaskMessage(msg)) {
- return CheckAccountForRegisterResult.available;
- }
- }
- rethrow;
- }
- }
- // ── 发送登录验证码 ──────────────────────────────────────
- Future<void> sendLoginEmailCode(String email) async {
- await _dio.post<dynamic>(
- 'uc/login/email/code',
- data: {'username': email, 'email': email},
- options: _formOptions,
- );
- }
- // ── 密码+验证码登录 ──────────────────────────────────────
- /// [vtype] 验证类型:2=邮箱验证码,3=谷歌验证码
- Future<LoginResult> loginWithPassword({
- required String email,
- required String password,
- required String code,
- String vtype = '2',
- }) async {
- final deviceInfo = await DeviceFingerprintService.getDeviceInfo();
- final response = await _dio.post<Map<String, dynamic>>(
- 'uc/login',
- data: {
- 'username': email,
- 'password': password,
- 'country': '',
- 'vtype': vtype,
- 'vcode': code,
- 'deviceType': _deviceType,
- 'deviceFingerprint': deviceInfo.fingerprint,
- 'deviceModel': deviceInfo.model,
- 'osVersion': deviceInfo.osVersion,
- },
- options: _formOptions,
- );
- final data = (response.data?['data'] as Map<String, dynamic>?) ?? {};
- return LoginResult.fromJson(data);
- }
- // ── 发送注册验证码 ──────────────────────────────────────
- Future<void> sendRegisterEmailCode(String email) async {
- await _dio.post<dynamic>(
- 'uc/reg/email/code',
- data: {'username': email, 'email': email},
- options: _formOptions,
- );
- }
- // ── 邮箱注册 ────────────────────────────────────────────
- Future<void> registerWithEmail({
- required String email,
- required String password,
- required String code,
- String? inviteCode,
- String country = '不丹',
- }) async {
- await _dio.post<Map<String, dynamic>>(
- 'uc/register/email',
- data: {
- 'email': email,
- 'username': email,
- 'password': password,
- 'code': code,
- 'country': country,
- 'promotion': inviteCode ?? '',
- 'deviceType': _deviceType,
- },
- options: _formOptions,
- );
- }
- // ── 发送重置密码验证码 ──────────────────────────────────
- Future<void> sendResetEmailCode(String email) async {
- await _dio.post<dynamic>(
- 'uc/reset/email/code',
- data: {'username': email, 'account': email},
- options: _formOptions,
- );
- }
- // ── 重置密码 ────────────────────────────────────────────
- Future<void> resetPassword({
- required String email,
- required String password,
- required String code,
- }) async {
- await _dio.post<dynamic>(
- 'uc/reset/login/password',
- data: {'email': email, 'password': password, 'code': code, 'account': email, 'mode': 1},
- options: _formOptions,
- );
- }
- // ── 退出登录 ────────────────────────────────────────────
- Future<void> logout() async {
- await _dio.post<dynamic>('uc/loginout');
- }
- // ── 获取用户信息 ────────────────────────────────────────
- Future<Map<String, dynamic>> getMyInfo() async {
- final response =
- await _dio.post<Map<String, dynamic>>('uc/member/my-info');
- return (response.data?['data'] as Map<String, dynamic>?) ?? {};
- }
- // ── 谷歌验证器绑定流程 ──────────────────────────────────
- /// 获取谷歌验证器秘钥
- /// 返回 { link: "otpauth://...", secret: "P12EB42NCCSE8VTX" }
- Future<Map<String, dynamic>> getGoogleSecret() async {
- final response = await _dio.get<Map<String, dynamic>>(
- 'uc/google/sendgoogle',
- );
- return (response.data?['data'] as Map<String, dynamic>?) ?? {};
- }
- /// 发送谷歌验证器绑定的邮箱验证码
- Future<void> sendGoogleAuthEmailCode() async {
- await _dio.post<dynamic>(
- 'uc/googleAuth/email/code',
- options: _formOptions,
- );
- }
- /// 绑定谷歌验证器
- /// [codes] Google Authenticator 6位动态码
- /// [vcode] 邮箱收到的6位验证码
- /// [secret] 第一步获取的密钥
- /// [vtype] 验证方式 "2"=邮箱
- Future<void> bindGoogleAuth({
- required String codes,
- required String vcode,
- required String secret,
- String vtype = '2',
- }) async {
- await _dio.post<dynamic>(
- 'uc/google/googleAuthWithSms',
- data: {
- 'codes': codes,
- 'vtype': vtype,
- 'vcode': vcode,
- 'secret': secret,
- },
- options: _formOptions,
- );
- }
- // ── 资金密码 ──────────────────────────────────────────────
- /// 首次设置资金密码
- Future<void> setFundPassword(String password) async {
- await _dio.post<dynamic>(
- 'uc/approve/transaction/password',
- data: {'jyPassword': password},
- options: _formOptions,
- );
- }
- /// 发送资金密码重置邮箱验证码
- Future<void> sendFundPasswordEmailCode() async {
- await _dio.post<dynamic>(
- 'uc/transaction/email/code',
- options: _formOptions,
- );
- }
- /// 重置资金密码
- /// 发送修改登录密码邮箱验证码 — POST uc/updatePassword/email/code
- Future<void> sendChangePasswordEmailCode() async {
- await _dio.post<dynamic>(
- 'uc/updatePassword/email/code',
- options: _formOptions,
- );
- }
- /// 修改登录密码 — POST uc/approve/update/password
- Future<void> changeLoginPassword({
- required String oldPassword,
- required String newPassword,
- required String vcode,
- }) async {
- await _dio.post<dynamic>(
- 'uc/approve/update/password',
- data: {
- 'oldPassword': oldPassword,
- 'newPassword': newPassword,
- 'vtype': '2',
- 'vcode': vcode,
- },
- options: _formOptions,
- );
- }
- Future<void> resetFundPassword({
- required String newPassword,
- required String vcode,
- String vtype = '2',
- }) async {
- await _dio.post<dynamic>(
- 'uc/approve/reset/transaction/password',
- data: {
- 'newPassword': newPassword,
- 'vtype': vtype,
- 'vcode': vcode,
- },
- options: _formOptions,
- );
- }
- }
|