Files
customer-im-client-dev/apps/im_app/lib/data/remote/get_profile_request.dart
pp-bot e715a0673b feat(chat): 发收消息全量实现 (#25~#28)
- 移除 @riverpod/@freezed 注解依赖,全部改为手写 Provider(无需 build_runner)
  · LoginState 改为纯 Dart,LoginViewModel/ThemeViewModel/ChatViewModel 改为 Notifier
  · UserNotifier 改为 FamilyAsyncNotifier<User?,int>,mini_app_provider 改为手写 Provider
  · 15 个 StreamProvider/StreamProvider.family 从 @riverpod 迁移至手写

- 发送消息(#25)
  · SendMessageRequest/SendMessageResponse DTO
  · SendMessageUseCase:乐观写入 DB → HTTP POST → 更新 Chat 摘要

- 接收消息 WS(#26)
  · WsMessageService:监听 mode2 WS 帧 → HTTP 补拉 → DB 写入 → Chat 更新
  · FetchHistoryRequest/FetchHistoryResponse DTO(GET /app/api/chat/history)
  · FetchHistoryUseCase:拉取 → insertOrReplaceAll

- DI 装配(chat_service_providers.dart)
  · wsMessageServiceProvider、sendMessageUseCaseProvider、fetchHistoryUseCaseProvider

- 聊天列表页(#27)
  · ChatListViewModel(Notifier<void>)+ chat_page.dart 真实会话列表 UI
  · ListTile:头像首字母、最新消息摘要、未读角标、时间格式化

- 聊天详情页(#28)
  · ChatDetailViewModel(FamilyNotifier<ChatDetailState,int>)+ chat_detail_page.dart
  · 消息气泡(自己/他人分左右)、底部输入框、发送状态与错误提示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:16:44 +09:00

132 lines
4.5 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:json_annotation/json_annotation.dart';
import 'package:networks_sdk/networks_sdk.dart';
import 'package:im_app/core/foundation/api_paths.dart';
import 'package:im_app/domain/entities/user.dart';
part 'get_profile_request.g.dart';
/// # /user/profile — 获取用户资料GET 请求)
///
/// GET 请求无 body`toJson()` 结果自动作为 URL query parameters 发送。
/// 如需 query 参数(如分页),直接在类中添加字段,生成器自动序列化。
///
/// ## 数据流位置
///
/// ```
/// UserRepositoryImpl.getProfile()
/// → _client.executeRequest( ★ GetProfileRequest ★ ) ← 你在这里
/// → 服务端 GET /user/profile
/// → SDK 内部 ApiResponseWrapper 拆包 { code, message, data }
/// → ★ ProfileResponse ★ = data 字段 ← 也在这里
/// → ProfileResponse.toEntity() → User
/// ```
// ─────────────────────────────────────────────
// Response DTO
// ─────────────────────────────────────────────
/// 用户资料接口的业务响应数据(对应服务端 `data` 字段)。
///
/// `{ code, message }` 由 SDK 内部的 `ApiResponseWrapper` 统一处理。纯 Dart 类,无需任何注解。
class ProfileResponse {
final int uid;
final String uuid;
@JsonKey(name: 'last_online')
final int lastOnline;
@JsonKey(name: 'profile_pic')
final String profilePic;
@JsonKey(name: 'profile_pic_gaussian')
final String profilePicGaussian;
final String nickname;
final String contact;
@JsonKey(name: 'country_code')
final String countryCode;
final String email;
@JsonKey(name: 'recovery_email')
final String recoveryEmail;
final String username;
final String bio;
final int relationship;
@JsonKey(name: 'user_alias')
final String? userAlias;
@JsonKey(name: 'channel_id')
final int channelId;
@JsonKey(name: 'channel_group_id')
final int channelGroupId;
final String hint;
const ProfileResponse({
required this.uid,
required this.uuid,
required this.lastOnline,
required this.profilePic,
required this.profilePicGaussian,
required this.nickname,
required this.contact,
required this.countryCode,
required this.email,
required this.recoveryEmail,
required this.username,
required this.bio,
required this.relationship,
this.userAlias,
required this.channelId,
required this.channelGroupId,
required this.hint,
});
factory ProfileResponse.fromJson(Map<String, dynamic> json) => ProfileResponse(
uid: (json['uid'] as num?)?.toInt() ?? 0,
uuid: json['uuid'] as String? ?? '',
lastOnline: (json['last_online'] as num?)?.toInt() ?? 0,
profilePic: json['profile_pic'] as String? ?? '',
profilePicGaussian: json['profile_pic_gaussian'] as String? ?? '',
nickname: json['nickname'] as String? ?? '',
contact: json['contact'] as String? ?? '',
countryCode: json['country_code'] as String? ?? '',
email: json['email'] as String? ?? '',
recoveryEmail: json['recovery_email'] as String? ?? '',
username: json['username'] as String? ?? '',
bio: json['bio'] as String? ?? '',
relationship: (json['relationship'] as num?)?.toInt() ?? 0,
userAlias: json['user_alias'] as String?,
channelId: (json['channel_id'] as num?)?.toInt() ?? 0,
channelGroupId: (json['channel_group_id'] as num?)?.toInt() ?? 0,
hint: json['hint'] as String? ?? '',
);
User toEntity() => User(
uid: uid,
uuid: uuid,
lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname,
contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
hint: hint,
);
}
// ─────────────────────────────────────────────
// Request
// ─────────────────────────────────────────────
/// 获取用户资料请求GET无参数
@ApiRequest(
path: ApiPaths.userProfile,
method: HttpMethod.get,
responseType: ProfileResponse,
)
class GetProfileRequest extends ApiRequestable<ProfileResponse>
with _$GetProfileRequestApi {
GetProfileRequest();
}