Files
tongxunruanjian/mobile/lib/services/auth_api.dart
T
KIMI b95159f7eb 新增 mobile/:畅联手机端 Flutter 工程(B-58)
- 登录:工号+密码走 account-service /api/login,自动登录、被踢下线回登录页
- 消息:会话列表(未读角标/免打扰/时间)、单聊群聊、文字/语音/图片/文件消息、失败重发、历史分页
- 通讯录:新的同事/我的群聊入口、按部门分组(好友 ex 字段)、搜索
- 通话:一对一语音通话(信令走 OpenIM 自定义消息 + LiveKit,token 走 /api/rtc_token)
- 界面按确认效果图 m1/m2/m3 实现,主色 #3B87F5,四态视图齐全,无英文残留
2026-08-09 01:28:12 +08:00

121 lines
4.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:dio/dio.dart';
import '../config.dart';
/// 公司账号登录接口返回的数据
class AuthResult {
final String userID;
final String token;
final String nickname;
AuthResult({required this.userID, required this.token, required this.nickname});
factory AuthResult.fromJson(Map<String, dynamic> json) => AuthResult(
userID: json['userID']?.toString() ?? '',
token: json['imToken']?.toString() ?? '',
nickname: json['nickname']?.toString() ?? '',
);
}
/// 登录失败,message 直接给用户看(简体中文)
class AuthException implements Exception {
final String message;
AuthException(this.message);
@override
String toString() => message;
}
/// 公司账号登录 HTTP 客户端。
///
/// 接口契约(account-service,见仓库 account-service/README.md):
/// - POST {authApiBase}/api/login
/// body: {"staffNo": "工号", "password": "...", "platformID": 1 iOS / 2 Android}
/// 响应统一包络 {"code": 0, "msg": "", "data": {...}},失败也是 HTTP 200 + code != 0
/// 成功 data: {"userID", "nickname", "imToken", "expireTimeSeconds"}userID/imToken 直接用于 OpenIM SDK 登录)
/// - POST {authApiBase}/api/rtc_token(语音通话换 LiveKit 进房 token
/// 请求头: Authorization: Bearer {imToken}
/// body: {"room": "房间号", "identity": "当前用户 userID"}
/// 成功 data: {"token": "LiveKit 访问 token"}
class AuthApi {
final Dio _dio = Dio(BaseOptions(
baseUrl: authApiBase,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
));
/// 拆统一响应包络:code == 0 返回 data,否则用 msg 抛 [AuthException]
Map<String, dynamic> _unwrap(dynamic body) {
if (body is Map<String, dynamic>) {
if (body['code'] == 0 && body['data'] is Map<String, dynamic>) {
return Map<String, dynamic>.from(body['data'] as Map);
}
final msg = body['msg']?.toString();
throw AuthException((msg != null && msg.isNotEmpty) ? msg : '服务器返回的数据不对,请联系管理员');
}
throw AuthException('服务器返回的数据不对,请联系管理员');
}
/// 工号 + 密码登录,成功后返回 OpenIM 登录所需的 userID/imToken
Future<AuthResult> login({required String staffNo, required String password, required int platformID}) async {
try {
final resp = await _dio.post('/api/login', data: {
'staffNo': staffNo,
'password': password,
'platformID': platformID,
});
final result = AuthResult.fromJson(_unwrap(resp.data));
if (result.userID.isNotEmpty && result.token.isNotEmpty) return result;
throw AuthException('服务器返回的数据不对,请联系管理员');
} on DioException catch (e) {
// 401 等 HTTP 层失败也带 {code, msg} 包络
final data = e.response?.data;
if (data is Map && data['msg'] != null && data['msg'].toString().isNotEmpty) {
throw AuthException(data['msg'].toString());
}
throw AuthException('连不上服务器,请检查网络');
} catch (e) {
if (e is AuthException) rethrow;
throw AuthException('登录出错了,请稍后再试');
}
}
/// 获取 LiveKit 房间 token(语音通话用)。authToken 即登录返回的 imToken。
Future<LiveKitCredential> getRtcToken({required String room, required String identity, required String authToken}) async {
try {
final resp = await _dio.post(
'/api/rtc_token',
data: {'room': room, 'identity': identity},
options: Options(headers: {'Authorization': 'Bearer $authToken'}),
);
final data = _unwrap(resp.data);
final token = data['token']?.toString();
if (token != null && token.isNotEmpty) {
final live = data['liveURL']?.toString();
return LiveKitCredential(
token: token,
liveURL: live != null && live.isNotEmpty ? live : livekitUrl,
);
}
throw AuthException('服务器返回的数据不对,请联系管理员');
} on DioException catch (e) {
final data = e.response?.data;
if (data is Map && data['msg'] != null && data['msg'].toString().isNotEmpty) {
throw AuthException(data['msg'].toString());
}
throw AuthException('连不上服务器,请检查网络');
} catch (e) {
if (e is AuthException) rethrow;
throw AuthException('发起通话失败,请稍后再试');
}
}
}
/// LiveKit 进房凭证
class LiveKitCredential {
final String token;
final String liveURL;
LiveKitCredential({required this.token, required this.liveURL});
}