KfUserListData | undefined;
+ getKfSelectedUser: () => KfUserListData | undefined;
newContractList: { groupName: string; contacts: any[] }[];
asyncKfSelected: (data: number) => void;
getkfUserList: () => KfUserListData[];
diff --git a/Cunkebao/src/store/module/ckchat/ckchat.ts b/Cunkebao/src/store/module/ckchat/ckchat.ts
index 591a2bf1..899bb9f7 100644
--- a/Cunkebao/src/store/module/ckchat/ckchat.ts
+++ b/Cunkebao/src/store/module/ckchat/ckchat.ts
@@ -6,7 +6,7 @@ import {
CkAccount,
KfUserListData,
} from "@/pages/pc/ckbox/data";
-
+import { kfUserService } from "@/utils/db";
export const useCkChatStore = createPersistStore(
set => ({
userInfo: null,
@@ -16,9 +16,18 @@ export const useCkChatStore = createPersistStore(
kfUserList: [], //客服列表
kfSelected: 0,
newContractList: [], //联系人分组
- kfSelectedUser: () => {
- const state = useCkChatStore.getState();
- return state.kfUserList.find(item => item.id === state.kfSelected);
+ //客服列表
+ asyncKfUserList: async data => {
+ console.log(data);
+
+ await kfUserService.createManyWithServerId(data);
+ // set({ kfUserList: data });
+ },
+ // 获取客服列表
+ getkfUserList: async () => {
+ return await kfUserService.findAll();
+ // const state = useCkChatStore.getState();
+ // return state.kfUserList;
},
asyncKfSelected: (data: number) => {
set({ kfSelected: data });
@@ -39,14 +48,12 @@ export const useCkChatStore = createPersistStore(
asyncContractList: data => {
set({ contractList: data });
},
- // 控制终端用户列表
- getkfUserList: () => {
+ //获取选中的客服信息
+ getgetKfSelectedUser: () => {
const state = useCkChatStore.getState();
- return state.kfUserList;
- },
- asyncKfUserList: data => {
- set({ kfUserList: data });
+ return state.kfUserList.find(item => item.id === state.kfSelected);
},
+
// 删除控制终端用户
deleteCtrlUser: (userId: number) => {
set(state => ({
diff --git a/Cunkebao/src/utils/db.ts b/Cunkebao/src/utils/db.ts
index 2ec84c0b..943e3b44 100644
--- a/Cunkebao/src/utils/db.ts
+++ b/Cunkebao/src/utils/db.ts
@@ -1,45 +1,53 @@
/**
- * 数据库工具类 - 解决服务器ID与本地自增主键冲突问题
+ * 数据库工具类 - 使用serverId作为主键的优化架构
*
- * 问题描述:
- * 接口返回的数据包含id字段,直接存储到数据库会与Dexie的自增主键(++id)产生冲突
+ * 架构设计:
+ * 1. 使用serverId作为数据库主键,直接对应接口返回的id字段
+ * 2. 保留原始的id字段,用于存储接口数据的完整性
+ * 3. 简化数据处理逻辑,避免ID映射的复杂性
*
- * 解决方案:
- * 1. 将服务器返回的id字段映射为serverId字段存储
- * 2. 数据库使用自增的id作为主键
- * 3. 提供专门的方法处理服务器数据的存储和查询
+ * 优势:
+ * - 直接使用服务器ID作为主键,避免ID冲突
+ * - 保持数据的一致性和可追溯性
+ * - 简化查询逻辑,提高性能
+ * - 支持重复数据检测和去重
*
* 使用方法:
* - 存储接口数据:使用 createWithServerId() 或 createManyWithServerId()
- * - 查询服务器数据:使用 findByServerId()
- * - 常规操作:使用原有的 create(), findById() 等方法
+ * - 查询数据:使用 findById(id) 根据原始ID查询,或 findByPrimaryKey(serverId) 根据主键查询
+ * - 批量查询:使用 findByIds([id1, id2, ...]) 根据原始ID批量查询
+ * - 内部操作:serverId作为主键用于数据库内部管理
*
* 示例:
* const serverData = { id: 1001, name: '测试', ... }; // 接口返回的数据
- * const localId = await service.createWithServerId(serverData); // 存储,返回本地ID
- * const data = await service.findByServerId(1001); // 根据服务器ID查询
+ * const serverId = await service.createWithServerId(serverData); // 存储,返回serverId
+ * const data = await service.findById(1001); // 根据原始ID查询(用户友好)
+ * const dataByPK = await service.findByPrimaryKey(serverId); // 根据主键查询(内部使用)
*/
import Dexie, { Table } from "dexie";
import { KfUserListData, GroupData, ContractData } from "@/pages/pc/ckbox/data";
-// 扩展数据类型,添加serverId字段
-export interface KfUserWithServerId extends KfUserListData {
- serverId?: number | string; // 服务器返回的原始ID
+// 数据类型定义,使用serverId作为主键
+export interface KfUserWithServerId extends Omit {
+ serverId: number | string; // 服务器ID作为主键
+ id?: number; // 接口数据的原始ID字段
}
-export interface GroupWithServerId extends GroupData {
- serverId?: number | string; // 服务器返回的原始ID
+export interface GroupWithServerId extends Omit {
+ serverId: number | string; // 服务器ID作为主键
+ id?: number; // 接口数据的原始ID字段
}
-export interface ContractWithServerId extends ContractData {
- serverId?: number | string; // 服务器返回的原始ID
+export interface ContractWithServerId extends Omit {
+ serverId: number | string; // 服务器ID作为主键
+ id?: number; // 接口数据的原始ID字段
}
// 新联系人列表数据接口
export interface NewContactListData {
- id?: number;
- serverId?: number | string; // 服务器返回的原始ID
+ serverId: number | string; // 服务器ID作为主键
+ id?: number; // 接口数据的原始ID字段
groupName: string;
contacts: ContractData[] | GroupData[];
}
@@ -54,34 +62,16 @@ class CunkebaoDatabase extends Dexie {
constructor() {
super("CunkebaoDatabase");
- // 版本1:初始版本(不包含serverId字段)
+ // 版本1:使用serverId作为主键的架构
this.version(1).stores({
kfUsers:
- "++id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
+ "serverId, id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
groups:
- "++id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar, groupId, config, unreadCount, notice, selfDisplyName",
+ "serverId, id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar, groupId, config, unreadCount, notice, selfDisplyName",
contracts:
- "++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, unreadCount, duplicate",
- newContractList: "++id, groupName, contacts",
+ "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, unreadCount, duplicate",
+ newContractList: "serverId, id, groupName, contacts",
});
-
- // 版本2:添加serverId字段支持
- this.version(2)
- .stores({
- kfUsers:
- "++id, serverId, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
- groups:
- "++id, serverId, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar, groupId, config, unreadCount, notice, selfDisplyName",
- contracts:
- "++id, serverId, wechatAccountId, wechatId, alias, conRemark, nickname, quanPin, avatar, gender, region, addFrom, phone, signature, accountId, extendFields, city, lastUpdateTime, isPassed, tenantId, groupId, thirdParty, additionalPicture, desc, config, lastMessageTime, unreadCount, duplicate",
- newContractList: "++id, serverId, groupName, contacts",
- })
- .upgrade(tx => {
- // 数据库升级逻辑:为现有数据添加serverId字段(可选)
- console.log("数据库升级到版本2:添加serverId字段支持");
- // 注意:这里不需要迁移数据,因为serverId是可选字段
- // 如果需要迁移现有数据,可以在这里添加相应逻辑
- });
}
}
@@ -92,64 +82,90 @@ export const db = new CunkebaoDatabase();
export class DatabaseService {
constructor(private table: Table) {}
- // 基础 CRUD 操作
- async create(data: Omit): Promise {
+ // 基础 CRUD 操作 - 使用serverId作为主键
+ async create(data: Omit): Promise {
return await this.table.add(data as T);
}
- // 创建数据(处理服务器ID映射)
- // 用于存储从接口获取的数据,将服务器的id字段映射为serverId,避免与数据库自增主键冲突
- async createWithServerId(data: any): Promise {
- const { id, ...restData } = data;
+ // 创建数据(直接使用接口数据)
+ // 接口数据的id字段直接作为serverId主键,原id字段保留
+ async createWithServerId(data: any): Promise {
const dataToInsert = {
- ...restData,
- serverId: id, // 将服务器的id映射为serverId
+ ...data,
+ serverId: data.id, // 使用接口的id作为serverId主键
};
return await this.table.add(dataToInsert as T);
}
- async findById(id: number): Promise {
- return await this.table.get(id);
+ // 根据原始ID查询(用户友好的查询方法)
+ async findById(id: string | number): Promise {
+ return await this.table.where("id").equals(id).first();
+ }
+
+ // 根据serverId查询(内部主键查询)
+ async findByPrimaryKey(serverId: string | number): Promise {
+ return await this.table.get(serverId);
}
async findAll(): Promise {
return await this.table.toArray();
}
- async update(id: number, data: Partial): Promise {
- return await this.table.update(id, data as any);
+ async update(serverId: string | number, data: Partial): Promise {
+ return await this.table.update(serverId, data as any);
}
async updateMany(
- dataList: { id: number; data: Partial }[],
+ dataList: { serverId: string | number; data: Partial }[],
): Promise {
return await this.table.bulkUpdate(
dataList.map(item => ({
- key: item.id,
+ key: item.serverId,
changes: item.data as any,
})),
);
}
- async createMany(dataList: Omit[]): Promise {
+ async createMany(
+ dataList: Omit[],
+ ): Promise<(string | number)[]> {
return await this.table.bulkAdd(dataList as T[], { allKeys: true });
}
- // 批量创建数据(处理服务器ID映射)
- // 用于批量存储从接口获取的数据,将服务器的id字段映射为serverId
- async createManyWithServerId(dataList: any[]): Promise {
- const processedData = dataList.map(item => {
- const { id, ...restData } = item;
- return {
- ...restData,
- serverId: id, // 将服务器的id映射为serverId
- };
- });
+ // 批量创建数据(直接使用接口数据)
+ // 接口数据的id字段直接作为serverId主键
+ async createManyWithServerId(dataList: any[]): Promise<(string | number)[]> {
+ // 检查是否存在重复的serverId
+ const serverIds = dataList.map(item => item.id);
+ const existingData = await this.table
+ .where("serverId")
+ .anyOf(serverIds)
+ .toArray();
+ const existingServerIds = new Set(
+ existingData.map((item: any) => item.serverId),
+ );
+
+ // 过滤掉已存在的数据
+ const newData = dataList.filter(item => !existingServerIds.has(item.id));
+
+ if (newData.length === 0) {
+ console.log("所有数据都已存在,跳过插入");
+ return [];
+ }
+
+ const processedData = newData.map(item => ({
+ ...item,
+ serverId: item.id, // 使用接口的id作为serverId主键
+ }));
+
+ console.log(
+ `插入 ${processedData.length} 条新数据,跳过 ${dataList.length - newData.length} 条重复数据`,
+ );
return await this.table.bulkAdd(processedData as T[], { allKeys: true });
}
- async delete(id: number): Promise {
- await this.table.delete(id);
+ async delete(serverId: string | number): Promise {
+ await this.table.delete(serverId);
}
async clear(): Promise {
@@ -164,10 +180,14 @@ export class DatabaseService {
.toArray();
}
- // 根据服务器ID查询
- // 用于根据原始的服务器ID查找数据
+ // 根据服务器ID查询(兼容性方法)
async findByServerId(serverId: any): Promise {
- return await this.table.where("serverId").equals(serverId).first();
+ return await this.table.get(serverId);
+ }
+
+ // 根据原始ID批量查询
+ async findByIds(ids: (string | number)[]): Promise {
+ return await this.table.where("id").anyOf(ids).toArray();
}
// 多值查询(IN 查询)