更新ContractData接口以使extendFields可选并修改相关序列化逻辑。增强数据库模式以支持extendFields作为JSON字符串,并确保在数据操作期间进行正确处理。改进ContactManager中的比较逻辑以包含extendFields。
This commit is contained in:
@@ -146,7 +146,7 @@ export interface ContractData {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
signature: string;
|
signature: string;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
extendFields: null;
|
extendFields?: Record<string, any> | null;
|
||||||
city?: string;
|
city?: string;
|
||||||
lastUpdateTime: string;
|
lastUpdateTime: string;
|
||||||
isPassed: boolean;
|
isPassed: boolean;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface ContractData {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
signature: string;
|
signature: string;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
extendFields: null;
|
extendFields?: Record<string, any> | null;
|
||||||
city?: string;
|
city?: string;
|
||||||
lastUpdateTime: string;
|
lastUpdateTime: string;
|
||||||
isPassed: boolean;
|
isPassed: boolean;
|
||||||
|
|||||||
@@ -82,6 +82,20 @@ export const getAllGroups = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const serializeExtendFields = (value: any) => {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return value.trim() ? value : "{}";
|
||||||
|
}
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("序列化 extendFields 失败:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "{}";
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将好友数据转换为统一的 Contact 格式
|
* 将好友数据转换为统一的 Contact 格式
|
||||||
*/
|
*/
|
||||||
@@ -95,11 +109,21 @@ export const convertFriendsToContacts = (
|
|||||||
id: friend.id,
|
id: friend.id,
|
||||||
type: "friend" as const,
|
type: "friend" as const,
|
||||||
wechatAccountId: friend.wechatAccountId,
|
wechatAccountId: friend.wechatAccountId,
|
||||||
|
wechatFriendId: friend.id,
|
||||||
wechatId: friend.wechatId,
|
wechatId: friend.wechatId,
|
||||||
nickname: friend.nickname || "",
|
nickname: friend.nickname || "",
|
||||||
conRemark: friend.conRemark || "",
|
conRemark: friend.conRemark || "",
|
||||||
avatar: friend.avatar || "",
|
avatar: friend.avatar || "",
|
||||||
|
alias: friend.alias || "",
|
||||||
|
gender: friend.gender,
|
||||||
|
aiType: friend.aiType ?? 0,
|
||||||
|
phone: friend.phone ?? "",
|
||||||
|
region: friend.region ?? "",
|
||||||
|
quanPin: friend.quanPin || "",
|
||||||
|
signature: friend.signature || "",
|
||||||
|
config: friend.config || {},
|
||||||
groupId: friend.groupId, // 保留标签ID
|
groupId: friend.groupId, // 保留标签ID
|
||||||
|
extendFields: serializeExtendFields(friend.extendFields),
|
||||||
lastUpdateTime: new Date().toISOString(),
|
lastUpdateTime: new Date().toISOString(),
|
||||||
sortKey: "",
|
sortKey: "",
|
||||||
searchKey: "",
|
searchKey: "",
|
||||||
@@ -120,10 +144,19 @@ export const convertGroupsToContacts = (
|
|||||||
type: "group" as const,
|
type: "group" as const,
|
||||||
wechatAccountId: group.wechatAccountId,
|
wechatAccountId: group.wechatAccountId,
|
||||||
wechatId: group.chatroomId || "",
|
wechatId: group.chatroomId || "",
|
||||||
|
chatroomId: group.chatroomId || "",
|
||||||
|
chatroomOwner: group.chatroomOwner || "",
|
||||||
nickname: group.nickname || "",
|
nickname: group.nickname || "",
|
||||||
conRemark: group.conRemark || "",
|
conRemark: group.conRemark || "",
|
||||||
avatar: group.chatroomAvatar || group.avatar || "",
|
avatar: group.chatroomAvatar || group.avatar || "",
|
||||||
|
selfDisplayName: group.selfDisplyName || "",
|
||||||
|
notice: group.notice || "",
|
||||||
|
aiType: group.aiType ?? 0,
|
||||||
|
phone: group.phone ?? "",
|
||||||
|
region: group.region ?? "",
|
||||||
|
config: group.config || {},
|
||||||
groupId: group.groupId, // 保留标签ID
|
groupId: group.groupId, // 保留标签ID
|
||||||
|
extendFields: serializeExtendFields(group.extendFields),
|
||||||
lastUpdateTime: new Date().toISOString(),
|
lastUpdateTime: new Date().toISOString(),
|
||||||
sortKey: "",
|
sortKey: "",
|
||||||
searchKey: "",
|
searchKey: "",
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export interface ContractData {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
signature: string;
|
signature: string;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
extendFields: null;
|
extendFields?: Record<string, any> | null;
|
||||||
city?: string;
|
city?: string;
|
||||||
lastUpdateTime: string;
|
lastUpdateTime: string;
|
||||||
isPassed: boolean;
|
isPassed: boolean;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export interface ContractData {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
signature: string;
|
signature: string;
|
||||||
accountId: number;
|
accountId: number;
|
||||||
extendFields: null;
|
extendFields?: Record<string, any> | null;
|
||||||
city?: string;
|
city?: string;
|
||||||
lastUpdateTime: string;
|
lastUpdateTime: string;
|
||||||
isPassed: boolean;
|
isPassed: boolean;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export interface ChatSession {
|
|||||||
notice?: string; // 群公告
|
notice?: string; // 群公告
|
||||||
phone?: string; // 联系人电话
|
phone?: string; // 联系人电话
|
||||||
region?: string; // 联系人地区
|
region?: string; // 联系人地区
|
||||||
|
extendFields?: string; // 扩展字段(JSON 字符串)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 统一联系人表(兼容好友和群聊) ====================
|
// ==================== 统一联系人表(兼容好友和群聊) ====================
|
||||||
@@ -92,6 +93,7 @@ export interface Contact {
|
|||||||
signature?: string; // 个性签名
|
signature?: string; // 个性签名
|
||||||
phone?: string; // 手机号
|
phone?: string; // 手机号
|
||||||
quanPin?: string; // 全拼
|
quanPin?: string; // 全拼
|
||||||
|
extendFields?: string; // 扩展字段(JSON 字符串)
|
||||||
|
|
||||||
// 群聊特有字段(type='group'时有效)
|
// 群聊特有字段(type='group'时有效)
|
||||||
chatroomId?: string; // 群聊ID
|
chatroomId?: string; // 群聊ID
|
||||||
@@ -147,6 +149,41 @@ class CunkebaoDatabase extends Dexie {
|
|||||||
userLoginRecords:
|
userLoginRecords:
|
||||||
"serverId, userId, lastLoginTime, loginCount, createTime, lastActiveTime",
|
"serverId, userId, lastLoginTime, loginCount, createTime, lastActiveTime",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.version(2)
|
||||||
|
.stores({
|
||||||
|
chatSessions:
|
||||||
|
"serverId, userId, id, type, wechatAccountId, [userId+type], [userId+wechatAccountId], [userId+lastUpdateTime], [userId+aiType], sortKey, nickname, conRemark, avatar, content, lastUpdateTime, aiType, phone, region, extendFields",
|
||||||
|
contactsUnified:
|
||||||
|
"serverId, userId, id, type, wechatAccountId, [userId+type], [userId+wechatAccountId], [userId+aiType], sortKey, searchKey, nickname, conRemark, avatar, lastUpdateTime, groupId, aiType, phone, region, extendFields",
|
||||||
|
contactLabelMap:
|
||||||
|
"serverId, userId, labelId, contactId, contactType, [userId+labelId], [userId+contactId], [userId+labelId+sortKey], sortKey, searchKey, avatar, nickname, conRemark, unreadCount, lastUpdateTime",
|
||||||
|
userLoginRecords:
|
||||||
|
"serverId, userId, lastLoginTime, loginCount, createTime, lastActiveTime",
|
||||||
|
})
|
||||||
|
.upgrade(async tx => {
|
||||||
|
await tx
|
||||||
|
.table("chatSessions")
|
||||||
|
.toCollection()
|
||||||
|
.modify(session => {
|
||||||
|
if (!("extendFields" in session) || session.extendFields == null) {
|
||||||
|
session.extendFields = "{}";
|
||||||
|
} else if (typeof session.extendFields !== "string") {
|
||||||
|
session.extendFields = JSON.stringify(session.extendFields);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await tx
|
||||||
|
.table("contactsUnified")
|
||||||
|
.toCollection()
|
||||||
|
.modify(contact => {
|
||||||
|
if (!("extendFields" in contact) || contact.extendFields == null) {
|
||||||
|
contact.extendFields = "{}";
|
||||||
|
} else if (typeof contact.extendFields !== "string") {
|
||||||
|
contact.extendFields = JSON.stringify(contact.extendFields);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,18 +332,18 @@ export class DatabaseService<T> {
|
|||||||
|
|
||||||
// 基础 CRUD 操作 - 使用serverId作为主键
|
// 基础 CRUD 操作 - 使用serverId作为主键
|
||||||
async create(data: Omit<T, "serverId">): Promise<string | number> {
|
async create(data: Omit<T, "serverId">): Promise<string | number> {
|
||||||
return await this.table.add(data as T);
|
return await this.table.add(this.prepareDataForWrite(data) as T);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建数据(直接使用接口数据)
|
// 创建数据(直接使用接口数据)
|
||||||
// 接口数据的id字段直接作为serverId主键,原id字段保留
|
// 接口数据的id字段直接作为serverId主键,原id字段保留
|
||||||
async createWithServerId(data: any): Promise<string | number> {
|
async createWithServerId(data: any): Promise<string | number> {
|
||||||
const dataToInsert = {
|
const dataToInsert = this.prepareDataForWrite({
|
||||||
...data,
|
...data,
|
||||||
serverId: data.id, // 使用接口的id作为serverId主键
|
serverId: data.id, // 使用接口的id作为serverId主键
|
||||||
phone: data.phone ?? "",
|
phone: data.phone ?? "",
|
||||||
region: data.region ?? "",
|
region: data.region ?? "",
|
||||||
};
|
});
|
||||||
return await this.table.add(dataToInsert as T);
|
return await this.table.add(dataToInsert as T);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +362,10 @@ export class DatabaseService<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(serverId: string | number, data: Partial<T>): Promise<number> {
|
async update(serverId: string | number, data: Partial<T>): Promise<number> {
|
||||||
return await this.table.update(serverId, data as any);
|
return await this.table.update(
|
||||||
|
serverId,
|
||||||
|
this.prepareDataForWrite(data) as any,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMany(
|
async updateMany(
|
||||||
@@ -334,7 +374,7 @@ export class DatabaseService<T> {
|
|||||||
return await this.table.bulkUpdate(
|
return await this.table.bulkUpdate(
|
||||||
dataList.map(item => ({
|
dataList.map(item => ({
|
||||||
key: item.serverId,
|
key: item.serverId,
|
||||||
changes: item.data as any,
|
changes: this.prepareDataForWrite(item.data) as any,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -342,7 +382,8 @@ export class DatabaseService<T> {
|
|||||||
async createMany(
|
async createMany(
|
||||||
dataList: Omit<T, "serverId">[],
|
dataList: Omit<T, "serverId">[],
|
||||||
): Promise<(string | number)[]> {
|
): Promise<(string | number)[]> {
|
||||||
return await this.table.bulkAdd(dataList as T[], { allKeys: true });
|
const processed = dataList.map(item => this.prepareDataForWrite(item));
|
||||||
|
return await this.table.bulkAdd(processed as T[], { allKeys: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量创建数据(直接使用接口数据)
|
// 批量创建数据(直接使用接口数据)
|
||||||
@@ -366,12 +407,14 @@ export class DatabaseService<T> {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const processedData = newData.map(item => ({
|
const processedData = newData.map(item =>
|
||||||
...item,
|
this.prepareDataForWrite({
|
||||||
serverId: item.id, // 使用接口的id作为serverId主键
|
...item,
|
||||||
phone: item.phone ?? "",
|
serverId: item.id, // 使用接口的id作为serverId主键
|
||||||
region: item.region ?? "",
|
phone: item.phone ?? "",
|
||||||
}));
|
region: item.region ?? "",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return await this.table.bulkAdd(processedData as T[], { allKeys: true });
|
return await this.table.bulkAdd(processedData as T[], { allKeys: true });
|
||||||
}
|
}
|
||||||
@@ -545,6 +588,27 @@ export class DatabaseService<T> {
|
|||||||
.equals(value)
|
.equals(value)
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private prepareDataForWrite(data: any) {
|
||||||
|
if (!data || typeof data !== "object") {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prepared = { ...data };
|
||||||
|
|
||||||
|
if ("extendFields" in prepared) {
|
||||||
|
const value = prepared.extendFields;
|
||||||
|
if (typeof value === "string" && value.trim() !== "") {
|
||||||
|
prepared.extendFields = value;
|
||||||
|
} else if (value && typeof value === "object") {
|
||||||
|
prepared.extendFields = JSON.stringify(value);
|
||||||
|
} else {
|
||||||
|
prepared.extendFields = "{}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prepared;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建统一表的服务实例
|
// 创建统一表的服务实例
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ export class ContactManager {
|
|||||||
local.wechatAccountId !== server.wechatAccountId ||
|
local.wechatAccountId !== server.wechatAccountId ||
|
||||||
(local.aiType ?? 0) !== (server.aiType ?? 0) || // 添加 aiType 比较
|
(local.aiType ?? 0) !== (server.aiType ?? 0) || // 添加 aiType 比较
|
||||||
(local.phone ?? "") !== (server.phone ?? "") ||
|
(local.phone ?? "") !== (server.phone ?? "") ||
|
||||||
(local.region ?? "") !== (server.region ?? "")
|
(local.region ?? "") !== (server.region ?? "") ||
|
||||||
|
(local.extendFields ?? "{}") !== (server.extendFields ?? "{}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,10 +195,12 @@ export class ContactManager {
|
|||||||
* 获取联系人分组列表
|
* 获取联系人分组列表
|
||||||
*/
|
*/
|
||||||
static async getContactGroups(
|
static async getContactGroups(
|
||||||
userId: number,
|
_userId: number,
|
||||||
customerId?: number,
|
_customerId?: number,
|
||||||
): Promise<ContactGroupByLabel[]> {
|
): Promise<ContactGroupByLabel[]> {
|
||||||
try {
|
try {
|
||||||
|
void _userId;
|
||||||
|
void _customerId;
|
||||||
// 这里应该根据实际的标签系统来实现
|
// 这里应该根据实际的标签系统来实现
|
||||||
// 暂时返回空数组,实际实现需要根据标签表来查询
|
// 暂时返回空数组,实际实现需要根据标签表来查询
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ import Dexie from "dexie";
|
|||||||
import { db, chatSessionService, ChatSession } from "../db";
|
import { db, chatSessionService, ChatSession } from "../db";
|
||||||
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
import { ContractData, weChatGroup } from "@/pages/pc/ckbox/data";
|
||||||
|
|
||||||
|
const serializeExtendFields = (value: any) => {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return value.trim() ? value : "{}";
|
||||||
|
}
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("序列化 extendFields 失败:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "{}";
|
||||||
|
};
|
||||||
|
|
||||||
export class MessageManager {
|
export class MessageManager {
|
||||||
private static updateCallbacks = new Set<(sessions: ChatSession[]) => void>();
|
private static updateCallbacks = new Set<(sessions: ChatSession[]) => void>();
|
||||||
|
|
||||||
@@ -103,6 +117,7 @@ export class MessageManager {
|
|||||||
wechatFriendId: friend.id,
|
wechatFriendId: friend.id,
|
||||||
wechatId: friend.wechatId,
|
wechatId: friend.wechatId,
|
||||||
alias: friend.alias,
|
alias: friend.alias,
|
||||||
|
extendFields: serializeExtendFields((friend as any).extendFields),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +154,7 @@ export class MessageManager {
|
|||||||
chatroomOwner: group.chatroomOwner,
|
chatroomOwner: group.chatroomOwner,
|
||||||
selfDisplayName: group.selfDisplyName,
|
selfDisplayName: group.selfDisplyName,
|
||||||
notice: group.notice,
|
notice: group.notice,
|
||||||
|
extendFields: serializeExtendFields((group as any).extendFields),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +221,7 @@ export class MessageManager {
|
|||||||
"aiType", // 添加aiType比较
|
"aiType", // 添加aiType比较
|
||||||
"phone",
|
"phone",
|
||||||
"region",
|
"region",
|
||||||
|
"extendFields",
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const field of fieldsToCompare) {
|
for (const field of fieldsToCompare) {
|
||||||
|
|||||||
Reference in New Issue
Block a user