Merge pull request 'dto/业务数据分离,替换' (#5) from happi/dev/database-update into dev

Reviewed-on: https://gitea.winwayinfo.com/CUS-IM/customer-im-client/pulls/5
This commit is contained in:
wangfeng
2026-03-08 16:30:32 +08:00
66 changed files with 4369 additions and 208 deletions

View File

@@ -0,0 +1,31 @@
{
"code": 0,
"message": "OK",
"data": {
"account_id": "1713925030yFMUBu",
"profile": {
"uid": 2137067,
"uuid": "1713925030yFMUBu",
"last_online": 1772819822,
"profile_pic": "Image/7e/f5/7ef5b60dd83a34a74c164a21fbd1f098/7ef5b60dd83a34a74c164a21fbd1f098.jpg",
"profile_pic_gaussian": "",
"nickname": "Happi哈比",
"contact": "86552205",
"country_code": "+65",
"email": "happi@winwayinfo.com",
"recovery_email": "",
"username": "happi",
"bio": "",
"relationship": 2,
"user_alias": null,
"channel_id": 1,
"channel_group_id": 1,
"hint": "1111"
},
"nonce": "",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIxMzcwNjcsInVkaWQiOjI2NjI2MzcsInNpZCI6IjE3NzI4NjU0NDc0Z1c2VWc9PSIsImlzcyI6ImFiYy5jb20iLCJhdWQiOlsidXNlciJdLCJleHAiOjE3NzQxNjE0NDcsIm5iZiI6MTc3Mjg2NTQ0NywiaWF0IjoxNzcyODY1NDQ3fQ.gUL6hyKgyPP8Tw9y7kRSq-ndNKfV9uGFhU4YKiQzg0I",
"refresh_token": "ps0FF3XayvnJB_P8Cnfu7w-uD781b1-vfmUjbrONZxI=",
"device_id": "SP1A.210812",
"login_data": ""
}
}

View File

@@ -29,25 +29,25 @@ class AppDatabase extends _$AppDatabase {
return {}; return {};
} }
return { return {
Favourite: database.favourites, DriftFavourite: database.favourites,
Sound: database.sounds, DriftSound: database.sounds,
Tag: database.tags, DriftTag: database.tags,
PendingFriendRequestHistory: database.pendingFriendRequestHistories, DriftPendingFriendRequestHistory: database.pendingFriendRequestHistories,
Message: database.messages, DriftMessage: database.messages,
RecentMiniApp: database.recentMiniApps, DriftRecentMiniApp: database.recentMiniApps,
Retry: database.retries, DriftRetry: database.retries,
Group: database.groups, DriftGroup: database.groups,
FavoriteMiniApp: database.favoriteMiniApps, DriftFavoriteMiniApp: database.favoriteMiniApps,
DiscoverMiniApp: database.discoverMiniApps, DriftDiscoverMiniApp: database.discoverMiniApps,
ChatCategory: database.chatCategories, DriftChatCategory: database.chatCategories,
ChatBot: database.chatBots, DriftChatBot: database.chatBots,
FavouriteDetail: database.favouriteDetails, DriftFavouriteDetail: database.favouriteDetails,
UserRequestHistory: database.userRequestHistories, DriftUserRequestHistory: database.userRequestHistories,
Workspace: database.workspaces, DriftWorkspace: database.workspaces,
User: database.users, DriftUser: database.users,
ExploreMiniApp: database.exploreMiniApps, DriftExploreMiniApp: database.exploreMiniApps,
CallLog: database.callLogs, DriftCallLog: database.callLogs,
Chat: database.chats, DriftChat: database.chats,
}; };
} }

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('CallLog') @DataClassName('DriftCallLog')
class CallLogs extends Table { class CallLogs extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
IntColumn get callerId => integer().nullable()(); IntColumn get callerId => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('ChatBot') @DataClassName('DriftChatBot')
class ChatBots extends Table { class ChatBots extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -1,9 +1,9 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('ChatCategory') @DataClassName('DriftChatCategory')
class ChatCategories extends Table { class ChatCategories extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
TextColumn get name => text().nullable().unique()(); TextColumn get name => text().nullable()();
TextColumn get includedChatIds => text().nullable()(); TextColumn get includedChatIds => text().nullable()();
TextColumn get excludedChatIds => text().nullable()(); TextColumn get excludedChatIds => text().nullable()();
IntColumn get seq => integer().nullable()(); IntColumn get seq => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Chat') @DataClassName('DriftChat')
class Chats extends Table { class Chats extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
IntColumn get typ => integer().nullable()(); IntColumn get typ => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('DiscoverMiniApp') @DataClassName('DriftDiscoverMiniApp')
class DiscoverMiniApps extends Table { class DiscoverMiniApps extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('ExploreMiniApp') @DataClassName('DriftExploreMiniApp')
class ExploreMiniApps extends Table { class ExploreMiniApps extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('FavoriteMiniApp') @DataClassName('DriftFavoriteMiniApp')
class FavoriteMiniApps extends Table { class FavoriteMiniApps extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('FavouriteDetail') @DataClassName('DriftFavouriteDetail')
class FavouriteDetails extends Table { class FavouriteDetails extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
TextColumn get relatedId => text().withDefault(const Constant(''))(); TextColumn get relatedId => text().withDefault(const Constant(''))();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Favourite') @DataClassName('DriftFavourite')
class Favourites extends Table { class Favourites extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
TextColumn get parentId => text().withDefault(const Constant(''))(); TextColumn get parentId => text().withDefault(const Constant(''))();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Group') @DataClassName('DriftGroup')
class Groups extends Table { class Groups extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
IntColumn get userJoinDate => integer().nullable()(); IntColumn get userJoinDate => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Message') @DataClassName('DriftMessage')
class Messages extends Table { class Messages extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
IntColumn get messageId => integer().nullable()(); IntColumn get messageId => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('PendingFriendRequestHistory') @DataClassName('DriftPendingFriendRequestHistory')
class PendingFriendRequestHistories extends Table { class PendingFriendRequestHistories extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
IntColumn get uid => integer()(); IntColumn get uid => integer()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('RecentMiniApp') @DataClassName('DriftRecentMiniApp')
class RecentMiniApps extends Table { class RecentMiniApps extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Retry') @DataClassName('DriftRetry')
class Retries extends Table { class Retries extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()(); IntColumn get uid => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Sound') @DataClassName('DriftSound')
class Sounds extends Table { class Sounds extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
TextColumn get filePath => text().withDefault(const Constant(''))(); TextColumn get filePath => text().withDefault(const Constant(''))();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Tag') @DataClassName('DriftTag')
class Tags extends Table { class Tags extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()(); IntColumn get uid => integer().nullable()();

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('UserRequestHistory') @DataClassName('DriftUserRequestHistory')
class UserRequestHistories extends Table { class UserRequestHistories extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
IntColumn get status => integer().nullable()(); IntColumn get status => integer().nullable()();

View File

@@ -1,9 +1,9 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('User') @DataClassName('DriftUser')
class Users extends Table { class Users extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()(); IntColumn get uid => integer().unique()();
TextColumn get uuid => text().nullable()(); TextColumn get uuid => text().nullable()();
IntColumn get lastOnline => integer().nullable()(); IntColumn get lastOnline => integer().nullable()();
TextColumn get profilePic => text().nullable()(); TextColumn get profilePic => text().nullable()();
@@ -36,6 +36,7 @@ class Users extends Table {
TextColumn get publicKey => text().nullable()(); TextColumn get publicKey => text().nullable()();
IntColumn get configBits => integer().withDefault(const Constant(0))(); IntColumn get configBits => integer().withDefault(const Constant(0))();
TextColumn get hint => text().nullable()(); TextColumn get hint => text().nullable()();
@override @override
String get tableName => 'user'; String get tableName => 'user';
} }

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
@DataClassName('Workspace') @DataClassName('DriftWorkspace')
class Workspaces extends Table { class Workspaces extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
TextColumn get name => text().nullable()(); TextColumn get name => text().nullable()();

View File

@@ -0,0 +1,122 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/call_log.dart';
/// 通话记录 DTOData Transfer Object
///
/// local / remote 共用的数据传输对象。
/// 提供与 Domain Entity [CallLog] 之间的双向转换。
class CallLogDto {
final String id;
final int? callerId;
final int? receiverId;
final int? chatId;
final int? duration;
final int? videoCall;
final int? createdAt;
final int? updatedAt;
final int? endedAt;
final int? status;
final int? isDeleted;
final int? deletedAt;
final int? isRead;
const CallLogDto({
required this.id,
this.callerId,
this.receiverId,
this.chatId,
this.duration,
this.videoCall,
this.createdAt,
this.updatedAt,
this.endedAt,
this.status,
this.isDeleted,
this.deletedAt,
this.isRead,
});
factory CallLogDto.fromJson(Map<String, dynamic> json) => CallLogDto(
id: json['id'] as String,
callerId: json['caller_id'],
receiverId: json['receiver_id'],
chatId: json['chat_id'],
duration: json['duration'],
videoCall: json['video_call'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
endedAt: json['ended_at'],
status: json['status'],
isDeleted: json['is_deleted'],
deletedAt: json['deleted_at'],
isRead: json['is_read'],
);
Map<String, dynamic> toJson() => {
'id': id,
'caller_id': callerId,
'receiver_id': receiverId,
'chat_id': chatId,
'duration': duration,
'video_call': videoCall,
'created_at': createdAt,
'updated_at': updatedAt,
'ended_at': endedAt,
'status': status,
'is_deleted': isDeleted,
'deleted_at': deletedAt,
'is_read': isRead,
};
/// DTO → Domain Entity
CallLog toEntity() => CallLog(
id: id,
callerId: callerId,
receiverId: receiverId,
chatId: chatId,
duration: duration,
videoCall: videoCall,
createdAt: createdAt,
updatedAt: updatedAt,
endedAt: endedAt,
status: status,
isDeleted: isDeleted,
deletedAt: deletedAt,
isRead: isRead,
);
/// Domain Entity → DTO
factory CallLogDto.fromEntity(CallLog callLog) => CallLogDto(
id: callLog.id,
callerId: callLog.callerId,
receiverId: callLog.receiverId,
chatId: callLog.chatId,
duration: callLog.duration,
videoCall: callLog.videoCall,
createdAt: callLog.createdAt,
updatedAt: callLog.updatedAt,
endedAt: callLog.endedAt,
status: callLog.status,
isDeleted: callLog.isDeleted,
deletedAt: callLog.deletedAt,
isRead: callLog.isRead,
);
/// DTO → Drift Companion (for DB insert/update)
CallLogsCompanion toCompanion() => CallLogsCompanion(
id: Value(id),
callerId: Value(callerId),
receiverId: Value(receiverId),
chatId: Value(chatId),
duration: Value(duration),
videoCall: Value(videoCall),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
endedAt: Value(endedAt),
status: Value(status),
isDeleted: Value(isDeleted),
deletedAt: Value(deletedAt),
isRead: Value(isRead),
);
}

View File

@@ -0,0 +1,179 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/chat_bot.dart';
/// 聊天机器人 DTO
class ChatBotDto {
final int id;
final String? name;
final String? username;
final int? botUserId;
final String? icon;
final String? iconGaussian;
final String? description;
final String? token;
final int? flag;
final int? status;
final String? webhook;
final String? commands;
final String? banner;
final int? channelId;
final int? channelGroupId;
final int? deletedAt;
final String? internalWebhook;
final int? mode;
final String? redirectUrl;
final int? isInvitable;
final int? isAllowForward;
final String? tips;
const ChatBotDto({
required this.id,
this.name,
this.username,
this.botUserId,
this.icon,
this.iconGaussian,
this.description,
this.token,
this.flag,
this.status,
this.webhook,
this.commands,
this.banner,
this.channelId,
this.channelGroupId,
this.deletedAt,
this.internalWebhook,
this.mode,
this.redirectUrl,
this.isInvitable,
this.isAllowForward,
this.tips,
});
factory ChatBotDto.fromJson(Map<String, dynamic> json) => ChatBotDto(
id: json['id'] as int,
name: json['name'],
username: json['username'],
botUserId: json['bot_user_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
description: json['description'],
token: json['token'],
flag: json['flag'],
status: json['status'],
webhook: json['webhook'],
commands: json['commands'],
banner: json['banner'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
deletedAt: json['deleted_at'],
internalWebhook: json['internal_webhook'],
mode: json['mode'],
redirectUrl: json['redirect_url'],
isInvitable: json['is_invitable'],
isAllowForward: json['is_allow_forward'],
tips: json['tips'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'username': username,
'bot_user_id': botUserId,
'icon': icon,
'icon_gaussian': iconGaussian,
'description': description,
'token': token,
'flag': flag,
'status': status,
'webhook': webhook,
'commands': commands,
'banner': banner,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'deleted_at': deletedAt,
'internal_webhook': internalWebhook,
'mode': mode,
'redirect_url': redirectUrl,
'is_invitable': isInvitable,
'is_allow_forward': isAllowForward,
'tips': tips,
};
ChatBot toEntity() => ChatBot(
id: id,
name: name,
username: username,
botUserId: botUserId,
icon: icon,
iconGaussian: iconGaussian,
description: description,
token: token,
flag: flag,
status: status,
webhook: webhook,
commands: commands,
banner: banner,
channelId: channelId,
channelGroupId: channelGroupId,
deletedAt: deletedAt,
internalWebhook: internalWebhook,
mode: mode,
redirectUrl: redirectUrl,
isInvitable: isInvitable,
isAllowForward: isAllowForward,
tips: tips,
);
factory ChatBotDto.fromEntity(ChatBot chatBot) => ChatBotDto(
id: chatBot.id,
name: chatBot.name,
username: chatBot.username,
botUserId: chatBot.botUserId,
icon: chatBot.icon,
iconGaussian: chatBot.iconGaussian,
description: chatBot.description,
token: chatBot.token,
flag: chatBot.flag,
status: chatBot.status,
webhook: chatBot.webhook,
commands: chatBot.commands,
banner: chatBot.banner,
channelId: chatBot.channelId,
channelGroupId: chatBot.channelGroupId,
deletedAt: chatBot.deletedAt,
internalWebhook: chatBot.internalWebhook,
mode: chatBot.mode,
redirectUrl: chatBot.redirectUrl,
isInvitable: chatBot.isInvitable,
isAllowForward: chatBot.isAllowForward,
tips: chatBot.tips,
);
ChatBotsCompanion toCompanion() => ChatBotsCompanion(
id: Value(id),
name: Value(name),
username: Value(username),
botUserId: Value(botUserId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
description: Value(description),
token: Value(token),
flag: Value(flag),
status: Value(status),
webhook: Value(webhook ?? ''),
commands: Value(commands ?? '[]'),
banner: Value(banner),
channelId: Value(channelId),
channelGroupId: Value(channelGroupId),
deletedAt: Value(deletedAt),
internalWebhook: Value(internalWebhook),
mode: Value(mode),
redirectUrl: Value(redirectUrl),
isInvitable: Value(isInvitable),
isAllowForward: Value(isAllowForward),
tips: Value(tips),
);
}

View File

@@ -0,0 +1,90 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/chat_category.dart';
/// 聊天分类 DTO
class ChatCategoryDto {
final int id;
final String? name;
final String? includedChatIds;
final String? excludedChatIds;
final int? seq;
final int isHide;
final int createdAt;
final int updatedAt;
final int deletedAt;
const ChatCategoryDto({
required this.id,
this.name,
this.includedChatIds,
this.excludedChatIds,
this.seq,
this.isHide = 0,
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
});
factory ChatCategoryDto.fromJson(Map<String, dynamic> json) =>
ChatCategoryDto(
id: json['id'] as int,
name: json['name'],
includedChatIds: json['included_chat_ids'],
excludedChatIds: json['excluded_chat_ids'],
seq: json['seq'],
isHide: json['is_hide'] ?? 0,
createdAt: json['created_at'] ?? 0,
updatedAt: json['updated_at'] ?? 0,
deletedAt: json['deleted_at'] ?? 0,
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'included_chat_ids': includedChatIds,
'excluded_chat_ids': excludedChatIds,
'seq': seq,
'is_hide': isHide,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
};
ChatCategory toEntity() => ChatCategory(
id: id,
name: name,
includedChatIds: includedChatIds,
excludedChatIds: excludedChatIds,
seq: seq,
isHide: isHide,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
);
factory ChatCategoryDto.fromEntity(ChatCategory chatCategory) =>
ChatCategoryDto(
id: chatCategory.id,
name: chatCategory.name,
includedChatIds: chatCategory.includedChatIds,
excludedChatIds: chatCategory.excludedChatIds,
seq: chatCategory.seq,
isHide: chatCategory.isHide,
createdAt: chatCategory.createdAt,
updatedAt: chatCategory.updatedAt,
deletedAt: chatCategory.deletedAt,
);
ChatCategoriesCompanion toCompanion() => ChatCategoriesCompanion(
id: Value(id),
name: Value(name),
includedChatIds: Value(includedChatIds),
excludedChatIds: Value(excludedChatIds),
seq: Value(seq),
isHide: Value(isHide),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
);
}

View File

@@ -0,0 +1,200 @@
/// 聊天 Domain 实体
class Chat {
final int id;
final int? typ;
final int? lastId;
final int? lastTyp;
final String? lastMsg;
final int? lastTime;
final int lastPos;
final int firstPos;
final int? msgIdx;
final String? profile;
final String? pin;
final String? icon;
final String iconGaussian;
final String? name;
final int? userId;
final int? chatId;
final int? friendId;
final int? sort;
final int? unreadNum;
final int? unreadCount;
final int? hideChatMsgIdx;
final int? readChatMsgIdx;
final int? otherReadIdx;
final String? unreadAtMsgIdx;
final int? deleteTime;
final int? addIndex;
final int flag;
final int? flagMy;
final int? autoDeleteInterval;
final int? mute;
final int? verified;
final int? createTime;
final int? startIdx;
final int? isReadMsg;
final String translateOutgoing;
final String translateIncoming;
final int incomingIdx;
final int outgoingIdx;
final int incomingSoundId;
final int outgoingSoundId;
final int notificationSoundId;
final String chatKey;
final String activeChatKey;
final int coverIdx;
final int round;
final int workspaceId;
final int localPermission;
const Chat({
required this.id,
this.typ,
this.lastId,
this.lastTyp,
this.lastMsg,
this.lastTime,
this.lastPos = 0,
this.firstPos = -1,
this.msgIdx,
this.profile,
this.pin,
this.icon,
this.iconGaussian = '',
this.name,
this.userId,
this.chatId,
this.friendId,
this.sort,
this.unreadNum,
this.unreadCount,
this.hideChatMsgIdx,
this.readChatMsgIdx,
this.otherReadIdx,
this.unreadAtMsgIdx,
this.deleteTime,
this.addIndex,
this.flag = 0,
this.flagMy,
this.autoDeleteInterval,
this.mute,
this.verified,
this.createTime,
this.startIdx,
this.isReadMsg,
this.translateOutgoing = '',
this.translateIncoming = '',
this.incomingIdx = 0,
this.outgoingIdx = 0,
this.incomingSoundId = 0,
this.outgoingSoundId = 0,
this.notificationSoundId = 0,
this.chatKey = '',
this.activeChatKey = '',
this.coverIdx = 0,
this.round = 0,
this.workspaceId = 0,
this.localPermission = 0,
});
Chat copyWith({
int? id,
int? typ,
int? lastId,
int? lastTyp,
String? lastMsg,
int? lastTime,
int? lastPos,
int? firstPos,
int? msgIdx,
String? profile,
String? pin,
String? icon,
String? iconGaussian,
String? name,
int? userId,
int? chatId,
int? friendId,
int? sort,
int? unreadNum,
int? unreadCount,
int? hideChatMsgIdx,
int? readChatMsgIdx,
int? otherReadIdx,
String? unreadAtMsgIdx,
int? deleteTime,
int? addIndex,
int? flag,
int? flagMy,
int? autoDeleteInterval,
int? mute,
int? verified,
int? createTime,
int? startIdx,
int? isReadMsg,
String? translateOutgoing,
String? translateIncoming,
int? incomingIdx,
int? outgoingIdx,
int? incomingSoundId,
int? outgoingSoundId,
int? notificationSoundId,
String? chatKey,
String? activeChatKey,
int? coverIdx,
int? round,
int? workspaceId,
int? localPermission,
}) {
return Chat(
id: id ?? this.id,
typ: typ ?? this.typ,
lastId: lastId ?? this.lastId,
lastTyp: lastTyp ?? this.lastTyp,
lastMsg: lastMsg ?? this.lastMsg,
lastTime: lastTime ?? this.lastTime,
lastPos: lastPos ?? this.lastPos,
firstPos: firstPos ?? this.firstPos,
msgIdx: msgIdx ?? this.msgIdx,
profile: profile ?? this.profile,
pin: pin ?? this.pin,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
name: name ?? this.name,
userId: userId ?? this.userId,
chatId: chatId ?? this.chatId,
friendId: friendId ?? this.friendId,
sort: sort ?? this.sort,
unreadNum: unreadNum ?? this.unreadNum,
unreadCount: unreadCount ?? this.unreadCount,
hideChatMsgIdx: hideChatMsgIdx ?? this.hideChatMsgIdx,
readChatMsgIdx: readChatMsgIdx ?? this.readChatMsgIdx,
otherReadIdx: otherReadIdx ?? this.otherReadIdx,
unreadAtMsgIdx: unreadAtMsgIdx ?? this.unreadAtMsgIdx,
deleteTime: deleteTime ?? this.deleteTime,
addIndex: addIndex ?? this.addIndex,
flag: flag ?? this.flag,
flagMy: flagMy ?? this.flagMy,
autoDeleteInterval: autoDeleteInterval ?? this.autoDeleteInterval,
mute: mute ?? this.mute,
verified: verified ?? this.verified,
createTime: createTime ?? this.createTime,
startIdx: startIdx ?? this.startIdx,
isReadMsg: isReadMsg ?? this.isReadMsg,
translateOutgoing: translateOutgoing ?? this.translateOutgoing,
translateIncoming: translateIncoming ?? this.translateIncoming,
incomingIdx: incomingIdx ?? this.incomingIdx,
outgoingIdx: outgoingIdx ?? this.outgoingIdx,
incomingSoundId: incomingSoundId ?? this.incomingSoundId,
outgoingSoundId: outgoingSoundId ?? this.outgoingSoundId,
notificationSoundId: notificationSoundId ?? this.notificationSoundId,
chatKey: chatKey ?? this.chatKey,
activeChatKey: activeChatKey ?? this.activeChatKey,
coverIdx: coverIdx ?? this.coverIdx,
round: round ?? this.round,
workspaceId: workspaceId ?? this.workspaceId,
localPermission: localPermission ?? this.localPermission,
);
}
}

View File

@@ -0,0 +1,112 @@
/// 发现小程序 Domain 实体
class DiscoverMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final String? lastLoginAt;
final String? screen;
const DiscoverMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
DiscoverMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
String? lastLoginAt,
String? screen,
}) {
return DiscoverMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}

View File

@@ -0,0 +1,202 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/explore_mini_app.dart';
/// 探索小程序 DTO
class ExploreMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const ExploreMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory ExploreMiniAppDto.fromJson(Map<String, dynamic> json) =>
ExploreMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
ExploreMiniApp toEntity() => ExploreMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory ExploreMiniAppDto.fromEntity(ExploreMiniApp app) =>
ExploreMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
ExploreMiniAppsCompanion toCompanion() => ExploreMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}

View File

@@ -0,0 +1,202 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favorite_mini_app.dart';
/// 收藏小程序 DTO
class FavoriteMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const FavoriteMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory FavoriteMiniAppDto.fromJson(Map<String, dynamic> json) =>
FavoriteMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
FavoriteMiniApp toEntity() => FavoriteMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory FavoriteMiniAppDto.fromEntity(FavoriteMiniApp app) =>
FavoriteMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
FavoriteMiniAppsCompanion toCompanion() => FavoriteMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}

View File

@@ -0,0 +1,83 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favourite_detail.dart';
/// 收藏详情 DTO
class FavouriteDetailDto {
final int? id;
final String relatedId;
final String content;
final int? typ;
final int? messageId;
final int? sendId;
final int? chatId;
final int? sendTime;
const FavouriteDetailDto({
this.id,
this.relatedId = '',
this.content = '',
this.typ,
this.messageId,
this.sendId,
this.chatId,
this.sendTime,
});
factory FavouriteDetailDto.fromJson(Map<String, dynamic> json) =>
FavouriteDetailDto(
id: json['id'],
relatedId: json['related_id'] ?? '',
content: json['content'] ?? '',
typ: json['typ'],
messageId: json['messageId'],
sendId: json['sendId'],
chatId: json['chatId'],
sendTime: json['sendTime'],
);
Map<String, dynamic> toJson() => {
'id': id,
'related_id': relatedId,
'content': content,
'typ': typ,
'messageId': messageId,
'sendId': sendId,
'chatId': chatId,
'sendTime': sendTime,
};
FavouriteDetail toEntity() => FavouriteDetail(
id: id,
relatedId: relatedId,
content: content,
typ: typ,
messageId: messageId,
sendId: sendId,
chatId: chatId,
sendTime: sendTime,
);
factory FavouriteDetailDto.fromEntity(FavouriteDetail detail) =>
FavouriteDetailDto(
id: detail.id,
relatedId: detail.relatedId,
content: detail.content,
typ: detail.typ,
messageId: detail.messageId,
sendId: detail.sendId,
chatId: detail.chatId,
sendTime: detail.sendTime,
);
FavouriteDetailsCompanion toCompanion() => FavouriteDetailsCompanion(
id: id != null ? Value(id!) : const Value.absent(),
relatedId: Value(relatedId),
content: Value(content),
typ: Value(typ),
messageId: Value(messageId),
sendId: Value(sendId),
chatId: Value(chatId),
sendTime: Value(sendTime),
);
}

View File

@@ -0,0 +1,130 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favourite.dart';
/// 收藏 DTO
class FavouriteDto {
final int id;
final String parentId;
final String data;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int? source;
final int? userId;
final int? authorId;
final String typ;
final String tag;
final int isPin;
final int chatTyp;
final int isUploaded;
final String urls;
const FavouriteDto({
required this.id,
this.parentId = '',
this.data = '',
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
this.source,
this.userId,
this.authorId,
this.typ = '[]',
this.tag = '[]',
this.isPin = 0,
this.chatTyp = 0,
this.isUploaded = 1,
this.urls = '[]',
});
factory FavouriteDto.fromJson(Map<String, dynamic> json) => FavouriteDto(
id: json['id'] as int,
parentId: json['parent_id'] ?? '',
data: json['data'] ?? '',
createdAt: json['created_at'] ?? 0,
updatedAt: json['updated_at'] ?? 0,
deletedAt: json['deleted_at'] ?? 0,
source: json['source'],
userId: json['user_id'],
authorId: json['author_id'],
typ: json['typ'] ?? '[]',
tag: json['tag'] ?? '[]',
isPin: json['is_pin'] ?? 0,
chatTyp: json['chat_typ'] ?? 0,
isUploaded: json['is_uploaded'] ?? 1,
urls: json['urls'] ?? '[]',
);
Map<String, dynamic> toJson() => {
'id': id,
'parent_id': parentId,
'data': data,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'source': source,
'user_id': userId,
'author_id': authorId,
'typ': typ,
'tag': tag,
'is_pin': isPin,
'chat_typ': chatTyp,
'is_uploaded': isUploaded,
'urls': urls,
};
Favourite toEntity() => Favourite(
id: id,
parentId: parentId,
data: data,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
source: source,
userId: userId,
authorId: authorId,
typ: typ,
tag: tag,
isPin: isPin,
chatTyp: chatTyp,
isUploaded: isUploaded,
urls: urls,
);
factory FavouriteDto.fromEntity(Favourite favourite) => FavouriteDto(
id: favourite.id,
parentId: favourite.parentId,
data: favourite.data,
createdAt: favourite.createdAt,
updatedAt: favourite.updatedAt,
deletedAt: favourite.deletedAt,
source: favourite.source,
userId: favourite.userId,
authorId: favourite.authorId,
typ: favourite.typ,
tag: favourite.tag,
isPin: favourite.isPin,
chatTyp: favourite.chatTyp,
isUploaded: favourite.isUploaded,
urls: favourite.urls,
);
FavouritesCompanion toCompanion() => FavouritesCompanion(
id: Value(id),
parentId: Value(parentId),
data: Value(data),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
source: Value(source),
userId: Value(userId),
authorId: Value(authorId),
typ: Value(typ),
tag: Value(tag),
isPin: Value(isPin),
chatTyp: Value(chatTyp),
isUploaded: Value(isUploaded),
urls: Value(urls),
);
}

View File

@@ -0,0 +1,221 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/group.dart';
/// 群组 DTO
class GroupDto {
final int id;
final int? userJoinDate;
final String? name;
final String? profile;
final String? icon;
final String iconGaussian;
final int? permission;
final int? admin;
final String? members;
final int? owner;
final String? admins;
final int? visible;
final int? speakInterval;
final int? groupType;
final int? roomType;
final int? maxNumber;
final int? channelId;
final int? channelGroupId;
final int? createTime;
final int? updateTime;
final int? addIndex;
final int? maxMember;
final int? expireTime;
final int workspaceId;
final int mode;
final int redpacketPlay;
final String? topic;
final String? rp;
const GroupDto({
required this.id,
this.userJoinDate,
this.name,
this.profile,
this.icon,
this.iconGaussian = '',
this.permission,
this.admin,
this.members,
this.owner,
this.admins,
this.visible,
this.speakInterval,
this.groupType,
this.roomType,
this.maxNumber,
this.channelId,
this.channelGroupId,
this.createTime,
this.updateTime,
this.addIndex,
this.maxMember,
this.expireTime,
this.workspaceId = 0,
this.mode = 0,
this.redpacketPlay = 0,
this.topic,
this.rp,
});
factory GroupDto.fromJson(Map<String, dynamic> json) => GroupDto(
id: json['id'] as int,
userJoinDate: json['user_join_date'],
name: json['name'],
profile: json['profile'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'] ?? '',
permission: json['permission'],
admin: json['admin'],
members: json['members'],
owner: json['owner'],
admins: json['admins'],
visible: json['visible'],
speakInterval: json['speak_interval'],
groupType: json['group_type'],
roomType: json['room_type'],
maxNumber: json['max_number'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
createTime: json['create_time'],
updateTime: json['update_time'],
addIndex: json['__add_index'],
maxMember: json['max_member'],
expireTime: json['expire_time'],
workspaceId: json['workspace_id'] ?? 0,
mode: json['mode'] ?? 0,
redpacketPlay: json['redpacket_play'] ?? 0,
topic: json['topic'],
rp: json['rp'],
);
Map<String, dynamic> toJson() => {
'id': id,
'user_join_date': userJoinDate,
'name': name,
'profile': profile,
'icon': icon,
'icon_gaussian': iconGaussian,
'permission': permission,
'admin': admin,
'members': members,
'owner': owner,
'admins': admins,
'visible': visible,
'speak_interval': speakInterval,
'group_type': groupType,
'room_type': roomType,
'max_number': maxNumber,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'create_time': createTime,
'update_time': updateTime,
'__add_index': addIndex,
'max_member': maxMember,
'expire_time': expireTime,
'workspace_id': workspaceId,
'mode': mode,
'redpacket_play': redpacketPlay,
'topic': topic,
'rp': rp,
};
Group toEntity() => Group(
id: id,
userJoinDate: userJoinDate,
name: name,
profile: profile,
icon: icon,
iconGaussian: iconGaussian,
permission: permission,
admin: admin,
members: members,
owner: owner,
admins: admins,
visible: visible,
speakInterval: speakInterval,
groupType: groupType,
roomType: roomType,
maxNumber: maxNumber,
channelId: channelId,
channelGroupId: channelGroupId,
createTime: createTime,
updateTime: updateTime,
addIndex: addIndex,
maxMember: maxMember,
expireTime: expireTime,
workspaceId: workspaceId,
mode: mode,
redpacketPlay: redpacketPlay,
topic: topic,
rp: rp,
);
factory GroupDto.fromEntity(Group group) => GroupDto(
id: group.id,
userJoinDate: group.userJoinDate,
name: group.name,
profile: group.profile,
icon: group.icon,
iconGaussian: group.iconGaussian,
permission: group.permission,
admin: group.admin,
members: group.members,
owner: group.owner,
admins: group.admins,
visible: group.visible,
speakInterval: group.speakInterval,
groupType: group.groupType,
roomType: group.roomType,
maxNumber: group.maxNumber,
channelId: group.channelId,
channelGroupId: group.channelGroupId,
createTime: group.createTime,
updateTime: group.updateTime,
addIndex: group.addIndex,
maxMember: group.maxMember,
expireTime: group.expireTime,
workspaceId: group.workspaceId,
mode: group.mode,
redpacketPlay: group.redpacketPlay,
topic: group.topic,
rp: group.rp,
);
GroupsCompanion toCompanion() => GroupsCompanion(
id: Value(id),
userJoinDate: Value(userJoinDate),
name: Value(name),
profile: Value(profile),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
permission: Value(permission),
admin: Value(admin),
members: Value(members),
owner: Value(owner),
admins: Value(admins),
visible: Value(visible),
speakInterval: Value(speakInterval),
groupType: Value(groupType),
roomType: Value(roomType),
maxNumber: Value(maxNumber),
channelId: Value(channelId),
channelGroupId: Value(channelGroupId),
createTime: Value(createTime),
updateTime: Value(updateTime),
addIndex: Value(addIndex),
maxMember: Value(maxMember),
expireTime: Value(expireTime),
workspaceId: Value(workspaceId),
mode: Value(mode),
redpacketPlay: Value(redpacketPlay),
topic: Value(topic),
rp: Value(rp),
);
}

View File

@@ -0,0 +1,137 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/message.dart';
/// 消息 DTO
class MessageDto {
final int id;
final int? messageId;
final int? chatId;
final int? chatIdx;
final int? sendId;
final String? content;
final int? typ;
final int? sendTime;
final int? expireTime;
final int? createTime;
final String? atUsers;
final String emojis;
final int editTime;
final int refTyp;
final int flag;
final String cmid;
const MessageDto({
required this.id,
this.messageId,
this.chatId,
this.chatIdx,
this.sendId,
this.content,
this.typ,
this.sendTime,
this.expireTime,
this.createTime,
this.atUsers,
this.emojis = '[]',
this.editTime = 0,
this.refTyp = 0,
this.flag = 0,
this.cmid = '',
});
factory MessageDto.fromJson(Map<String, dynamic> json) => MessageDto(
id: json['id'] as int,
messageId: json['message_id'],
chatId: json['chat_id'],
chatIdx: json['chat_idx'],
sendId: json['send_id'],
content: json['content'],
typ: json['typ'],
sendTime: json['send_time'],
expireTime: json['expire_time'],
createTime: json['create_time'],
atUsers: json['at_users'],
emojis: json['emojis'] ?? '[]',
editTime: json['edit_time'] ?? 0,
refTyp: json['ref_typ'] ?? 0,
flag: json['flag'] ?? 0,
cmid: json['cmid'] ?? '',
);
Map<String, dynamic> toJson() => {
'id': id,
'message_id': messageId,
'chat_id': chatId,
'chat_idx': chatIdx,
'send_id': sendId,
'content': content,
'typ': typ,
'send_time': sendTime,
'expire_time': expireTime,
'create_time': createTime,
'at_users': atUsers,
'emojis': emojis,
'edit_time': editTime,
'ref_typ': refTyp,
'flag': flag,
'cmid': cmid,
};
Message toEntity() => Message(
id: id,
messageId: messageId,
chatId: chatId,
chatIdx: chatIdx,
sendId: sendId,
content: content,
typ: typ,
sendTime: sendTime,
expireTime: expireTime,
createTime: createTime,
atUsers: atUsers,
emojis: emojis,
editTime: editTime,
refTyp: refTyp,
flag: flag,
cmid: cmid,
);
factory MessageDto.fromEntity(Message message) => MessageDto(
id: message.id,
messageId: message.messageId,
chatId: message.chatId,
chatIdx: message.chatIdx,
sendId: message.sendId,
content: message.content,
typ: message.typ,
sendTime: message.sendTime,
expireTime: message.expireTime,
createTime: message.createTime,
atUsers: message.atUsers,
emojis: message.emojis,
editTime: message.editTime,
refTyp: message.refTyp,
flag: message.flag,
cmid: message.cmid,
);
MessagesCompanion toCompanion() => MessagesCompanion(
id: Value(id),
messageId: Value(messageId),
chatId: Value(chatId),
chatIdx: Value(chatIdx),
sendId: Value(sendId),
content: Value(content),
typ: Value(typ),
sendTime: Value(sendTime),
expireTime: Value(expireTime),
createTime: Value(createTime),
atUsers: Value(atUsers),
emojis: Value(emojis),
editTime: Value(editTime),
refTyp: Value(refTyp),
flag: Value(flag),
cmid: Value(cmid),
);
}

View File

@@ -0,0 +1,71 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/pending_friend_request_history.dart';
/// 待处理好友请求历史 DTO
class PendingFriendRequestHistoryDto {
final int id;
final int uid;
final int requestTime;
final String? remarks;
final String? source;
final int? rs;
const PendingFriendRequestHistoryDto({
required this.id,
required this.uid,
required this.requestTime,
this.remarks,
this.source,
this.rs,
});
factory PendingFriendRequestHistoryDto.fromJson(Map<String, dynamic> json) =>
PendingFriendRequestHistoryDto(
id: json['id'] as int,
uid: json['uid'] as int,
requestTime: json['request_time'] as int,
remarks: json['remarks'],
source: json['source'],
rs: json['rs'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'request_time': requestTime,
'remarks': remarks,
'source': source,
'rs': rs,
};
PendingFriendRequestHistory toEntity() => PendingFriendRequestHistory(
id: id,
uid: uid,
requestTime: requestTime,
remarks: remarks,
source: source,
rs: rs,
);
factory PendingFriendRequestHistoryDto.fromEntity(
PendingFriendRequestHistory history) =>
PendingFriendRequestHistoryDto(
id: history.id,
uid: history.uid,
requestTime: history.requestTime,
remarks: history.remarks,
source: history.source,
rs: history.rs,
);
PendingFriendRequestHistoriesCompanion toCompanion() =>
PendingFriendRequestHistoriesCompanion(
id: Value(id),
uid: Value(uid),
requestTime: Value(requestTime),
remarks: Value(remarks),
source: Value(source),
rs: Value(rs),
);
}

View File

@@ -0,0 +1,201 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/recent_mini_app.dart';
/// 最近小程序 DTO
class RecentMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const RecentMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory RecentMiniAppDto.fromJson(Map<String, dynamic> json) =>
RecentMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
RecentMiniApp toEntity() => RecentMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory RecentMiniAppDto.fromEntity(RecentMiniApp app) => RecentMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
RecentMiniAppsCompanion toCompanion() => RecentMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}

View File

@@ -0,0 +1,109 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/retry.dart';
/// 重试 DTO
class RetryDto {
final int? id;
final int? uid;
final String apiType;
final String endPoint;
final String requestData;
final int? synced;
final String callbackFun;
final int? expired;
final int? replace;
final int? expireTime;
final int? createTime;
final int? addIndex;
const RetryDto({
this.id,
this.uid,
this.apiType = '',
this.endPoint = '',
this.requestData = '',
this.synced,
this.callbackFun = '',
this.expired,
this.replace,
this.expireTime,
this.createTime,
this.addIndex,
});
factory RetryDto.fromJson(Map<String, dynamic> json) => RetryDto(
id: json['id'],
uid: json['uid'],
apiType: json['api_type'] ?? '',
endPoint: json['end_point'] ?? '',
requestData: json['request_data'] ?? '',
synced: json['synced'],
callbackFun: json['callback_fun'] ?? '',
expired: json['expired'],
replace: json['replace'],
expireTime: json['expire_time'],
createTime: json['create_time'],
addIndex: json['__add_index'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'api_type': apiType,
'end_point': endPoint,
'request_data': requestData,
'synced': synced,
'callback_fun': callbackFun,
'expired': expired,
'replace': replace,
'expire_time': expireTime,
'create_time': createTime,
'__add_index': addIndex,
};
Retry toEntity() => Retry(
id: id,
uid: uid,
apiType: apiType,
endPoint: endPoint,
requestData: requestData,
synced: synced,
callbackFun: callbackFun,
expired: expired,
replace: replace,
expireTime: expireTime,
createTime: createTime,
addIndex: addIndex,
);
factory RetryDto.fromEntity(Retry retry) => RetryDto(
id: retry.id,
uid: retry.uid,
apiType: retry.apiType,
endPoint: retry.endPoint,
requestData: retry.requestData,
synced: retry.synced,
callbackFun: retry.callbackFun,
expired: retry.expired,
replace: retry.replace,
expireTime: retry.expireTime,
createTime: retry.createTime,
addIndex: retry.addIndex,
);
RetriesCompanion toCompanion() => RetriesCompanion(
id: id != null ? Value(id!) : const Value.absent(),
uid: Value(uid),
apiType: Value(apiType),
endPoint: Value(endPoint),
requestData: Value(requestData),
synced: Value(synced),
callbackFun: Value(callbackFun),
expired: Value(expired),
replace: Value(replace),
expireTime: Value(expireTime),
createTime: Value(createTime),
addIndex: Value(addIndex),
);
}

View File

@@ -0,0 +1,88 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/sound.dart';
/// 音效 DTO
class SoundDto {
final int id;
final String filePath;
final int typ;
final String name;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int channelGroupId;
final int isDefault;
const SoundDto({
required this.id,
this.filePath = '',
required this.typ,
this.name = '',
required this.createdAt,
required this.updatedAt,
this.deletedAt = 0,
required this.channelGroupId,
required this.isDefault,
});
factory SoundDto.fromJson(Map<String, dynamic> json) => SoundDto(
id: json['id'] as int,
filePath: json['file_path'] ?? '',
typ: json['typ'] as int,
name: json['name'] ?? '',
createdAt: json['created_at'] as int,
updatedAt: json['updated_at'] as int,
deletedAt: json['deleted_at'] ?? 0,
channelGroupId: json['channel_group_id'] as int,
isDefault: json['is_default'] as int,
);
Map<String, dynamic> toJson() => {
'id': id,
'file_path': filePath,
'typ': typ,
'name': name,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'channel_group_id': channelGroupId,
'is_default': isDefault,
};
Sound toEntity() => Sound(
id: id,
filePath: filePath,
typ: typ,
name: name,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
channelGroupId: channelGroupId,
isDefault: isDefault,
);
factory SoundDto.fromEntity(Sound sound) => SoundDto(
id: sound.id,
filePath: sound.filePath,
typ: sound.typ,
name: sound.name,
createdAt: sound.createdAt,
updatedAt: sound.updatedAt,
deletedAt: sound.deletedAt,
channelGroupId: sound.channelGroupId,
isDefault: sound.isDefault,
);
SoundsCompanion toCompanion() => SoundsCompanion(
id: Value(id),
filePath: Value(filePath),
typ: Value(typ),
name: Value(name),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
channelGroupId: Value(channelGroupId),
isDefault: Value(isDefault),
);
}

View File

@@ -0,0 +1,74 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/tag.dart';
/// 标签 DTO
class TagDto {
final int? id;
final int? uid;
final String name;
final int? type;
final int? createdAt;
final int? updatedAt;
final int? addIndex;
const TagDto({
this.id,
this.uid,
this.name = '',
this.type,
this.createdAt,
this.updatedAt,
this.addIndex,
});
factory TagDto.fromJson(Map<String, dynamic> json) => TagDto(
id: json['id'],
uid: json['uid'],
name: json['name'] ?? '',
type: json['type'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
addIndex: json['__add_index'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'name': name,
'type': type,
'created_at': createdAt,
'updated_at': updatedAt,
'__add_index': addIndex,
};
Tag toEntity() => Tag(
id: id,
uid: uid,
name: name,
type: type,
createdAt: createdAt,
updatedAt: updatedAt,
addIndex: addIndex,
);
factory TagDto.fromEntity(Tag tag) => TagDto(
id: tag.id,
uid: tag.uid,
name: tag.name,
type: tag.type,
createdAt: tag.createdAt,
updatedAt: tag.updatedAt,
addIndex: tag.addIndex,
);
TagsCompanion toCompanion() => TagsCompanion(
id: id != null ? Value(id!) : const Value.absent(),
uid: Value(uid),
name: Value(name),
type: Value(type),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
addIndex: Value(addIndex),
);
}

View File

@@ -1,68 +1,148 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import '../../domain/entities/user.dart'; import 'package:im_app/domain/entities/user.dart';
part 'user_dto.g.dart';
/// 用户 DTOData Transfer Object /// 用户 DTOData Transfer Object
/// ///
/// local / remote 共用的数据传输对象,放在 data/models/。 /// local / remote 共用的数据传输对象,放在 data/models/。
/// 提供与 Domain Entity [User] 之间的双向转换。 /// 提供与 Domain Entity [User] 之间的双向转换。
///
/// ## 数据流位置(本地存储场景)
///
/// ```
/// 写入本地:
/// LoginData.toEntity() → User
/// → UserDto.fromEntity(user) → ★ UserDto ★ ← 你在这里
/// → toJson() → SQLite / SharedPreferences
///
/// 读取本地:
/// SQLite / SharedPreferences → JSON
/// → ★ UserDto.fromJson() ★ ← 你在这里
/// → UserDto.toEntity() → User
/// → ViewModel.state → View
/// ```
///
/// 注意:登录接口的 Response DTO 是 [LoginData](含 token
/// 本类用于纯用户信息的本地持久化,不含 token。
@JsonSerializable()
class UserDto { class UserDto {
@JsonKey(name: 'user_id') final int uid;
final String userId; final String? uuid;
final String email; final int? lastOnline;
final String? profilePic;
final String? profilePicGaussian;
final String? nickname; final String? nickname;
final String? avatar; final String? contact;
final String? countryCode;
final String? email;
final String? recoveryEmail;
final String? username;
final String? bio;
final int? relationship;
final String? userAlias;
final int? channelId;
final int? channelGroupId;
final String? hint;
const UserDto({ const UserDto({
required this.userId, required this.uid,
required this.email, this.uuid,
this.lastOnline,
this.profilePic,
this.profilePicGaussian,
this.nickname, this.nickname,
this.avatar, this.contact,
this.countryCode,
this.email,
this.recoveryEmail,
this.username,
this.bio,
this.relationship,
this.userAlias,
this.channelId,
this.channelGroupId,
this.hint,
}); });
factory UserDto.fromJson(Map<String, dynamic> json) => factory UserDto.fromJson(Map<String, dynamic> json) => UserDto(
_$UserDtoFromJson(json); uid: json['uid'] as int,
uuid: json['uuid'],
lastOnline: json['last_online'],
profilePic: json['profile_pic'],
profilePicGaussian: json['profile_pic_gaussian'] ?? '',
nickname: json['nickname'],
contact: json['contact'],
countryCode: json['country_code'],
email: json['email'],
recoveryEmail: json['recovery_email'] ?? '',
username: json['username'],
bio: json['bio'] ?? '',
relationship: json['relationship'],
userAlias: json['user_alias'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
hint: json['hint'],
);
Map<String, dynamic> toJson() => _$UserDtoToJson(this); Map<String, dynamic> toJson() => {
'uid': uid,
'uuid': uuid,
'last_online': lastOnline,
'profile_pic': profilePic,
'profile_pic_gaussian': profilePicGaussian,
'nickname': nickname,
'contact': contact,
'country_code': countryCode,
'email': email,
'recovery_email': recoveryEmail,
'username': username,
'bio': bio,
'relationship': relationship,
'user_alias': userAlias,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'hint': hint,
};
/// DTO → Domain Entity /// DTO → Domain Entity
User toEntity() { User toEntity() => User(
return User( uid: uid,
id: userId, uuid: uuid,
email: email, lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname, nickname: nickname,
avatar: avatar, contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
); );
}
/// Domain Entity → DTO /// Domain Entity → DTO
factory UserDto.fromEntity(User user) { factory UserDto.fromEntity(User user) => UserDto(
return UserDto( uid: user.uid,
userId: user.id, uuid: user.uuid,
email: user.email, lastOnline: user.lastOnline,
profilePic: user.profilePic,
profilePicGaussian: user.profilePicGaussian,
nickname: user.nickname, nickname: user.nickname,
avatar: user.avatar, contact: user.contact,
countryCode: user.countryCode,
email: user.email,
recoveryEmail: user.recoveryEmail,
username: user.username,
bio: user.bio,
relationship: user.relationship,
userAlias: user.userAlias,
channelId: user.channelId,
channelGroupId: user.channelGroupId,
hint: user.hint,
);
/// DTO → Drift Companion (for DB insert/update)
UsersCompanion toCompanion() => UsersCompanion(
uid: Value(uid),
uuid: Value(uuid),
lastOnline: Value(lastOnline),
profilePic: Value(profilePic),
profilePicGaussian: Value(profilePicGaussian ?? ''),
nickname: Value(nickname),
contact: Value(contact),
countryCode: Value(countryCode),
email: Value(email),
recoveryEmail: Value(recoveryEmail),
username: Value(username),
bio: Value(bio),
relationship: Value(relationship),
userAlias: Value(userAlias),
hint: Value(hint),
); );
}
} }

View File

@@ -0,0 +1,49 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/user_request_history.dart';
/// 用户请求历史 DTO
class UserRequestHistoryDto {
final int id;
final int? status;
final int? createdAt;
const UserRequestHistoryDto({
required this.id,
this.status,
this.createdAt,
});
factory UserRequestHistoryDto.fromJson(Map<String, dynamic> json) =>
UserRequestHistoryDto(
id: json['id'] as int,
status: json['status'],
createdAt: json['created_at'],
);
Map<String, dynamic> toJson() => {
'id': id,
'status': status,
'created_at': createdAt,
};
UserRequestHistory toEntity() => UserRequestHistory(
id: id,
status: status,
createdAt: createdAt,
);
factory UserRequestHistoryDto.fromEntity(UserRequestHistory history) =>
UserRequestHistoryDto(
id: history.id,
status: history.status,
createdAt: history.createdAt,
);
UserRequestHistoriesCompanion toCompanion() =>
UserRequestHistoriesCompanion(
id: Value(id),
status: Value(status),
createdAt: Value(createdAt),
);
}

View File

@@ -0,0 +1,116 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/workspace.dart';
/// 工作空间 DTO
class WorkspaceDto {
final int id;
final String? name;
final int? ownerId;
final String? description;
final String? logo;
final int? grade;
final int? cap;
final String? currency;
final int? status;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final int? channelGroupId;
const WorkspaceDto({
required this.id,
this.name,
this.ownerId,
this.description,
this.logo,
this.grade,
this.cap,
this.currency,
this.status,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.channelGroupId,
});
factory WorkspaceDto.fromJson(Map<String, dynamic> json) => WorkspaceDto(
id: json['id'] as int,
name: json['name'],
ownerId: json['owner_id'],
description: json['description'],
logo: json['logo'],
grade: json['grade'],
cap: json['cap'],
currency: json['currency'],
status: json['status'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
channelGroupId: json['channel_group_id'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'owner_id': ownerId,
'description': description,
'logo': logo,
'grade': grade,
'cap': cap,
'currency': currency,
'status': status,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'channel_group_id': channelGroupId,
};
Workspace toEntity() => Workspace(
id: id,
name: name,
ownerId: ownerId,
description: description,
logo: logo,
grade: grade,
cap: cap,
currency: currency,
status: status,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
channelGroupId: channelGroupId,
);
factory WorkspaceDto.fromEntity(Workspace workspace) => WorkspaceDto(
id: workspace.id,
name: workspace.name,
ownerId: workspace.ownerId,
description: workspace.description,
logo: workspace.logo,
grade: workspace.grade,
cap: workspace.cap,
currency: workspace.currency,
status: workspace.status,
createdAt: workspace.createdAt,
updatedAt: workspace.updatedAt,
deletedAt: workspace.deletedAt,
channelGroupId: workspace.channelGroupId,
);
WorkspacesCompanion toCompanion() => WorkspacesCompanion(
id: Value(id),
name: Value(name),
ownerId: Value(ownerId),
description: Value(description),
logo: Value(logo),
grade: Value(grade),
cap: Value(cap),
currency: Value(currency),
status: Value(status),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
channelGroupId: Value(channelGroupId),
);
}

View File

@@ -28,31 +28,75 @@ part 'get_profile_request.g.dart';
/// 用户资料响应 DTO只需反序列化禁止生成无用的 toJson /// 用户资料响应 DTO只需反序列化禁止生成无用的 toJson
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class ProfileData { class ProfileData {
@JsonKey(name: 'user_id') final int uid;
final String userId; 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; final String email;
final String? nickname; @JsonKey(name: 'recovery_email')
final String? avatar; 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 ProfileData({ const ProfileData({
required this.userId, 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.email,
this.nickname, required this.recoveryEmail,
this.avatar, required this.username,
required this.bio,
required this.relationship,
this.userAlias,
required this.channelId,
required this.channelGroupId,
required this.hint,
}); });
factory ProfileData.fromJson(Map<String, dynamic> json) => factory ProfileData.fromJson(Map<String, dynamic> json) =>
_$ProfileDataFromJson(json); _$ProfileDataFromJson(json);
/// DTO → Domain Entity /// DTO → Domain Entity
User toEntity() { User toEntity() => User(
return User( uid: uid,
id: userId, uuid: uuid,
email: email, lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname, nickname: nickname,
avatar: avatar, contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
); );
}
} }
// ───────────────────────────────────────────── // ─────────────────────────────────────────────

View File

@@ -8,75 +8,155 @@ part 'login_request.g.dart';
/// # /auth/login — 登录接口 /// # /auth/login — 登录接口
/// ///
/// 一个端点 = 一个文件Response DTO + Request 放在同一文件中。
///
/// ## 数据流位置 /// ## 数据流位置
/// ///
/// ``` /// ```
/// AuthRepositoryImpl.login(email, password) /// AuthRepositoryImpl.login(email, password)
/// → _client.executeRequest( ★ LoginRequest ★ ) ← 你在这里 /// → _client.executeRequest( ★ LoginRequest ★ ) ← 你在这里
/// → 服务端 POST /auth/login /// → 服务端 POST /auth/login
/// → 响应 JSON → ★ LoginData ★ ← 也在这里 /// → 响应 JSON → ★ LoginResponse ★ ← 也在这里
/// → LoginData.toEntity() → User /// → LoginResponse.toEntity() → User
/// ``` /// ```
// ───────────────────────────────────────────── // ─────────────────────────────────────────────
// Response DTO // Response DTO
// ───────────────────────────────────────────── // ─────────────────────────────────────────────
/// 登录响应 DTO @JsonSerializable(createToJson: false)
/// class LoginProfile {
/// 服务端返回的登录数据,包含 token 和用户信息。 final int uid;
/// 通过 [toEntity] 转换为 Domain Entity [User]。 final String uuid;
@JsonSerializable() @JsonKey(name: 'last_online')
class LoginData { final int lastOnline;
final String token; @JsonKey(name: 'profile_pic')
@JsonKey(name: 'user_id') final String profilePic;
final String userId; @JsonKey(name: 'profile_pic_gaussian')
final String profilePicGaussian;
final String nickname;
final String contact;
@JsonKey(name: 'country_code')
final String countryCode;
final String email; final String email;
final String? nickname; @JsonKey(name: 'recovery_email')
final String? avatar; 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 LoginProfile({
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 LoginProfile.fromJson(Map<String, dynamic> json) =>
_$LoginProfileFromJson(json);
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,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
);
}
@JsonSerializable(createToJson: false, explicitToJson: true)
class LoginData {
@JsonKey(name: 'account_id')
final String accountId;
final LoginProfile profile;
final String nonce;
@JsonKey(name: 'access_token')
final String accessToken;
@JsonKey(name: 'refresh_token')
final String refreshToken;
@JsonKey(name: 'device_id')
final String deviceId;
@JsonKey(name: 'login_data')
final String loginData;
const LoginData({ const LoginData({
required this.token, required this.accountId,
required this.userId, required this.profile,
required this.email, required this.nonce,
this.nickname, required this.accessToken,
this.avatar, required this.refreshToken,
required this.deviceId,
required this.loginData,
}); });
factory LoginData.fromJson(Map<String, dynamic> json) => factory LoginData.fromJson(Map<String, dynamic> json) =>
_$LoginDataFromJson(json); _$LoginDataFromJson(json);
Map<String, dynamic> toJson() => _$LoginDataToJson(this); User toEntity() => profile.toEntity();
}
/// DTO → Domain Entity /// Top-level envelope: { "code": 0, "message": "OK", "data": { ... } }
User toEntity() { @JsonSerializable(createToJson: false, explicitToJson: true)
return User( class LoginResponse {
id: userId, final int code;
email: email, final String message;
nickname: nickname, final LoginData data;
avatar: avatar,
); const LoginResponse({
} required this.code,
required this.message,
required this.data,
});
factory LoginResponse.fromJson(Map<String, dynamic> json) =>
_$LoginResponseFromJson(json);
User toEntity() => data.toEntity();
} }
// ───────────────────────────────────────────── // ─────────────────────────────────────────────
// Request // Request
// ───────────────────────────────────────────── // ─────────────────────────────────────────────
/// 登录请求
///
/// `@ApiRequest` 自动生成 `_$LoginRequestApi` mixin
/// 提供 path / method / requestType / includeToken / fromJson 自动注册。
@ApiRequest( @ApiRequest(
path: ApiPaths.authLogin, path: ApiPaths.authLogin,
method: HttpMethod.post, method: HttpMethod.post,
responseType: LoginData, responseType: LoginResponse,
requestType: ApiRequestType.login, requestType: ApiRequestType.login,
) )
@JsonSerializable() @JsonSerializable()
class LoginRequest extends ApiRequestable<LoginData> with _$LoginRequestApi { class LoginRequest extends ApiRequestable<LoginResponse>
with _$LoginRequestApi {
final String email; final String email;
final String password; final String password;

View File

@@ -30,18 +30,18 @@ class AuthRepositoryImpl implements AuthRepository {
AuthRepositoryImpl({required NetworksSdkApi client, required void Function(String?) onTokenUpdate,}) : _client = client, _onTokenUpdate = onTokenUpdate; AuthRepositoryImpl({required NetworksSdkApi client, required void Function(String?) onTokenUpdate,}) : _client = client, _onTokenUpdate = onTokenUpdate;
@override @override
Future<User> login({required String email, required String password,}) async Future<User> login({required String email, required String password}) async {
{ final LoginResponse? loginResponse = await _client.executeRequest(
final LoginData? loginData = await _client.executeRequest(LoginRequest(email: email, password: password),); LoginRequest(email: email, password: password),
);
if (loginData == null) { if (loginResponse == null) {
throw Exception('Login failed: empty response'); // TODO: 接入国际化 throw Exception('Login failed: empty response');
} }
// 回调写入 Token内存 + 持久化由 Provider 层组合) _onTokenUpdate(loginResponse.data.accessToken);
_onTokenUpdate(loginData.token);
return loginData.toEntity(); // DTO → Domain Entity return loginResponse.toEntity();
} }
@override @override

View File

@@ -0,0 +1,67 @@
/// 通话记录 Domain 实体
///
/// 全局共享实体,被 call / chat 等多个 Feature 共用。
/// 纯 Dart 类,零 Flutter / 零网络 / 零 DB 依赖。
class CallLog {
final String id;
final int? callerId;
final int? receiverId;
final int? chatId;
final int? duration;
final int? videoCall;
final int? createdAt;
final int? updatedAt;
final int? endedAt;
final int? status;
final int? isDeleted;
final int? deletedAt;
final int? isRead;
const CallLog({
required this.id,
this.callerId,
this.receiverId,
this.chatId,
this.duration,
this.videoCall,
this.createdAt,
this.updatedAt,
this.endedAt,
this.status,
this.isDeleted,
this.deletedAt,
this.isRead,
});
CallLog copyWith({
String? id,
int? callerId,
int? receiverId,
int? chatId,
int? duration,
int? videoCall,
int? createdAt,
int? updatedAt,
int? endedAt,
int? status,
int? isDeleted,
int? deletedAt,
int? isRead,
}) {
return CallLog(
id: id ?? this.id,
callerId: callerId ?? this.callerId,
receiverId: receiverId ?? this.receiverId,
chatId: chatId ?? this.chatId,
duration: duration ?? this.duration,
videoCall: videoCall ?? this.videoCall,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
endedAt: endedAt ?? this.endedAt,
status: status ?? this.status,
isDeleted: isDeleted ?? this.isDeleted,
deletedAt: deletedAt ?? this.deletedAt,
isRead: isRead ?? this.isRead,
);
}
}

View File

@@ -0,0 +1,200 @@
/// 聊天 Domain 实体
class Chat {
final int id;
final int? typ;
final int? lastId;
final int? lastTyp;
final String? lastMsg;
final int? lastTime;
final int lastPos;
final int firstPos;
final int? msgIdx;
final String? profile;
final String? pin;
final String? icon;
final String iconGaussian;
final String? name;
final int? userId;
final int? chatId;
final int? friendId;
final int? sort;
final int? unreadNum;
final int? unreadCount;
final int? hideChatMsgIdx;
final int? readChatMsgIdx;
final int? otherReadIdx;
final String? unreadAtMsgIdx;
final int? deleteTime;
final int? addIndex;
final int flag;
final int? flagMy;
final int? autoDeleteInterval;
final int? mute;
final int? verified;
final int? createTime;
final int? startIdx;
final int? isReadMsg;
final String translateOutgoing;
final String translateIncoming;
final int incomingIdx;
final int outgoingIdx;
final int incomingSoundId;
final int outgoingSoundId;
final int notificationSoundId;
final String chatKey;
final String activeChatKey;
final int coverIdx;
final int round;
final int workspaceId;
final int localPermission;
const Chat({
required this.id,
this.typ,
this.lastId,
this.lastTyp,
this.lastMsg,
this.lastTime,
this.lastPos = 0,
this.firstPos = -1,
this.msgIdx,
this.profile,
this.pin,
this.icon,
this.iconGaussian = '',
this.name,
this.userId,
this.chatId,
this.friendId,
this.sort,
this.unreadNum,
this.unreadCount,
this.hideChatMsgIdx,
this.readChatMsgIdx,
this.otherReadIdx,
this.unreadAtMsgIdx,
this.deleteTime,
this.addIndex,
this.flag = 0,
this.flagMy,
this.autoDeleteInterval,
this.mute,
this.verified,
this.createTime,
this.startIdx,
this.isReadMsg,
this.translateOutgoing = '',
this.translateIncoming = '',
this.incomingIdx = 0,
this.outgoingIdx = 0,
this.incomingSoundId = 0,
this.outgoingSoundId = 0,
this.notificationSoundId = 0,
this.chatKey = '',
this.activeChatKey = '',
this.coverIdx = 0,
this.round = 0,
this.workspaceId = 0,
this.localPermission = 0,
});
Chat copyWith({
int? id,
int? typ,
int? lastId,
int? lastTyp,
String? lastMsg,
int? lastTime,
int? lastPos,
int? firstPos,
int? msgIdx,
String? profile,
String? pin,
String? icon,
String? iconGaussian,
String? name,
int? userId,
int? chatId,
int? friendId,
int? sort,
int? unreadNum,
int? unreadCount,
int? hideChatMsgIdx,
int? readChatMsgIdx,
int? otherReadIdx,
String? unreadAtMsgIdx,
int? deleteTime,
int? addIndex,
int? flag,
int? flagMy,
int? autoDeleteInterval,
int? mute,
int? verified,
int? createTime,
int? startIdx,
int? isReadMsg,
String? translateOutgoing,
String? translateIncoming,
int? incomingIdx,
int? outgoingIdx,
int? incomingSoundId,
int? outgoingSoundId,
int? notificationSoundId,
String? chatKey,
String? activeChatKey,
int? coverIdx,
int? round,
int? workspaceId,
int? localPermission,
}) {
return Chat(
id: id ?? this.id,
typ: typ ?? this.typ,
lastId: lastId ?? this.lastId,
lastTyp: lastTyp ?? this.lastTyp,
lastMsg: lastMsg ?? this.lastMsg,
lastTime: lastTime ?? this.lastTime,
lastPos: lastPos ?? this.lastPos,
firstPos: firstPos ?? this.firstPos,
msgIdx: msgIdx ?? this.msgIdx,
profile: profile ?? this.profile,
pin: pin ?? this.pin,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
name: name ?? this.name,
userId: userId ?? this.userId,
chatId: chatId ?? this.chatId,
friendId: friendId ?? this.friendId,
sort: sort ?? this.sort,
unreadNum: unreadNum ?? this.unreadNum,
unreadCount: unreadCount ?? this.unreadCount,
hideChatMsgIdx: hideChatMsgIdx ?? this.hideChatMsgIdx,
readChatMsgIdx: readChatMsgIdx ?? this.readChatMsgIdx,
otherReadIdx: otherReadIdx ?? this.otherReadIdx,
unreadAtMsgIdx: unreadAtMsgIdx ?? this.unreadAtMsgIdx,
deleteTime: deleteTime ?? this.deleteTime,
addIndex: addIndex ?? this.addIndex,
flag: flag ?? this.flag,
flagMy: flagMy ?? this.flagMy,
autoDeleteInterval: autoDeleteInterval ?? this.autoDeleteInterval,
mute: mute ?? this.mute,
verified: verified ?? this.verified,
createTime: createTime ?? this.createTime,
startIdx: startIdx ?? this.startIdx,
isReadMsg: isReadMsg ?? this.isReadMsg,
translateOutgoing: translateOutgoing ?? this.translateOutgoing,
translateIncoming: translateIncoming ?? this.translateIncoming,
incomingIdx: incomingIdx ?? this.incomingIdx,
outgoingIdx: outgoingIdx ?? this.outgoingIdx,
incomingSoundId: incomingSoundId ?? this.incomingSoundId,
outgoingSoundId: outgoingSoundId ?? this.outgoingSoundId,
notificationSoundId: notificationSoundId ?? this.notificationSoundId,
chatKey: chatKey ?? this.chatKey,
activeChatKey: activeChatKey ?? this.activeChatKey,
coverIdx: coverIdx ?? this.coverIdx,
round: round ?? this.round,
workspaceId: workspaceId ?? this.workspaceId,
localPermission: localPermission ?? this.localPermission,
);
}
}

View File

@@ -0,0 +1,100 @@
/// 聊天机器人 Domain 实体
class ChatBot {
final int id;
final String? name;
final String? username;
final int? botUserId;
final String? icon;
final String? iconGaussian;
final String? description;
final String? token;
final int? flag;
final int? status;
final String? webhook;
final String? commands;
final String? banner;
final int? channelId;
final int? channelGroupId;
final int? deletedAt;
final String? internalWebhook;
final int? mode;
final String? redirectUrl;
final int? isInvitable;
final int? isAllowForward;
final String? tips;
const ChatBot({
required this.id,
this.name,
this.username,
this.botUserId,
this.icon,
this.iconGaussian,
this.description,
this.token,
this.flag,
this.status,
this.webhook,
this.commands,
this.banner,
this.channelId,
this.channelGroupId,
this.deletedAt,
this.internalWebhook,
this.mode,
this.redirectUrl,
this.isInvitable,
this.isAllowForward,
this.tips,
});
ChatBot copyWith({
int? id,
String? name,
String? username,
int? botUserId,
String? icon,
String? iconGaussian,
String? description,
String? token,
int? flag,
int? status,
String? webhook,
String? commands,
String? banner,
int? channelId,
int? channelGroupId,
int? deletedAt,
String? internalWebhook,
int? mode,
String? redirectUrl,
int? isInvitable,
int? isAllowForward,
String? tips,
}) {
return ChatBot(
id: id ?? this.id,
name: name ?? this.name,
username: username ?? this.username,
botUserId: botUserId ?? this.botUserId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
description: description ?? this.description,
token: token ?? this.token,
flag: flag ?? this.flag,
status: status ?? this.status,
webhook: webhook ?? this.webhook,
commands: commands ?? this.commands,
banner: banner ?? this.banner,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
deletedAt: deletedAt ?? this.deletedAt,
internalWebhook: internalWebhook ?? this.internalWebhook,
mode: mode ?? this.mode,
redirectUrl: redirectUrl ?? this.redirectUrl,
isInvitable: isInvitable ?? this.isInvitable,
isAllowForward: isAllowForward ?? this.isAllowForward,
tips: tips ?? this.tips,
);
}
}

View File

@@ -0,0 +1,48 @@
/// 聊天分类 Domain 实体
class ChatCategory {
final int id;
final String? name;
final String? includedChatIds;
final String? excludedChatIds;
final int? seq;
final int isHide;
final int createdAt;
final int updatedAt;
final int deletedAt;
const ChatCategory({
required this.id,
this.name,
this.includedChatIds,
this.excludedChatIds,
this.seq,
this.isHide = 0,
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
});
ChatCategory copyWith({
int? id,
String? name,
String? includedChatIds,
String? excludedChatIds,
int? seq,
int? isHide,
int? createdAt,
int? updatedAt,
int? deletedAt,
}) {
return ChatCategory(
id: id ?? this.id,
name: name ?? this.name,
includedChatIds: includedChatIds ?? this.includedChatIds,
excludedChatIds: excludedChatIds ?? this.excludedChatIds,
seq: seq ?? this.seq,
isHide: isHide ?? this.isHide,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
);
}
}

View File

@@ -0,0 +1,112 @@
/// 发现小程序 Domain 实体
class DiscoverMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final String? lastLoginAt;
final String? screen;
const DiscoverMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
DiscoverMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
String? lastLoginAt,
String? screen,
}) {
return DiscoverMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}

View File

@@ -0,0 +1,112 @@
/// 探索小程序 Domain 实体
class ExploreMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const ExploreMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
ExploreMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return ExploreMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}

View File

@@ -0,0 +1,112 @@
/// 收藏小程序 Domain 实体
class FavoriteMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const FavoriteMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
FavoriteMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return FavoriteMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}

View File

@@ -0,0 +1,72 @@
/// 收藏 Domain 实体
class Favourite {
final int id;
final String parentId;
final String data;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int? source;
final int? userId;
final int? authorId;
final String typ;
final String tag;
final int isPin;
final int chatTyp;
final int isUploaded;
final String urls;
const Favourite({
required this.id,
this.parentId = '',
this.data = '',
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
this.source,
this.userId,
this.authorId,
this.typ = '[]',
this.tag = '[]',
this.isPin = 0,
this.chatTyp = 0,
this.isUploaded = 1,
this.urls = '[]',
});
Favourite copyWith({
int? id,
String? parentId,
String? data,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? source,
int? userId,
int? authorId,
String? typ,
String? tag,
int? isPin,
int? chatTyp,
int? isUploaded,
String? urls,
}) {
return Favourite(
id: id ?? this.id,
parentId: parentId ?? this.parentId,
data: data ?? this.data,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
source: source ?? this.source,
userId: userId ?? this.userId,
authorId: authorId ?? this.authorId,
typ: typ ?? this.typ,
tag: tag ?? this.tag,
isPin: isPin ?? this.isPin,
chatTyp: chatTyp ?? this.chatTyp,
isUploaded: isUploaded ?? this.isUploaded,
urls: urls ?? this.urls,
);
}
}

View File

@@ -0,0 +1,44 @@
/// 收藏详情 Domain 实体
class FavouriteDetail {
final int? id;
final String relatedId;
final String content;
final int? typ;
final int? messageId;
final int? sendId;
final int? chatId;
final int? sendTime;
const FavouriteDetail({
this.id,
this.relatedId = '',
this.content = '',
this.typ,
this.messageId,
this.sendId,
this.chatId,
this.sendTime,
});
FavouriteDetail copyWith({
int? id,
String? relatedId,
String? content,
int? typ,
int? messageId,
int? sendId,
int? chatId,
int? sendTime,
}) {
return FavouriteDetail(
id: id ?? this.id,
relatedId: relatedId ?? this.relatedId,
content: content ?? this.content,
typ: typ ?? this.typ,
messageId: messageId ?? this.messageId,
sendId: sendId ?? this.sendId,
chatId: chatId ?? this.chatId,
sendTime: sendTime ?? this.sendTime,
);
}
}

View File

@@ -0,0 +1,124 @@
/// 群组 Domain 实体
class Group {
final int id;
final int? userJoinDate;
final String? name;
final String? profile;
final String? icon;
final String iconGaussian;
final int? permission;
final int? admin;
final String? members;
final int? owner;
final String? admins;
final int? visible;
final int? speakInterval;
final int? groupType;
final int? roomType;
final int? maxNumber;
final int? channelId;
final int? channelGroupId;
final int? createTime;
final int? updateTime;
final int? addIndex;
final int? maxMember;
final int? expireTime;
final int workspaceId;
final int mode;
final int redpacketPlay;
final String? topic;
final String? rp;
const Group({
required this.id,
this.userJoinDate,
this.name,
this.profile,
this.icon,
this.iconGaussian = '',
this.permission,
this.admin,
this.members,
this.owner,
this.admins,
this.visible,
this.speakInterval,
this.groupType,
this.roomType,
this.maxNumber,
this.channelId,
this.channelGroupId,
this.createTime,
this.updateTime,
this.addIndex,
this.maxMember,
this.expireTime,
this.workspaceId = 0,
this.mode = 0,
this.redpacketPlay = 0,
this.topic,
this.rp,
});
Group copyWith({
int? id,
int? userJoinDate,
String? name,
String? profile,
String? icon,
String? iconGaussian,
int? permission,
int? admin,
String? members,
int? owner,
String? admins,
int? visible,
int? speakInterval,
int? groupType,
int? roomType,
int? maxNumber,
int? channelId,
int? channelGroupId,
int? createTime,
int? updateTime,
int? addIndex,
int? maxMember,
int? expireTime,
int? workspaceId,
int? mode,
int? redpacketPlay,
String? topic,
String? rp,
}) {
return Group(
id: id ?? this.id,
userJoinDate: userJoinDate ?? this.userJoinDate,
name: name ?? this.name,
profile: profile ?? this.profile,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
permission: permission ?? this.permission,
admin: admin ?? this.admin,
members: members ?? this.members,
owner: owner ?? this.owner,
admins: admins ?? this.admins,
visible: visible ?? this.visible,
speakInterval: speakInterval ?? this.speakInterval,
groupType: groupType ?? this.groupType,
roomType: roomType ?? this.roomType,
maxNumber: maxNumber ?? this.maxNumber,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
createTime: createTime ?? this.createTime,
updateTime: updateTime ?? this.updateTime,
addIndex: addIndex ?? this.addIndex,
maxMember: maxMember ?? this.maxMember,
expireTime: expireTime ?? this.expireTime,
workspaceId: workspaceId ?? this.workspaceId,
mode: mode ?? this.mode,
redpacketPlay: redpacketPlay ?? this.redpacketPlay,
topic: topic ?? this.topic,
rp: rp ?? this.rp,
);
}
}

View File

@@ -0,0 +1,76 @@
/// 消息 Domain 实体
class Message {
final int id;
final int? messageId;
final int? chatId;
final int? chatIdx;
final int? sendId;
final String? content;
final int? typ;
final int? sendTime;
final int? expireTime;
final int? createTime;
final String? atUsers;
final String emojis;
final int editTime;
final int refTyp;
final int flag;
final String cmid;
const Message({
required this.id,
this.messageId,
this.chatId,
this.chatIdx,
this.sendId,
this.content,
this.typ,
this.sendTime,
this.expireTime,
this.createTime,
this.atUsers,
this.emojis = '[]',
this.editTime = 0,
this.refTyp = 0,
this.flag = 0,
this.cmid = '',
});
Message copyWith({
int? id,
int? messageId,
int? chatId,
int? chatIdx,
int? sendId,
String? content,
int? typ,
int? sendTime,
int? expireTime,
int? createTime,
String? atUsers,
String? emojis,
int? editTime,
int? refTyp,
int? flag,
String? cmid,
}) {
return Message(
id: id ?? this.id,
messageId: messageId ?? this.messageId,
chatId: chatId ?? this.chatId,
chatIdx: chatIdx ?? this.chatIdx,
sendId: sendId ?? this.sendId,
content: content ?? this.content,
typ: typ ?? this.typ,
sendTime: sendTime ?? this.sendTime,
expireTime: expireTime ?? this.expireTime,
createTime: createTime ?? this.createTime,
atUsers: atUsers ?? this.atUsers,
emojis: emojis ?? this.emojis,
editTime: editTime ?? this.editTime,
refTyp: refTyp ?? this.refTyp,
flag: flag ?? this.flag,
cmid: cmid ?? this.cmid,
);
}
}

View File

@@ -0,0 +1,36 @@
/// 待处理好友请求历史 Domain 实体
class PendingFriendRequestHistory {
final int id;
final int uid;
final int requestTime;
final String? remarks;
final String? source;
final int? rs;
const PendingFriendRequestHistory({
required this.id,
required this.uid,
required this.requestTime,
this.remarks,
this.source,
this.rs,
});
PendingFriendRequestHistory copyWith({
int? id,
int? uid,
int? requestTime,
String? remarks,
String? source,
int? rs,
}) {
return PendingFriendRequestHistory(
id: id ?? this.id,
uid: uid ?? this.uid,
requestTime: requestTime ?? this.requestTime,
remarks: remarks ?? this.remarks,
source: source ?? this.source,
rs: rs ?? this.rs,
);
}
}

View File

@@ -0,0 +1,112 @@
/// 最近小程序 Domain 实体
class RecentMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const RecentMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
RecentMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return RecentMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}

View File

@@ -0,0 +1,60 @@
/// 重试 Domain 实体
class Retry {
final int? id;
final int? uid;
final String apiType;
final String endPoint;
final String requestData;
final int? synced;
final String callbackFun;
final int? expired;
final int? replace;
final int? expireTime;
final int? createTime;
final int? addIndex;
const Retry({
this.id,
this.uid,
this.apiType = '',
this.endPoint = '',
this.requestData = '',
this.synced,
this.callbackFun = '',
this.expired,
this.replace,
this.expireTime,
this.createTime,
this.addIndex,
});
Retry copyWith({
int? id,
int? uid,
String? apiType,
String? endPoint,
String? requestData,
int? synced,
String? callbackFun,
int? expired,
int? replace,
int? expireTime,
int? createTime,
int? addIndex,
}) {
return Retry(
id: id ?? this.id,
uid: uid ?? this.uid,
apiType: apiType ?? this.apiType,
endPoint: endPoint ?? this.endPoint,
requestData: requestData ?? this.requestData,
synced: synced ?? this.synced,
callbackFun: callbackFun ?? this.callbackFun,
expired: expired ?? this.expired,
replace: replace ?? this.replace,
expireTime: expireTime ?? this.expireTime,
createTime: createTime ?? this.createTime,
addIndex: addIndex ?? this.addIndex,
);
}
}

View File

@@ -0,0 +1,48 @@
/// 音效 Domain 实体
class Sound {
final int id;
final String filePath;
final int typ;
final String name;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int channelGroupId;
final int isDefault;
const Sound({
required this.id,
this.filePath = '',
required this.typ,
this.name = '',
required this.createdAt,
required this.updatedAt,
this.deletedAt = 0,
required this.channelGroupId,
required this.isDefault,
});
Sound copyWith({
int? id,
String? filePath,
int? typ,
String? name,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? channelGroupId,
int? isDefault,
}) {
return Sound(
id: id ?? this.id,
filePath: filePath ?? this.filePath,
typ: typ ?? this.typ,
name: name ?? this.name,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
channelGroupId: channelGroupId ?? this.channelGroupId,
isDefault: isDefault ?? this.isDefault,
);
}
}

View File

@@ -0,0 +1,40 @@
/// 标签 Domain 实体
class Tag {
final int? id;
final int? uid;
final String name;
final int? type;
final int? createdAt;
final int? updatedAt;
final int? addIndex;
const Tag({
this.id,
this.uid,
this.name = '',
this.type,
this.createdAt,
this.updatedAt,
this.addIndex,
});
Tag copyWith({
int? id,
int? uid,
String? name,
int? type,
int? createdAt,
int? updatedAt,
int? addIndex,
}) {
return Tag(
id: id ?? this.id,
uid: uid ?? this.uid,
name: name ?? this.name,
type: type ?? this.type,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
addIndex: addIndex ?? this.addIndex,
);
}
}

View File

@@ -14,15 +14,81 @@
/// → View 渲染 /// → View 渲染
/// ``` /// ```
class User { class User {
final String id; final int uid;
final String email; final String? uuid;
final int? lastOnline;
final String? profilePic;
final String? profilePicGaussian;
final String? nickname; final String? nickname;
final String? avatar; final String? contact;
final String? countryCode;
final String? email;
final String? recoveryEmail;
final String? username;
final String? bio;
final int? relationship;
final String? userAlias;
final int? channelId;
final int? channelGroupId;
final String? hint;
const User({ const User({
required this.id, required this.uid,
required this.email, this.uuid,
this.lastOnline,
this.profilePic,
this.profilePicGaussian,
this.nickname, this.nickname,
this.avatar, this.contact,
this.countryCode,
this.email,
this.recoveryEmail,
this.username,
this.bio,
this.relationship,
this.userAlias,
this.channelId,
this.channelGroupId,
this.hint,
}); });
User copyWith({
int? uid,
String? uuid,
int? lastOnline,
String? profilePic,
String? profilePicGaussian,
String? nickname,
String? contact,
String? countryCode,
String? email,
String? recoveryEmail,
String? username,
String? bio,
int? relationship,
String? userAlias,
int? channelId,
int? channelGroupId,
String? hint,
}) {
return User(
uid: uid ?? this.uid,
uuid: uuid ?? this.uuid,
lastOnline: lastOnline ?? this.lastOnline,
profilePic: profilePic ?? this.profilePic,
profilePicGaussian: profilePicGaussian ?? this.profilePicGaussian,
nickname: nickname ?? this.nickname,
contact: contact ?? this.contact,
countryCode: countryCode ?? this.countryCode,
email: email ?? this.email,
recoveryEmail: recoveryEmail ?? this.recoveryEmail,
username: username ?? this.username,
bio: bio ?? this.bio,
relationship: relationship ?? this.relationship,
userAlias: userAlias ?? this.userAlias,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
hint: hint ?? this.hint,
);
}
} }

View File

@@ -0,0 +1,24 @@
/// 用户请求历史 Domain 实体
class UserRequestHistory {
final int id;
final int? status;
final int? createdAt;
const UserRequestHistory({
required this.id,
this.status,
this.createdAt,
});
UserRequestHistory copyWith({
int? id,
int? status,
int? createdAt,
}) {
return UserRequestHistory(
id: id ?? this.id,
status: status ?? this.status,
createdAt: createdAt ?? this.createdAt,
);
}
}

View File

@@ -0,0 +1,64 @@
/// 工作空间 Domain 实体
class Workspace {
final int id;
final String? name;
final int? ownerId;
final String? description;
final String? logo;
final int? grade;
final int? cap;
final String? currency;
final int? status;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final int? channelGroupId;
const Workspace({
required this.id,
this.name,
this.ownerId,
this.description,
this.logo,
this.grade,
this.cap,
this.currency,
this.status,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.channelGroupId,
});
Workspace copyWith({
int? id,
String? name,
int? ownerId,
String? description,
String? logo,
int? grade,
int? cap,
String? currency,
int? status,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? channelGroupId,
}) {
return Workspace(
id: id ?? this.id,
name: name ?? this.name,
ownerId: ownerId ?? this.ownerId,
description: description ?? this.description,
logo: logo ?? this.logo,
grade: grade ?? this.grade,
cap: cap ?? this.cap,
currency: currency ?? this.currency,
status: status ?? this.status,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
channelGroupId: channelGroupId ?? this.channelGroupId,
);
}
}

View File

@@ -1,7 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:im_app/app/di/db_provider.dart'; import 'package:im_app/app/di/db_provider.dart';
import 'package:im_app/data/local/drift/app_database.dart'; import 'package:im_app/data/local/drift/app_database.dart';
@@ -87,12 +86,12 @@ class ChatDbTestViewModel extends _$ChatDbTestViewModel {
final chunk = List.generate( final chunk = List.generate(
chunkSize.clamp(0, count - i), chunkSize.clamp(0, count - i),
(j) => UsersCompanion.insert( (j) => UsersCompanion.insert(
uid: Value(i + j), uid: i + j,
nickname: Value('User ${i + j}'), nickname: Value('User ${i + j}'),
), ),
); );
await db.batchInsertOrReplace<User>(chunk); await db.batchInsertOrReplace<DriftUser>(chunk);
completed += chunk.length; completed += chunk.length;
// 让出主线程 // 让出主线程

View File

@@ -1,4 +1,8 @@
import 'package:flutter/foundation.dart'; import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:im_app/data/models/user_dto.dart';
import 'package:im_app/data/remote/login_request.dart';
import 'package:networks_sdk/networks_sdk.dart'; import 'package:networks_sdk/networks_sdk.dart';
import 'package:im_app/app/di/db_provider.dart'; import 'package:im_app/app/di/db_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -56,10 +60,23 @@ class LoginViewModel extends _$LoginViewModel {
/// 正式 [login] 成功后同样需要调用 [AuthNotifier.login] 更新守卫状态。 /// 正式 [login] 成功后同样需要调用 [AuthNotifier.login] 更新守卫状态。
Future<void> demoLogin() async { Future<void> demoLogin() async {
final storageApi = ref.read(storageSdkProvider); final storageApi = ref.read(storageSdkProvider);
///TODO: StorageSDKLifeCycle 需要只在主项目暴露
final storageLifeCycle = storageApi as StorageSdkLifecycle; final storageLifeCycle = storageApi as StorageSdkLifecycle;
ref.read(authNotifierProvider).login(); final provider = ref.read(authNotifierProvider);
await storageLifeCycle.openDatabase(1234567);
// Read mock response from assets
final String raw = await rootBundle.loadString('assets/loginData.json');
final Map<String, dynamic> json = jsonDecode(raw);
// Parse into LoginData (nested under 'data' key)
final loginResponse = LoginResponse.fromJson(json);
final user = loginResponse.data.toEntity();
provider.login();
// Open database for the user
await storageLifeCycle.openDatabase(user.uid);
///TODO: User 和 DTO和数据库之间转换
final userCompanion = UserDto.fromEntity(user).toCompanion();
storageApi.insert(userCompanion);
} }
/// 执行登录 /// 执行登录

View File

@@ -62,3 +62,5 @@ dev_dependencies:
flutter: flutter:
uses-material-design: true uses-material-design: true
assets:
- assets/

View File

@@ -23,7 +23,7 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
) async { ) async {
final db = _db; final db = _db;
if (db == null) return; if (db == null) return;
await db.into(table).insertOnConflictUpdate(companion); await db.into(table).insert(companion, mode: InsertMode.insertOrReplace);
} }
@override @override
@@ -44,7 +44,11 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
final db = _db; final db = _db;
if (db == null) return; if (db == null) return;
await db.batch( await db.batch(
(batch) => batch.insertAllOnConflictUpdate(table, companions), (batch) => batch.insertAll(
table,
companions,
mode: InsertMode.insertOrReplace,
),
); );
} }