import PocketBase, { RecordModel } from "pocketbase" import { Logger } from "winston" import { Context } from "../../types" import PbToolBase, { WithExpand } from "../base" import { SheetModel } from "../sheet" /** 聊天集合名称 */ const DB_NAME = "chat" /** * 聊天数据接口 */ export interface Chat { /** 飞书聊天 ID */ chatId: string /** 聊天名称 */ name: string /** 聊天头像 URL */ avatar: string /** 聊天模式: 群组、点对点或话题 */ mode: "group" | "p2p" | "topic" /** 是否启用周报汇总 */ weeklySummary: boolean /** 是否启用日报汇总 */ dailySummary: boolean /** 关联表单 ID */ sheet: string } /** 聊天数据模型,继承基础的 RecordModel */ export type ChatModel = Chat & RecordModel /** * 带有关联表单数据的聊天模型 * 扩展了表单关联字段 */ export type ChatModelWithSheet = ChatModel & WithExpand<{ sheet: SheetModel }> /** * 聊天数据管理类 * 提供对飞书聊天相关数据的存储、查询和管理功能 * 继承自 PbToolBase 基础工具类 */ class ChatDB extends PbToolBase { /** * 创建 ChatDB 实例 * * @param pbClient - PocketBase 客户端实例 * @param logger - 日志记录器实例 */ constructor(pbClient: PocketBase, logger: Logger) { super(DB_NAME, pbClient, logger) } /** * 通过聊天 ID 获取聊天信息 * * @param chatId - 飞书聊天 ID * @returns 聊天数据模型,包含关联的表单数据,失败时返回 null * * @example * ```typescript * const chat = await chatDB.getOneByChatId("oc_123456"); * ``` */ public getOneByChatId = (chatId: string) => { const filter = `chatId = "${chatId}"` return this.getFirstOne(filter, { expand: "sheet" }) } /** * 根据上下文获取聊天信息 * 如果数据库中不存在,则尝试从飞书 API 获取并创建新记录 * * @param context - 上下文对象,包含飞书服务和请求体 * @returns 聊天数据模型,失败时返回 null * * @example * ```typescript * const chat = await chatDB.getByCtx(ctx); * ``` */ public getByCtx = async ({ larkService, larkBody }: Context) => { const { chatId } = larkBody if (!chatId) { this.logger.error("chatId 为空") return null } const chat = await this.getOneByChatId(chatId) if (chat) return chat this.logger.info("群聊不在数据库里,尝试从飞书获取", { chatId }) const chatInfo = await larkService.chat.getChatInfo(chatId) if (!chatInfo || chatInfo.code !== 0) return null const { name, avatar, chat_mode } = chatInfo.data return this.create({ chatId, name, avatar, mode: chat_mode, weeklySummary: false, dailySummary: false, sheet: "", }) } /** * 获取需要汇总的聊天列表 * * @param timeScope - 汇总时间范围:"daily"(日报)、"weekly"(周报)或"all"(全部) * @returns 符合条件的聊天数据模型列表,失败时返回 null * * @example * ```typescript * const dailyChats = await chatDB.getNeedSummaryChats("daily"); * ``` */ public getNeedSummaryChats = async ( timeScope: "daily" | "weekly" | "all" ) => { const filterMap = { daily: "dailySummary = true", weekly: "weeklySummary = true", all: "dailySummary = true && weeklySummary = true", } return this.list({ filter: filterMap[timeScope] }) } } export default ChatDB