diff --git a/mobile-next/openim_common/lib/openim_common.dart b/mobile-next/openim_common/lib/openim_common.dart index 42d90d1..b10ba19 100644 --- a/mobile-next/openim_common/lib/openim_common.dart +++ b/mobile-next/openim_common/lib/openim_common.dart @@ -33,6 +33,7 @@ export 'src/utils/sp_util.dart'; export 'src/utils/utils.dart'; export 'src/utils/voice_record.dart'; export 'src/utils/api_service.dart'; +export 'src/utils/user_full_info_mapper.dart'; export 'src/widgets/avatar_view.dart'; export 'src/widgets/azlist_view.dart'; export 'src/widgets/bottom_bar.dart'; diff --git a/mobile-next/openim_common/lib/src/apis.dart b/mobile-next/openim_common/lib/src/apis.dart index 0ed37cf..ced27d6 100644 --- a/mobile-next/openim_common/lib/src/apis.dart +++ b/mobile-next/openim_common/lib/src/apis.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; import 'package:flutter_openim_sdk/flutter_openim_sdk.dart'; import 'package:get/get.dart'; @@ -11,14 +10,19 @@ import 'package:sprintf/sprintf.dart'; import 'utils/api_service.dart'; class Apis { - static Options get imTokenOptions => Options(headers: {'token': DataSp.imToken}); + static Options get imTokenOptions => + Options(headers: {'token': DataSp.imToken}); - static Options get chatTokenOptions => Options(headers: {'token': DataSp.chatToken}); + static Options get chatTokenOptions => + Options(headers: {'token': DataSp.chatToken}); static StreamController kickoffController = StreamController.broadcast(); static void _kickoff(int? errCode) { - if (errCode == 1501 || errCode == 1503 || errCode == 1504 || errCode == 1505) { + if (errCode == 1501 || + errCode == 1503 || + errCode == 1504 || + errCode == 1505) { kickoffController.sink.add(errCode); } } @@ -197,43 +201,16 @@ class Apis { int? allowBeep, int? allowVibration, }) async { - try { - Map param = {'userID': userID}; - void put(String key, dynamic value) { - if (null != value) { - param[key] = value; - } - } - - put('account', account); - put('phoneNumber', phoneNumber); - put('areaCode', areaCode); - put('email', email); - put('nickname', nickname); - put('faceURL', faceURL); - put('gender', gender); - put('gender', gender); - put('level', level); - put('birth', birth); - put('allowAddFriend', allowAddFriend); - put('allowBeep', allowBeep); - put('allowVibration', allowVibration); - - return HttpUtil.post( - Urls.updateUserInfo, - data: { - ...param, - 'platform': IMUtils.getPlatform(), - }, - options: chatTokenOptions, + // 原 chat `/user/update` 已随 :10008 下线。OpenIM 只同步昵称/头像; + // 邮箱、性别、生日等业务字段由调用方更新本地状态,不打账号服务。 + if (userID.isEmpty) return {}; + if (nickname != null || faceURL != null) { + await OpenIM.iMManager.userManager.setSelfInfo( + nickname: nickname, + faceURL: faceURL, ); - } catch (e, s) { - final t = e as (int, String?); - final errCode = t.$1; - final errMsg = t.$2; - _kickoff(errCode); - Logger.print('e:$errCode s:$errMsg'); } + return {}; } static Future> searchFriendInfo( @@ -251,7 +228,9 @@ class Apis { options: chatTokenOptions, ); if (data['users'] is List) { - return (data['users'] as List).map((e) => FriendInfo.fromJson(e)).toList(); + return (data['users'] as List) + .map((e) => FriendInfo.fromJson(e)) + .toList(); } return []; } catch (e, s) { @@ -269,26 +248,16 @@ class Apis { int showNumber = 10, required List userIDList, }) async { + if (userIDList.isEmpty) return []; try { - final data = await HttpUtil.post( - Urls.getUsersFullInfo, - data: { - 'pagination': {'pageNumber': pageNumber, 'showNumber': showNumber}, - 'userIDs': userIDList, - 'platform': IMUtils.getPlatform(), - }, - options: chatTokenOptions, + final users = await OpenIM.iMManager.userManager.getUsersInfo( + userIDList: userIDList, ); - if (data['users'] is List) { - return (data['users'] as List).map((e) => UserFullInfo.fromJson(e)).toList(); - } - return null; + return users + .map((e) => UserFullInfoMapper.fromImJson(e.toJson())) + .toList(); } catch (e, s) { - final t = e as (int, String?); - final errCode = t.$1; - final errMsg = t.$2; - _kickoff(errCode); - Logger.print('e:$errCode s:$errMsg'); + Logger.print('getUserFullInfo e:$e s:$s'); return []; } } @@ -298,34 +267,20 @@ class Apis { int pageNumber = 1, int showNumber = 10, }) async { - try { - final data = await HttpUtil.post( - Urls.searchUserFullInfo, - data: { - 'pagination': {'pageNumber': pageNumber, 'showNumber': showNumber}, - 'keyword': content, - }, - options: chatTokenOptions, - ); - if (data['users'] is List) { - return (data['users'] as List).map((e) => UserFullInfo.fromJson(e)).toList(); - } - return null; - } catch (e, s) { - final t = e as (int, String?); - final errCode = t.$1; - final errMsg = t.$2; - _kickoff(errCode); - Logger.print('e:$errCode s:$errMsg'); - return []; - } + final keyword = content.trim(); + if (keyword.isEmpty) return []; + if (pageNumber > 1) return []; + return getUserFullInfo(userIDList: [keyword], showNumber: showNumber); } static Future queryMyFullInfo() async { - final list = await Apis.getUserFullInfo( - userIDList: [OpenIM.iMManager.userID], - ); - return list?.firstOrNull; + try { + final user = await OpenIM.iMManager.userManager.getSelfUserInfo(); + return UserFullInfoMapper.fromImJson(user.toJson()); + } catch (e, s) { + Logger.print('queryMyFullInfo e:$e s:$s'); + return null; + } } static Future requestVerificationCode({ @@ -353,7 +308,8 @@ class Apis { }); } - static Future getTokenForRTC(String roomID, String userID) async { + static Future getTokenForRTC( + String roomID, String userID) async { return HttpUtil.post( Urls.getTokenForRTC, data: { @@ -410,7 +366,10 @@ class Apis { } static Future> getClientConfig() async { - return {'discoverPageURL': Config.discoverPageURL, 'allowSendMsgNotFriend': Config.allowSendMsgNotFriend}; + return { + 'discoverPageURL': Config.discoverPageURL, + 'allowSendMsgNotFriend': Config.allowSendMsgNotFriend + }; } static void _catchError(Object e, StackTrace s, {bool forceBack = true}) { diff --git a/mobile-next/openim_common/lib/src/urls.dart b/mobile-next/openim_common/lib/src/urls.dart index f967e73..989c5cd 100644 --- a/mobile-next/openim_common/lib/src/urls.dart +++ b/mobile-next/openim_common/lib/src/urls.dart @@ -5,6 +5,8 @@ class Urls { "${Config.imApiUrl}/manager/get_users_online_status"; static String get queryAllUsers => "${Config.imApiUrl}/manager/get_all_users_uid"; + // 以下 chat 路径仅作历史对照。账号服务 :10010 没有这些路由; + // 用户资料读写已改走 OpenIM SDK,见 Apis.getUserFullInfo / updateUserInfo。 static String get updateUserInfo => "${Config.appAuthUrl}/user/update"; static String get searchFriendInfo => "${Config.appAuthUrl}/friend/search"; static String get getUsersFullInfo => "${Config.appAuthUrl}/user/find/full"; diff --git a/mobile-next/openim_common/lib/src/utils/user_full_info_mapper.dart b/mobile-next/openim_common/lib/src/utils/user_full_info_mapper.dart new file mode 100644 index 0000000..d8e814b --- /dev/null +++ b/mobile-next/openim_common/lib/src/utils/user_full_info_mapper.dart @@ -0,0 +1,24 @@ +import '../models/user_full_info.dart'; + +/// 把 OpenIM 公开资料收成原 chat 服务 `UserFullInfo` 形状。 +/// +/// 官方 `open-im-chat`(:10008 `/user/find/full`)已下线,账号服务 :10010 +/// 没有这条路由。SDK 只保证 userID / nickname / faceURL / ex / 勿扰。 +class UserFullInfoMapper { + UserFullInfoMapper._(); + + static UserFullInfo fromImJson(Map json) { + return UserFullInfo.fromJson({ + 'userID': json['userID'], + 'nickname': json['nickname'], + 'faceURL': json['faceURL'], + 'ex': json['ex'], + 'remark': json['remark'], + 'globalRecvMsgOpt': json['globalRecvMsgOpt'], + }); + } + + static List fromImList(Iterable> items) { + return items.map(fromImJson).toList(); + } +} diff --git a/mobile-next/test/company/user_full_info_mapper_test.dart b/mobile-next/test/company/user_full_info_mapper_test.dart new file mode 100644 index 0000000..ed4cae0 --- /dev/null +++ b/mobile-next/test/company/user_full_info_mapper_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:openim_common/openim_common.dart'; + +void main() { + test('把 OpenIM 公开资料映射成我的信息可用字段', () { + final info = UserFullInfoMapper.fromImJson({ + 'userID': '10001', + 'nickname': '张三', + 'faceURL': 'http://example/a.png', + 'ex': '', + 'globalRecvMsgOpt': 0, + }); + expect(info.userID, '10001'); + expect(info.nickname, '张三'); + expect(info.faceURL, 'http://example/a.png'); + expect(info.globalRecvMsgOpt, 0); + }); + + test('不把 chat 业务字段当成仍可从账号服务拿到', () { + final info = UserFullInfoMapper.fromImJson({ + 'userID': '10001', + 'nickname': '张三', + 'phoneNumber': '13800000000', + 'email': 'a@b.c', + 'gender': 1, + }); + expect(info.userID, '10001'); + expect(info.nickname, '张三'); + expect(info.phoneNumber, isNull); + expect(info.email, isNull); + expect(info.gender, isNull); + }); + + test('空列表保持为空', () { + expect(UserFullInfoMapper.fromImList(const []), isEmpty); + }); +}