新增消息列表API,优化消息列表组件以支持加载状态和数据同步,提升用户体验和代码可读性。
This commit is contained in:
@@ -4,25 +4,15 @@
|
||||
* 架构设计:
|
||||
* 1. 使用serverId作为数据库主键,直接对应接口返回的id字段
|
||||
* 2. 保留原始的id字段,用于存储接口数据的完整性
|
||||
* 3. 简化数据处理逻辑,避免ID映射的复杂性
|
||||
* 3. 添加userId字段实现多用户数据隔离
|
||||
* 4. 统一会话表和联系人表,兼容好友和群聊
|
||||
*
|
||||
* 优势:
|
||||
* - 直接使用服务器ID作为主键,避免ID冲突
|
||||
* - 保持数据的一致性和可追溯性
|
||||
* - 简化查询逻辑,提高性能
|
||||
* - 支持重复数据检测和去重
|
||||
*
|
||||
* 使用方法:
|
||||
* - 存储接口数据:使用 createWithServerId() 或 createManyWithServerId()
|
||||
* - 查询数据:使用 findById(id) 根据原始ID查询,或 findByPrimaryKey(serverId) 根据主键查询
|
||||
* - 批量查询:使用 findByIds([id1, id2, ...]) 根据原始ID批量查询
|
||||
* - 内部操作:serverId作为主键用于数据库内部管理
|
||||
*
|
||||
* 示例:
|
||||
* const serverData = { id: 1001, name: '测试', ... }; // 接口返回的数据
|
||||
* const serverId = await service.createWithServerId(serverData); // 存储,返回serverId
|
||||
* const data = await service.findById(1001); // 根据原始ID查询(用户友好)
|
||||
* const dataByPK = await service.findByPrimaryKey(serverId); // 根据主键查询(内部使用)
|
||||
* - 通过userId实现多用户数据隔离
|
||||
* - 统一的会话和联系人表结构,兼容好友和群聊
|
||||
* - 支持复合索引,提高查询性能
|
||||
* - 支持用户登录记录和自动清理
|
||||
*/
|
||||
|
||||
import Dexie, { Table } from "dexie";
|
||||
@@ -33,33 +23,136 @@ import {
|
||||
MessageListData,
|
||||
} from "@/pages/pc/ckbox/data";
|
||||
|
||||
// 数据类型定义,使用serverId作为主键
|
||||
// ==================== 用户登录记录 ====================
|
||||
export interface UserLoginRecord {
|
||||
serverId: string; // 主键: user_${userId}
|
||||
userId: number; // 用户ID
|
||||
lastLoginTime: string; // 最后登录时间
|
||||
loginCount: number; // 登录次数
|
||||
createTime: string; // 首次登录时间
|
||||
lastActiveTime: string; // 最后活跃时间
|
||||
}
|
||||
|
||||
// ==================== 统一会话表(兼容好友和群聊) ====================
|
||||
export interface ChatSession {
|
||||
serverId: string; // 主键
|
||||
userId: number; // 用户ID(数据隔离)
|
||||
id: number; // 原始ID
|
||||
type: "friend" | "group"; // 类型:好友或群聊
|
||||
|
||||
// 通用字段
|
||||
wechatAccountId: number; // 所属客服账号
|
||||
nickname: string; // 显示名称
|
||||
conRemark?: string; // 备注名
|
||||
avatar: string; // 头像
|
||||
content: string; // 最新消息内容
|
||||
lastUpdateTime: string; // 最后更新时间
|
||||
config: {
|
||||
unreadCount: number; // 未读数量
|
||||
top: boolean; // 是否置顶
|
||||
};
|
||||
sortKey: string; // 预计算排序键
|
||||
|
||||
// 好友特有字段(type='friend'时有效)
|
||||
wechatFriendId?: number; // 好友ID
|
||||
wechatId?: string; // 微信号
|
||||
alias?: string; // 别名
|
||||
|
||||
// 群聊特有字段(type='group'时有效)
|
||||
chatroomId?: string; // 群聊ID
|
||||
chatroomOwner?: string; // 群主
|
||||
selfDisplayName?: string; // 群内昵称
|
||||
notice?: string; // 群公告
|
||||
}
|
||||
|
||||
// ==================== 统一联系人表(兼容好友和群聊) ====================
|
||||
export interface Contact {
|
||||
serverId: string; // 主键
|
||||
userId: number; // 用户ID(数据隔离)
|
||||
id: number; // 原始ID
|
||||
type: "friend" | "group"; // 类型:好友或群聊
|
||||
|
||||
// 通用字段
|
||||
wechatAccountId: number; // 所属客服账号
|
||||
nickname: string; // 显示名称
|
||||
conRemark?: string; // 备注名
|
||||
avatar: string; // 头像
|
||||
lastUpdateTime: string; // 最后更新时间
|
||||
config?: any; // 配置信息
|
||||
sortKey: string; // 预计算排序键
|
||||
searchKey: string; // 预计算搜索键
|
||||
|
||||
// 好友特有字段(type='friend'时有效)
|
||||
wechatFriendId?: number; // 好友ID
|
||||
wechatId?: string; // 微信号
|
||||
alias?: string; // 别名
|
||||
gender?: number; // 性别
|
||||
region?: string; // 地区
|
||||
signature?: string; // 个性签名
|
||||
phone?: string; // 手机号
|
||||
quanPin?: string; // 全拼
|
||||
|
||||
// 群聊特有字段(type='group'时有效)
|
||||
chatroomId?: string; // 群聊ID
|
||||
chatroomOwner?: string; // 群主
|
||||
selfDisplayName?: string; // 群内昵称
|
||||
notice?: string; // 群公告
|
||||
memberCount?: number; // 群成员数量
|
||||
}
|
||||
|
||||
// ==================== 联系人标签映射表 ====================
|
||||
export interface ContactLabelMap {
|
||||
serverId: string; // 主键: ${contactId}_${labelId}
|
||||
userId: number; // 用户ID(数据隔离)
|
||||
labelId: number; // 标签ID
|
||||
contactId: number; // 联系人ID
|
||||
contactType: "friend" | "group"; // 联系人类型
|
||||
sortKey: string; // 预计算排序键
|
||||
searchKey: string; // 预计算搜索键
|
||||
|
||||
// 列表展示必需字段(轻量)
|
||||
avatar: string;
|
||||
nickname: string;
|
||||
conRemark?: string;
|
||||
unreadCount: number;
|
||||
lastUpdateTime: string;
|
||||
}
|
||||
|
||||
// ==================== 保留原有数据类型(向后兼容) ====================
|
||||
export interface KfUserWithServerId extends Omit<KfUserListData, "id"> {
|
||||
serverId: number | string; // 服务器ID作为主键
|
||||
userId: number; // 用户ID(数据隔离)
|
||||
id?: number; // 接口数据的原始ID字段
|
||||
}
|
||||
|
||||
// 新联系人列表数据接口
|
||||
export interface NewContactListData {
|
||||
serverId: number | string; // 服务器ID作为主键
|
||||
userId: number; // 用户ID(数据隔离)
|
||||
id?: number; // 接口数据的原始ID字段
|
||||
groupName: string;
|
||||
contacts: ContractData[];
|
||||
weChatGroup: weChatGroup[];
|
||||
contacts: Contact[];
|
||||
weChatGroup: Contact[];
|
||||
}
|
||||
|
||||
// 数据库类
|
||||
class CunkebaoDatabase extends Dexie {
|
||||
// ==================== 保留原有表(向后兼容) ====================
|
||||
kfUsers!: Table<KfUserWithServerId>;
|
||||
weChatGroup!: Table<weChatGroup>;
|
||||
contracts!: Table<ContractData>;
|
||||
newContractList!: Table<NewContactListData>;
|
||||
newContactList!: Table<NewContactListData>;
|
||||
messageList!: Table<MessageListData>;
|
||||
|
||||
// ==================== 新增统一表 ====================
|
||||
chatSessions!: Table<ChatSession>; // 统一会话表
|
||||
contactsUnified!: Table<Contact>; // 统一联系人表
|
||||
contactLabelMap!: Table<ContactLabelMap>; // 联系人标签映射表
|
||||
userLoginRecords!: Table<UserLoginRecord>; // 用户登录记录表
|
||||
|
||||
constructor() {
|
||||
super("CunkebaoDatabase");
|
||||
|
||||
// 版本1:使用serverId作为主键的架构
|
||||
// 版本1:使用serverId作为主键的架构(保留原有表)
|
||||
this.version(1).stores({
|
||||
kfUsers:
|
||||
"serverId, id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
|
||||
@@ -67,10 +160,64 @@ class CunkebaoDatabase extends Dexie {
|
||||
"serverId, id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar,wechatChatroomId, groupId, config, notice, selfDisplyName",
|
||||
contracts:
|
||||
"serverId, id, wechatAccountId, wechatId, alias, conRemark, nickname, quanPin, avatar, gender, region, addFrom, phone, signature, accountId, extendFields, city, lastUpdateTime, isPassed, tenantId, groupId, thirdParty, additionalPicture, desc, config, lastMessageTime, duplicate",
|
||||
newContractList: "serverId, id, groupName, contacts",
|
||||
newContactList: "serverId, id, groupName, contacts",
|
||||
messageList:
|
||||
"serverId, id, dataType, wechatAccountId, tenantId, accountId, nickname, avatar, groupId, config, labels, wechatId, alias, conRemark, quanPin, gender, region, addFrom, phone, signature, extendFields, city, lastUpdateTime, isPassed, thirdParty, additionalPicture, desc, lastMessageTime, duplicate, chatroomId, chatroomOwner, chatroomAvatar, notice, selfDisplyName",
|
||||
});
|
||||
|
||||
// 版本2:添加用户隔离字段到原有表
|
||||
this.version(2)
|
||||
.stores({
|
||||
kfUsers:
|
||||
"serverId, userId, id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
|
||||
weChatGroup:
|
||||
"serverId, userId, id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar,wechatChatroomId, groupId, config, notice, selfDisplyName",
|
||||
contracts:
|
||||
"serverId, userId, id, wechatAccountId, wechatId, alias, conRemark, nickname, quanPin, avatar, gender, region, addFrom, phone, signature, accountId, extendFields, city, lastUpdateTime, isPassed, tenantId, groupId, thirdParty, additionalPicture, desc, config, lastMessageTime, duplicate",
|
||||
newContactList: "serverId, userId, id, groupName, contacts",
|
||||
messageList:
|
||||
"serverId, userId, id, dataType, wechatAccountId, tenantId, accountId, nickname, avatar, groupId, config, labels, wechatId, alias, conRemark, quanPin, gender, region, addFrom, phone, signature, extendFields, city, lastUpdateTime, isPassed, thirdParty, additionalPicture, desc, lastMessageTime, duplicate, chatroomId, chatroomOwner, chatroomAvatar, notice, selfDisplyName",
|
||||
})
|
||||
.upgrade(trans => {
|
||||
// 为现有数据添加默认userId=0(需要手动清理)
|
||||
return trans
|
||||
.table("kfUsers")
|
||||
.toCollection()
|
||||
.modify(item => {
|
||||
item.userId = 0;
|
||||
});
|
||||
});
|
||||
|
||||
// 版本3:添加新的统一表和用户登录记录表
|
||||
this.version(3).stores({
|
||||
// 保留原有表
|
||||
kfUsers:
|
||||
"serverId, userId, id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
|
||||
weChatGroup:
|
||||
"serverId, userId, id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar,wechatChatroomId, groupId, config, notice, selfDisplyName",
|
||||
contracts:
|
||||
"serverId, userId, id, wechatAccountId, wechatId, alias, conRemark, nickname, quanPin, avatar, gender, region, addFrom, phone, signature, accountId, extendFields, city, lastUpdateTime, isPassed, tenantId, groupId, thirdParty, additionalPicture, desc, config, lastMessageTime, duplicate",
|
||||
newContactList: "serverId, userId, id, groupName, contacts",
|
||||
messageList:
|
||||
"serverId, userId, id, dataType, wechatAccountId, tenantId, accountId, nickname, avatar, groupId, config, labels, wechatId, alias, conRemark, quanPin, gender, region, addFrom, phone, signature, extendFields, city, lastUpdateTime, isPassed, thirdParty, additionalPicture, desc, lastMessageTime, duplicate, chatroomId, chatroomOwner, chatroomAvatar, notice, selfDisplyName",
|
||||
|
||||
// 新增统一表
|
||||
// 会话表索引:支持按用户、类型、时间、置顶等查询
|
||||
chatSessions:
|
||||
"serverId, userId, id, type, wechatAccountId, [userId+type], [userId+wechatAccountId], [userId+lastUpdateTime], sortKey, nickname, conRemark, avatar, content, lastUpdateTime",
|
||||
|
||||
// 联系人表索引:支持按用户、类型、标签、搜索等查询
|
||||
contactsUnified:
|
||||
"serverId, userId, id, type, wechatAccountId, [userId+type], [userId+wechatAccountId], sortKey, searchKey, nickname, conRemark, avatar, lastUpdateTime",
|
||||
|
||||
// 联系人标签映射表索引:支持按用户、标签、联系人、类型查询
|
||||
contactLabelMap:
|
||||
"serverId, userId, labelId, contactId, contactType, [userId+labelId], [userId+contactId], [userId+labelId+sortKey], sortKey, searchKey, avatar, nickname, conRemark, unreadCount, lastUpdateTime",
|
||||
|
||||
// 用户登录记录表索引:支持按用户ID、登录时间查询
|
||||
userLoginRecords:
|
||||
"serverId, userId, lastLoginTime, loginCount, createTime, lastActiveTime",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,8 +482,14 @@ export class DatabaseService<T> {
|
||||
export const kfUserService = new DatabaseService(db.kfUsers);
|
||||
export const weChatGroupService = new DatabaseService(db.weChatGroup);
|
||||
export const contractService = new DatabaseService(db.contracts);
|
||||
export const newContactListService = new DatabaseService(db.newContractList);
|
||||
export const newContactListService = new DatabaseService(db.newContactList);
|
||||
export const messageListService = new DatabaseService(db.messageList);
|
||||
|
||||
// 新增统一表服务
|
||||
export const chatSessionService = new DatabaseService(db.chatSessions);
|
||||
export const contactUnifiedService = new DatabaseService(db.contactsUnified);
|
||||
export const contactLabelMapService = new DatabaseService(db.contactLabelMap);
|
||||
export const userLoginRecordService = new DatabaseService(db.userLoginRecords);
|
||||
|
||||
// 默认导出数据库实例
|
||||
export default db;
|
||||
|
||||
Reference in New Issue
Block a user