feat: 优化请求处理 & 拆分Type
This commit is contained in:
parent
ae199d661e
commit
b7437f47e4
@ -1,10 +1,6 @@
|
||||
import { RecordModel } from "pocketbase";
|
||||
import pbClient from "../pbClient";
|
||||
import { managePb404 } from "../../utils/pbTools";
|
||||
|
||||
export interface AppConfigRecordModel extends RecordModel {
|
||||
value: string;
|
||||
}
|
||||
import { DB } from "../../types";
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
@ -12,7 +8,7 @@ export interface AppConfigRecordModel extends RecordModel {
|
||||
* @returns
|
||||
*/
|
||||
const get = async (key: string) => {
|
||||
const config = await managePb404<AppConfigRecordModel>(
|
||||
const config = await managePb404<DB.AppConfig>(
|
||||
async () =>
|
||||
await await pbClient.collection("config").getFirstListItem(`key='${key}'`)
|
||||
);
|
||||
|
@ -1,23 +1,9 @@
|
||||
import { DB } from "../../types";
|
||||
import { managePb404 } from "../../utils/pbTools";
|
||||
import pbClient from "../pbClient";
|
||||
|
||||
export interface PBMessageGroup {
|
||||
collectionId: string;
|
||||
collectionName: string;
|
||||
updated: string;
|
||||
created: string;
|
||||
desc: string;
|
||||
id: string;
|
||||
name: string;
|
||||
email?: string[];
|
||||
chat_id?: string[];
|
||||
open_id?: string[];
|
||||
union_id?: string[];
|
||||
user_id?: string[];
|
||||
}
|
||||
|
||||
const getOne = (groupId: string) =>
|
||||
managePb404<PBMessageGroup>(
|
||||
managePb404<DB.MessageGroup>(
|
||||
async () => await pbClient.collection("message_group").getOne(groupId)
|
||||
);
|
||||
|
||||
|
3
index.ts
3
index.ts
@ -1,5 +1,6 @@
|
||||
import { manageBotReq } from "./routes/bot";
|
||||
import { manageMessageReq } from "./routes/message";
|
||||
import { manageMicroAppReq } from "./routes/microApp";
|
||||
import { initSchedule } from "./schedule";
|
||||
|
||||
initSchedule();
|
||||
@ -14,6 +15,8 @@ Bun.serve({
|
||||
if (url.pathname === "/bot") return await manageBotReq(req);
|
||||
// 消息代理发送
|
||||
if (url.pathname === "/message") return await manageMessageReq(req);
|
||||
// 小程序
|
||||
if (url.pathname.startsWith("/micro_app")) return await manageMicroAppReq(req);
|
||||
// 其他
|
||||
return new Response("hello, glade to see you!");
|
||||
} catch (error: any) {
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { sleep } from "bun";
|
||||
import { getActionType, getIsActionMsg } from "../../utils/msgTools";
|
||||
import { LarkUserAction } from "../../types";
|
||||
import lark from "../../service/lark";
|
||||
|
||||
const makeChatIdCard = async (body: LarkUserAction) => {
|
||||
import service from "../../services";
|
||||
import { LarkAction } from "../../types";
|
||||
|
||||
/**
|
||||
* 返回ChatId卡片
|
||||
* @param {LarkAction.Data} body
|
||||
*/
|
||||
const makeChatIdCard = async (body: LarkAction.Data) => {
|
||||
await sleep(500);
|
||||
return JSON.stringify({
|
||||
type: "template",
|
||||
@ -25,9 +30,9 @@ const ACTION_MAP = {
|
||||
|
||||
/**
|
||||
* 处理按钮点击事件
|
||||
* @param {LarkUserAction} body
|
||||
* @param {LarkAction.Data} body
|
||||
*/
|
||||
const manageBtnClick = async (body: LarkUserAction) => {
|
||||
const manageBtnClick = async (body: LarkAction.Data) => {
|
||||
const { action } = body?.action?.value as {
|
||||
action: keyof typeof ACTION_MAP;
|
||||
};
|
||||
@ -37,15 +42,15 @@ const manageBtnClick = async (body: LarkUserAction) => {
|
||||
const card = await func(body);
|
||||
if (!card) return;
|
||||
// 更新飞书的卡片
|
||||
await lark.updateCard(body.open_message_id, card);
|
||||
await service.lark.message.update(body.open_message_id, card);
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理Action消息
|
||||
* @param {LarkUserAction} body
|
||||
* @param {LarkAction.Data} body
|
||||
* @returns {boolean} 是否在本函数中处理了消息
|
||||
*/
|
||||
export const manageActionMsg = (body: LarkUserAction) => {
|
||||
export const manageActionMsg = (body: LarkAction.Data) => {
|
||||
// 过滤非Action消息
|
||||
if (!getIsActionMsg(body)) {
|
||||
return false;
|
@ -1,6 +1,5 @@
|
||||
import { fetchCIMonitor, fetchReportCollector } from "../../service";
|
||||
import lark from "../../service/lark";
|
||||
import { LarkMessageEvent } from "../../types";
|
||||
import service from "../../services";
|
||||
import { LarkEvent } from "../../types";
|
||||
import {
|
||||
getChatId,
|
||||
getChatType,
|
||||
@ -12,10 +11,10 @@ import {
|
||||
|
||||
/**
|
||||
* 是否为P2P或者群聊并且艾特了小煎蛋
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns {boolean} 是否为P2P或者群聊并且艾特了小煎蛋
|
||||
*/
|
||||
const getIsP2pOrGroupAtBot = (body: LarkMessageEvent) => {
|
||||
const getIsP2pOrGroupAtBot = (body: LarkEvent.Data) => {
|
||||
const isP2p = getChatType(body) === "p2p";
|
||||
const isAtBot = getMentions(body)?.some?.(
|
||||
(mention) => mention.name === "小煎蛋"
|
||||
@ -25,10 +24,10 @@ const getIsP2pOrGroupAtBot = (body: LarkMessageEvent) => {
|
||||
|
||||
/**
|
||||
* 过滤出非法消息,如果发表情包就直接发回去
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns {boolean} 是否为非法消息
|
||||
*/
|
||||
const filterIllegalMsg = (body: LarkMessageEvent) => {
|
||||
const filterIllegalMsg = (body: LarkEvent.Data) => {
|
||||
// 没有chatId的消息不处理
|
||||
const chatId = getChatId(body);
|
||||
if (!chatId) return true;
|
||||
@ -49,7 +48,7 @@ const filterIllegalMsg = (body: LarkMessageEvent) => {
|
||||
// 发表情包就直接发回去
|
||||
if (msgType === "sticker") {
|
||||
const content = body?.event?.message?.content;
|
||||
lark.sendMsg("chat_id", chatId, "sticker", content);
|
||||
service.lark.message.send("chat_id", chatId, "sticker", content);
|
||||
}
|
||||
|
||||
// 非表情包只在私聊或者群聊中艾特小煎蛋时才回复
|
||||
@ -57,7 +56,7 @@ const filterIllegalMsg = (body: LarkMessageEvent) => {
|
||||
const content = JSON.stringify({
|
||||
text: "哇!这是什么东东?我只懂普通文本啦![可爱]",
|
||||
});
|
||||
lark.sendMsg("chat_id", chatId, "text", content);
|
||||
service.lark.message.send("chat_id", chatId, "text", content);
|
||||
}
|
||||
|
||||
// 非纯文本,全不放行
|
||||
@ -81,7 +80,7 @@ const manageIdMsg = async (chatId: string) => {
|
||||
},
|
||||
},
|
||||
});
|
||||
lark.sendMsg("chat_id", chatId, "interactive", content);
|
||||
service.lark.message.send("chat_id", chatId, "interactive", content);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -89,7 +88,7 @@ const manageIdMsg = async (chatId: string) => {
|
||||
* @param body - 消息体
|
||||
* @returns
|
||||
*/
|
||||
const manageCMDMsg = (body: LarkMessageEvent) => {
|
||||
const manageCMDMsg = (body: LarkEvent.Data) => {
|
||||
const text = getMsgText(body);
|
||||
const chatId = getChatId(body);
|
||||
if (text === "/id") {
|
||||
@ -97,16 +96,16 @@ const manageCMDMsg = (body: LarkMessageEvent) => {
|
||||
return true;
|
||||
}
|
||||
if (text === "/ci") {
|
||||
fetchCIMonitor(chatId);
|
||||
service.attach.ciMonitor(chatId);
|
||||
return true;
|
||||
}
|
||||
if (text.includes("share") && text.includes("简报")) {
|
||||
fetchReportCollector(body);
|
||||
service.attach.reportCollector(body);
|
||||
// 这个用时比较久,先发一条提醒用户收到了请求
|
||||
const content = JSON.stringify({
|
||||
text: "正在为您收集简报,请稍等片刻~",
|
||||
});
|
||||
lark.sendMsg("chat_id", chatId, "text", content);
|
||||
service.lark.message.send("chat_id", chatId, "text", content);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -114,9 +113,9 @@ const manageCMDMsg = (body: LarkMessageEvent) => {
|
||||
|
||||
/**
|
||||
* 回复引导消息
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
*/
|
||||
const replyGuideMsg = async (body: LarkMessageEvent) => {
|
||||
const replyGuideMsg = async (body: LarkEvent.Data) => {
|
||||
const chatId = getChatId(body);
|
||||
const content = JSON.stringify({
|
||||
type: "template",
|
||||
@ -131,7 +130,7 @@ const replyGuideMsg = async (body: LarkMessageEvent) => {
|
||||
},
|
||||
},
|
||||
});
|
||||
await lark.sendMsg("chat_id", chatId, "interactive", content);
|
||||
await service.lark.message.send("chat_id", chatId, "interactive", content);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -139,7 +138,7 @@ const replyGuideMsg = async (body: LarkMessageEvent) => {
|
||||
* @param {LarkUserAction} body
|
||||
* @returns {boolean} 是否在本函数中处理了消息
|
||||
*/
|
||||
export const manageEventMsg = (body: LarkMessageEvent) => {
|
||||
export const manageEventMsg = (body: LarkEvent.Data) => {
|
||||
// 过滤非Event消息
|
||||
if (!getIsEventMsg(body)) {
|
||||
return false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { manageActionMsg } from "./activeMsg";
|
||||
import { manageActionMsg } from "./actionMsg";
|
||||
import { manageEventMsg } from "./eventMsg";
|
||||
|
||||
export const manageBotReq = async (req: Request) => {
|
||||
|
@ -1,24 +1,9 @@
|
||||
import db from "../../db";
|
||||
import lark from "../../service/lark";
|
||||
import { MsgType, ReceiveIDType } from "../../types";
|
||||
import service from "../../services";
|
||||
import { LarkServer, MsgProxy } from "../../types";
|
||||
|
||||
interface BaseMsg {
|
||||
msg_type: MsgType;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface GroupMsg extends BaseMsg {
|
||||
group_id: string;
|
||||
}
|
||||
|
||||
interface NormalMsg extends BaseMsg {
|
||||
receive_id: string;
|
||||
receive_id_type: ReceiveIDType;
|
||||
}
|
||||
|
||||
type MessageReqJson = GroupMsg & NormalMsg;
|
||||
|
||||
const validateMessageReq = (body: MessageReqJson) => {
|
||||
const validateMessageReq = (body: MsgProxy.Body) => {
|
||||
if (!body.group_id && !body.receive_id) {
|
||||
return new Response("group_id or receive_id is required", { status: 400 });
|
||||
}
|
||||
@ -35,7 +20,7 @@ const validateMessageReq = (body: MessageReqJson) => {
|
||||
};
|
||||
|
||||
export const manageMessageReq = async (req: Request) => {
|
||||
const body = (await req.json()) as MessageReqJson;
|
||||
const body = (await req.json()) as MsgProxy.Body;
|
||||
// 校验参数
|
||||
const validateRes = validateMessageReq(body);
|
||||
if (validateRes) return validateRes;
|
||||
@ -68,11 +53,11 @@ export const manageMessageReq = async (req: Request) => {
|
||||
const { chat_id, open_id, union_id, user_id, email } = group;
|
||||
|
||||
// 构造发送消息函数
|
||||
const makeSendFunc = (receive_id_type: ReceiveIDType) => {
|
||||
const makeSendFunc = (receive_id_type: LarkServer.ReceiveIDType) => {
|
||||
return (receive_id: string) => {
|
||||
sendList.push(
|
||||
lark
|
||||
.sendMsg(receive_id_type, receive_id, body.msg_type, finalContent)
|
||||
service.lark.message
|
||||
.send(receive_id_type, receive_id, body.msg_type, finalContent)
|
||||
.then((res) => {
|
||||
sendRes[receive_id_type][receive_id] = res;
|
||||
})
|
||||
@ -90,8 +75,8 @@ export const manageMessageReq = async (req: Request) => {
|
||||
|
||||
if (body.receive_id && body.receive_id_type) {
|
||||
sendList.push(
|
||||
lark
|
||||
.sendMsg(
|
||||
service.lark.message
|
||||
.send(
|
||||
body.receive_id_type,
|
||||
body.receive_id,
|
||||
body.msg_type,
|
||||
|
@ -1 +0,0 @@
|
||||
# 批量发送消息,给已经订阅的用户和群组发送消息
|
7
routes/microApp/index.ts
Normal file
7
routes/microApp/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const manageMicroAppReq = async (req: Request) => {
|
||||
const url = new URL(req.url);
|
||||
const body = (await req.json()) as any;
|
||||
console.log("🚀 ~ manageMicroAppReq ~ body:", body);
|
||||
|
||||
return new Response("hello, glade to see you!");
|
||||
};
|
0
routes/microApp/login.ts
Normal file
0
routes/microApp/login.ts
Normal file
@ -1,37 +0,0 @@
|
||||
import { LarkMessageEvent } from "../types";
|
||||
|
||||
/**
|
||||
* 请求 CI 监控
|
||||
*/
|
||||
export const fetchCIMonitor = async (chat_id: string) => {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`https://ci-monitor.xiaomiwh.cn/ci?chat_id=${chat_id}`
|
||||
);
|
||||
return ((await res.json()) as string) || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 请求简报收集器
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
export const fetchReportCollector = async (body: LarkMessageEvent) => {
|
||||
const url = "https://report.imoaix.cn/report";
|
||||
// 将body作为请求体,post到url
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return ((await res.json()) as string) || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
125
service/lark.ts
125
service/lark.ts
@ -1,125 +0,0 @@
|
||||
import db from "../db";
|
||||
import { MsgType, ReceiveIDType, ServerResponse } from "../types";
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param func fetch
|
||||
* @returns
|
||||
*/
|
||||
const manageFetch = async (func: Function) => {
|
||||
try {
|
||||
const res = await func();
|
||||
const data = (await res.json()) as ServerResponse;
|
||||
console.log("🚀 ~ manageFetch ~ data:", data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.log("🚀 ~ manageFetch ~ error:", error);
|
||||
return {
|
||||
code: 1,
|
||||
data: null,
|
||||
msg: "sendMsg fetch error",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取header
|
||||
* @returns header
|
||||
*/
|
||||
const getHeaders = async () => {
|
||||
const tenant_access_token = await db.tenantAccessToken.get();
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${tenant_access_token}`,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送卡片
|
||||
* @param {ReceiveIDType} receive_id_type 消息接收者id类型 open_id/user_id/union_id/email/chat_id
|
||||
* @param {string} receive_id 消息接收者的ID,ID类型应与查询参数receive_id_type 对应
|
||||
* @param {MsgType} msg_type 消息类型 包括:text、post、image、file、audio、media、sticker、interactive、share_chat、share_user
|
||||
* @param {string} content 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容
|
||||
*/
|
||||
const sendMsg = async (
|
||||
receive_id_type: ReceiveIDType,
|
||||
receive_id: string,
|
||||
msg_type: MsgType,
|
||||
content: string
|
||||
) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/im/v1/messages?receive_id_type=${receive_id_type}`;
|
||||
const headers = await getHeaders();
|
||||
return await manageFetch(() =>
|
||||
fetch(URL, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({ receive_id, msg_type, content }),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新卡片
|
||||
* @param {string} message_id 消息id
|
||||
* @param {string} content 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容
|
||||
*/
|
||||
const updateCard = async (message_id: string, content: string) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/im/v1/messages/${message_id}`;
|
||||
const headers = await getHeaders();
|
||||
return await manageFetch(() =>
|
||||
fetch(URL, {
|
||||
method: "PATCH",
|
||||
headers,
|
||||
body: JSON.stringify({ content }),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送某人可见的卡片
|
||||
* @param {string} chat_id 对话流ID
|
||||
* @param {string} open_id 消息接收者的ID
|
||||
* @param {MsgType} msg_type 消息类型 包括:text、post、image、file、audio、media、sticker、interactive、share_chat、share_user
|
||||
* @param {*} card 消息卡片的描述内容,注意不是String
|
||||
*/
|
||||
const sendEphemeralMsg = async (
|
||||
chat_id: string,
|
||||
open_id: string,
|
||||
msg_type: MsgType,
|
||||
card: any
|
||||
) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/ephemeral/v1/send`;
|
||||
const headers = await getHeaders();
|
||||
return await manageFetch(() =>
|
||||
fetch(URL, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({ chat_id, open_id, msg_type, card }),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除某人可见的卡片
|
||||
* @param message_id 消息id
|
||||
*/
|
||||
const delEphemeralMsg = async (message_id: string) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/ephemeral/v1/delete`;
|
||||
const headers = await getHeaders();
|
||||
return await manageFetch(() =>
|
||||
fetch(URL, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({ message_id }),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const lark = {
|
||||
sendMsg,
|
||||
updateCard,
|
||||
sendEphemeralMsg,
|
||||
delEphemeralMsg,
|
||||
};
|
||||
|
||||
export default lark;
|
37
services/attach/index.ts
Normal file
37
services/attach/index.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { LarkEvent } from "../../types";
|
||||
import netTool from "../netTool";
|
||||
|
||||
/**
|
||||
* 请求 CI 监控
|
||||
*/
|
||||
const ciMonitor = async (chat_id: string) => {
|
||||
const URL = `https://ci-monitor.xiaomiwh.cn/ci?chat_id=${chat_id}`;
|
||||
try {
|
||||
const res = await netTool.get(URL);
|
||||
return (res as string) || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 请求简报收集器
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
const reportCollector = async (body: LarkEvent.Data) => {
|
||||
const URL = "https://report.imoaix.cn/report";
|
||||
try {
|
||||
const res = await netTool.post(URL, body);
|
||||
return (res as string) || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const attach = {
|
||||
ciMonitor,
|
||||
reportCollector,
|
||||
};
|
||||
|
||||
export default attach;
|
9
services/index.ts
Normal file
9
services/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import attach from "./attach";
|
||||
import lark from "./lark";
|
||||
|
||||
const service = {
|
||||
attach,
|
||||
lark,
|
||||
};
|
||||
|
||||
export default service;
|
10
services/lark/index.ts
Normal file
10
services/lark/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import message from "./message";
|
||||
import user from "./user";
|
||||
|
||||
|
||||
const lark = {
|
||||
message,
|
||||
user,
|
||||
};
|
||||
|
||||
export default lark;
|
63
services/lark/larkNetTool.ts
Normal file
63
services/lark/larkNetTool.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import db from "../../db";
|
||||
import { LarkServer } from "../../types";
|
||||
import netTool from "../netTool";
|
||||
|
||||
const larkNetTool = async <T = LarkServer.BaseRes>({
|
||||
url,
|
||||
method,
|
||||
params,
|
||||
data,
|
||||
headers,
|
||||
}: {
|
||||
url: string;
|
||||
method: string;
|
||||
params?: any;
|
||||
data?: any;
|
||||
headers?: any;
|
||||
}): Promise<T> => {
|
||||
const headersWithAuth = {
|
||||
Authorization: `Bearer ${await db.tenantAccessToken.get()}`,
|
||||
...headers,
|
||||
};
|
||||
return netTool<T>({
|
||||
url,
|
||||
method,
|
||||
params,
|
||||
data,
|
||||
headers: headersWithAuth,
|
||||
}).catch((error) => {
|
||||
console.error("网络请求异常", error);
|
||||
return {
|
||||
code: 1,
|
||||
data: null,
|
||||
msg: "网络请求异常",
|
||||
} as T;
|
||||
});
|
||||
};
|
||||
|
||||
larkNetTool.get = <T = LarkServer.BaseRes>(
|
||||
url: string,
|
||||
params?: any,
|
||||
headers?: any
|
||||
): Promise<T> => larkNetTool({ url, method: "get", params, headers });
|
||||
|
||||
larkNetTool.post = <T = LarkServer.BaseRes>(
|
||||
url: string,
|
||||
data?: any,
|
||||
params?: any,
|
||||
headers?: any
|
||||
): Promise<T> => larkNetTool({ url, method: "post", data, params, headers });
|
||||
|
||||
larkNetTool.del = <T = LarkServer.BaseRes>(
|
||||
url: string,
|
||||
data: any,
|
||||
headers?: any
|
||||
): Promise<T> => larkNetTool({ url, method: "delete", data, headers });
|
||||
|
||||
larkNetTool.patch = <T = LarkServer.BaseRes>(
|
||||
url: string,
|
||||
data: any,
|
||||
headers?: any
|
||||
): Promise<T> => larkNetTool({ url, method: "patch", data, headers });
|
||||
|
||||
export default larkNetTool;
|
40
services/lark/message.ts
Normal file
40
services/lark/message.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { LarkServer } from "../../types/larkServer";
|
||||
import larkNetTool from "./larkNetTool";
|
||||
|
||||
/**
|
||||
* 发送卡片
|
||||
* @param {LarkServer.ReceiveIDType} receive_id_type 消息接收者id类型 open_id/user_id/union_id/email/chat_id
|
||||
* @param {string} receive_id 消息接收者的ID,ID类型应与查询参数receive_id_type 对应
|
||||
* @param {MsgType} msg_type 消息类型 包括:text、post、image、file、audio、media、sticker、interactive、share_chat、share_user
|
||||
* @param {string} content 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容
|
||||
*/
|
||||
const send = async (
|
||||
receive_id_type: LarkServer.ReceiveIDType,
|
||||
receive_id: string,
|
||||
msg_type: LarkServer.MsgType,
|
||||
content: string
|
||||
) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/im/v1/messages?receive_id_type=${receive_id_type}`;
|
||||
return larkNetTool.post<LarkServer.BaseRes>(URL, {
|
||||
receive_id,
|
||||
msg_type,
|
||||
content,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新卡片
|
||||
* @param {string} message_id 消息id
|
||||
* @param {string} content 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容
|
||||
*/
|
||||
const update = async (message_id: string, content: string) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/im/v1/messages/${message_id}`;
|
||||
return larkNetTool.patch<LarkServer.BaseRes>(URL, { content });
|
||||
};
|
||||
|
||||
const message = {
|
||||
send,
|
||||
update,
|
||||
};
|
||||
|
||||
export default message;
|
45
services/lark/user.ts
Normal file
45
services/lark/user.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { LarkServer } from "../../types/larkServer";
|
||||
import larkNetTool from "./larkNetTool";
|
||||
|
||||
/**
|
||||
* 登录凭证校验
|
||||
* @param code
|
||||
* @returns
|
||||
*/
|
||||
const code2Session = async (code: string) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/mina/v2/tokenLoginValidate`;
|
||||
return larkNetTool.post<LarkServer.UserSessionRes>(URL, { code });
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param user_id
|
||||
* @returns
|
||||
*/
|
||||
const getUser = async (user_id: string) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/contact/v3/users/${user_id}`;
|
||||
return larkNetTool.get<LarkServer.UserInfoRes>(URL, {
|
||||
user_id_type: "user_id",
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量获取用户信息
|
||||
* @param user_ids
|
||||
* @returns
|
||||
*/
|
||||
const getMultiUser = async (user_ids: string[]) => {
|
||||
const URL = `https://open.f.mioffice.cn/open-apis/user/v1/batch_get`;
|
||||
return larkNetTool.get<LarkServer.UserInfoRes>(URL, {
|
||||
user_ids,
|
||||
user_id_type: "user_id",
|
||||
});
|
||||
};
|
||||
|
||||
const user = {
|
||||
code2Session,
|
||||
getMultiUser,
|
||||
getUser,
|
||||
};
|
||||
|
||||
export default user;
|
53
services/netTool.ts
Normal file
53
services/netTool.ts
Normal file
@ -0,0 +1,53 @@
|
||||
interface NetGetParams {
|
||||
url: string;
|
||||
method: string;
|
||||
params?: any;
|
||||
data?: any;
|
||||
headers?: any;
|
||||
}
|
||||
|
||||
const netTool = <T = any>({
|
||||
url,
|
||||
method,
|
||||
params,
|
||||
data,
|
||||
headers,
|
||||
}: NetGetParams): Promise<T> => {
|
||||
let fullUrl = url;
|
||||
if (params) {
|
||||
const queryString = new URLSearchParams(params).toString();
|
||||
fullUrl = `${url}?${queryString}`;
|
||||
}
|
||||
|
||||
return fetch(fullUrl, {
|
||||
method,
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...headers,
|
||||
},
|
||||
}).then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("网络响应异常");
|
||||
}
|
||||
return response.json() as Promise<T>;
|
||||
});
|
||||
};
|
||||
|
||||
netTool.get = <T = any>(url: string, params?: any, headers?: any): Promise<T> =>
|
||||
netTool({ url, method: "get", params, headers });
|
||||
|
||||
netTool.post = <T = any>(
|
||||
url: string,
|
||||
data?: any,
|
||||
params?: any,
|
||||
headers?: any
|
||||
): Promise<T> => netTool({ url, method: "post", data, params, headers });
|
||||
|
||||
netTool.del = <T = any>(url: string, data: any, headers?: any): Promise<T> =>
|
||||
netTool({ url, method: "delete", data, headers });
|
||||
|
||||
netTool.patch = <T = any>(url: string, data: any, headers?: any): Promise<T> =>
|
||||
netTool({ url, method: "patch", data, headers });
|
||||
|
||||
export default netTool;
|
21
types/db.ts
Normal file
21
types/db.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { RecordModel } from "pocketbase";
|
||||
|
||||
export namespace DB {
|
||||
export interface AppConfig extends RecordModel {
|
||||
value: string;
|
||||
}
|
||||
export interface MessageGroup extends RecordModel {
|
||||
collectionId: string;
|
||||
collectionName: string;
|
||||
updated: string;
|
||||
created: string;
|
||||
desc: string;
|
||||
id: string;
|
||||
name: string;
|
||||
email?: string[];
|
||||
chat_id?: string[];
|
||||
open_id?: string[];
|
||||
union_id?: string[];
|
||||
user_id?: string[];
|
||||
}
|
||||
}
|
471
types/index.ts
471
types/index.ts
@ -1,466 +1,7 @@
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
export interface User {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
userId: string;
|
||||
/**
|
||||
* open_id
|
||||
*/
|
||||
openId: string;
|
||||
/**
|
||||
* 提醒列表
|
||||
*/
|
||||
remindList: string[];
|
||||
}
|
||||
import type { DB } from "./db";
|
||||
import type { LarkAction } from "./larkAction";
|
||||
import type { LarkEvent } from "./larkEvent";
|
||||
import type { LarkServer } from "./larkServer";
|
||||
import type { MsgProxy } from "./msgProxy";
|
||||
|
||||
/**
|
||||
* 提醒列表
|
||||
*/
|
||||
export interface Remind {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 所有者信息,绑定用户表的id
|
||||
*/
|
||||
owner: string;
|
||||
/**
|
||||
* 消息Id
|
||||
*/
|
||||
messageId: string;
|
||||
/**
|
||||
* 接收者类型
|
||||
*/
|
||||
subscriberType: "open_id" | "user_id" | "union_id" | "email" | "chat_id";
|
||||
/**
|
||||
* 接收者Id
|
||||
*/
|
||||
subscriberId: string;
|
||||
/**
|
||||
* 是否需要回复,不需要回复的也不会重复提醒
|
||||
*/
|
||||
needReply: boolean;
|
||||
/**
|
||||
* 延迟时间
|
||||
*/
|
||||
delayTime: number;
|
||||
/**
|
||||
* 卡片信息,用于绘制初始卡片、确认卡片、取消卡片、延迟卡片
|
||||
*/
|
||||
cardInfo: {
|
||||
/**
|
||||
* 提醒标题,必须要有
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* 插图key
|
||||
*/
|
||||
imageKey?: string;
|
||||
/**
|
||||
* 提醒内容,为空不显示
|
||||
*/
|
||||
content?: string;
|
||||
/**
|
||||
* 确认文本,为空不显示,为需要回复卡片时,如果为空则默认为“完成”
|
||||
*/
|
||||
confirmText?: string;
|
||||
/**
|
||||
* 取消文本,为空不显示
|
||||
*/
|
||||
cancelText?: string;
|
||||
/**
|
||||
* 延迟文本,为空不显示
|
||||
*/
|
||||
delayText?: string;
|
||||
} | null;
|
||||
/**
|
||||
* 卡片模板信息
|
||||
*/
|
||||
templateInfo: {
|
||||
/**
|
||||
* 卡片模板ID,会注入变量
|
||||
* ${owner} 所有者
|
||||
* ${remindTime} 提醒时间
|
||||
*/
|
||||
pendingTemplateId: string;
|
||||
/**
|
||||
* 交互之后的卡片模板ID,如果有这个就不会用下边三个但是都会注入变量
|
||||
* ${owner} 所有者
|
||||
* ${remindTime} 提醒时间
|
||||
* ${result} 交互结果,会读卡片按钮绑定的变量text,如果没有则是绑定的result对应的 已确认、已取消、已延迟
|
||||
* ${interactTime} 交互时间
|
||||
*/
|
||||
interactedTemplateId: string;
|
||||
/**
|
||||
* 确认之后的卡片模板ID
|
||||
*/
|
||||
confirmedTemplateId: string;
|
||||
/**
|
||||
* 取消之后的卡片模板ID
|
||||
*/
|
||||
cancelededTemplateId: string;
|
||||
/**
|
||||
* 延迟之后的卡片模板ID
|
||||
*/
|
||||
delayedTemplateId: string;
|
||||
} | null;
|
||||
|
||||
/**
|
||||
* 提醒时间
|
||||
*/
|
||||
remindTimes: RemindTime[];
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
enabled: boolean;
|
||||
/**
|
||||
* 下次提醒的时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
nextRemindTime: string;
|
||||
/**
|
||||
* 下次提醒时间的中文
|
||||
*/
|
||||
nextRemindTimeCHS: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提醒时间
|
||||
* 为了支持多个时间点提醒,将时间存成数组
|
||||
*/
|
||||
export interface RemindTime {
|
||||
/**
|
||||
* 重复类型
|
||||
* single: 一次性
|
||||
* daily: 每天
|
||||
* weekly: 每周
|
||||
* monthly: 每月
|
||||
* yearly: 每年
|
||||
* workday: 工作日
|
||||
* holiday: 节假日
|
||||
*/
|
||||
frequency:
|
||||
| "single"
|
||||
| "daily"
|
||||
| "weekly"
|
||||
| "monthly"
|
||||
| "yearly"
|
||||
| "workday"
|
||||
| "holiday";
|
||||
/**
|
||||
* 提醒时间,格式为HH:mm, single类型时仅作展示用,类型为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
time: string;
|
||||
/**
|
||||
* 星期几[1-7],当frequency为weekly时有效
|
||||
*/
|
||||
daysOfWeek: number[];
|
||||
/**
|
||||
* 每月的几号[1-31],当frequency为monthly时有效
|
||||
*/
|
||||
daysOfMonth: number[];
|
||||
/**
|
||||
* 每年的哪天提醒,当frequency为 yearly 时有效,格式为MM-dd
|
||||
*/
|
||||
dayOfYear: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提醒记录
|
||||
* 记录提醒时间,回答结果等
|
||||
*/
|
||||
export interface RemindRecord {
|
||||
/**
|
||||
* 记录Id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 关联的提醒Id
|
||||
*/
|
||||
remindId: string;
|
||||
/**
|
||||
* 发送的卡片Id
|
||||
*/
|
||||
messageId: string;
|
||||
/**
|
||||
* 提醒状态
|
||||
* pending: 待确认
|
||||
* delay: 已延迟
|
||||
* confirmed: 已确认
|
||||
* canceled: 已取消
|
||||
*/
|
||||
status: "pending" | "delayed" | "confirmed" | "canceled";
|
||||
/**
|
||||
* 本次提醒时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
remindTime: string;
|
||||
/**
|
||||
* 用户交互的时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
interactTime: string;
|
||||
/**
|
||||
* 用户回答的结果,类似每天 07:00
|
||||
*/
|
||||
result: object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息事件头
|
||||
*/
|
||||
export interface Header {
|
||||
/**
|
||||
* 事件ID
|
||||
* @example 0f8ab23b60993cf8dd15c8cde4d7b0f5
|
||||
*/
|
||||
event_id: string;
|
||||
/**
|
||||
* token
|
||||
* @example tV9djUKSjzVnekV7xTg2Od06NFTcsBnj
|
||||
*/
|
||||
token: string;
|
||||
/**
|
||||
* 创建时间戳
|
||||
* @example 1693565712117
|
||||
*/
|
||||
create_time: string;
|
||||
/**
|
||||
* 事件类型
|
||||
* @example im.message.receive_v1
|
||||
*/
|
||||
event_type: string;
|
||||
/**
|
||||
* tenant_key
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
/**
|
||||
* app_id
|
||||
* @example cli_a1eff35b43b89063
|
||||
*/
|
||||
app_id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户ID信息
|
||||
*/
|
||||
export interface UserIdInfo {
|
||||
/**
|
||||
* 用户标记
|
||||
* @example ou_032f507d08f9a7f28b042fcd086daef5
|
||||
*/
|
||||
open_id: string;
|
||||
/**
|
||||
* 用户标记
|
||||
* @example on_7111660fddd8302ce47bf1999147c011
|
||||
*/
|
||||
union_id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
user_id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 被AT的人的信息
|
||||
*/
|
||||
export interface Mention {
|
||||
/**
|
||||
* 被艾特的人的ID信息
|
||||
*/
|
||||
id: UserIdInfo;
|
||||
/**
|
||||
* 对应到文本内的内容
|
||||
* @example "@_user_1"
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example 小煎蛋
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内容信息
|
||||
*/
|
||||
export interface Message {
|
||||
/**
|
||||
* 对话流ID
|
||||
* @example oc_433b1cb7a9dbb7ebe70a4e1a59cb8bb1
|
||||
*/
|
||||
chat_id: string;
|
||||
/**
|
||||
* 消息类型
|
||||
* @example group | p2p
|
||||
*/
|
||||
chat_type: "group" | "p2p";
|
||||
/**
|
||||
* JSON字符串文本内容
|
||||
* @example "{\"text\":\"@_user_1 测试\"}"
|
||||
*/
|
||||
content: string;
|
||||
/**
|
||||
* 消息发送时间戳
|
||||
* @example 1693565711996
|
||||
*/
|
||||
create_time: string;
|
||||
/**
|
||||
* 被艾特的人信息
|
||||
*/
|
||||
mentions?: Mention[];
|
||||
/**
|
||||
* 当前消息的ID
|
||||
* @example om_038fc0eceed6224a1abc1cdaa4266405
|
||||
*/
|
||||
message_id: string;
|
||||
/**
|
||||
* 消息类型
|
||||
* @example text、post、image、file、audio、media、sticker、interactive、share_chat、share_user
|
||||
*/
|
||||
message_type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送者信息
|
||||
*/
|
||||
export interface Sender {
|
||||
/**
|
||||
* id 相关信息
|
||||
*/
|
||||
sender_id: UserIdInfo;
|
||||
/**
|
||||
* 发送者类型
|
||||
* @example user
|
||||
*/
|
||||
sender_type: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件详情
|
||||
*/
|
||||
export interface Event {
|
||||
message: Message;
|
||||
sender: Sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件订阅信息
|
||||
*/
|
||||
export interface LarkMessageEvent {
|
||||
/**
|
||||
* 协议版本
|
||||
* @example 2.0
|
||||
*/
|
||||
schema: string;
|
||||
/**
|
||||
* 事件头
|
||||
*/
|
||||
header: Header;
|
||||
/**
|
||||
* 事件详情
|
||||
*/
|
||||
event: Event;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户Action信息
|
||||
*/
|
||||
export interface LarkUserAction {
|
||||
/**
|
||||
* open_id
|
||||
*/
|
||||
open_id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
user_id: string;
|
||||
/**
|
||||
* 当前消息的ID
|
||||
* @example om_038fc0eceed6224a1abc1cdaa4266405
|
||||
*/
|
||||
open_message_id: string;
|
||||
/**
|
||||
* 对话流ID
|
||||
* @example oc_433b1cb7a9dbb7ebe70a4e1a59cb8bb1
|
||||
*/
|
||||
open_chat_id: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
/**
|
||||
* token
|
||||
* @example tV9djUKSjzVnekV7xTg2Od06NFTcsBnj
|
||||
*/
|
||||
token: string;
|
||||
/**
|
||||
* 事件结果
|
||||
*/
|
||||
action: {
|
||||
/**
|
||||
* 传的参数
|
||||
*/
|
||||
value: any;
|
||||
/**
|
||||
* 标签名
|
||||
* @example picker_datetime
|
||||
*/
|
||||
tag: string;
|
||||
/**
|
||||
* 选择的事件
|
||||
* @example 2023-09-03 10:35 +0800
|
||||
*/
|
||||
option: string;
|
||||
/**
|
||||
* 时区
|
||||
*/
|
||||
timezone: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ReceiveIDType =
|
||||
| "open_id"
|
||||
| "user_id"
|
||||
| "union_id"
|
||||
| "email"
|
||||
| "chat_id";
|
||||
|
||||
export type MsgType =
|
||||
| "text"
|
||||
| "post"
|
||||
| "image"
|
||||
| "file"
|
||||
| "audio"
|
||||
| "media"
|
||||
| "sticker"
|
||||
| "interactive"
|
||||
| "share_chat"
|
||||
| "share_user";
|
||||
|
||||
export interface ServerResponse {
|
||||
code: number;
|
||||
data: any;
|
||||
msg: string;
|
||||
}
|
||||
export { DB, LarkAction, LarkEvent, LarkServer, MsgProxy };
|
||||
|
56
types/larkAction.ts
Normal file
56
types/larkAction.ts
Normal file
@ -0,0 +1,56 @@
|
||||
export namespace LarkAction {
|
||||
export interface Data {
|
||||
/**
|
||||
* open_id
|
||||
*/
|
||||
open_id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
user_id: string;
|
||||
/**
|
||||
* 当前消息的ID
|
||||
* @example om_038fc0eceed6224a1abc1cdaa4266405
|
||||
*/
|
||||
open_message_id: string;
|
||||
/**
|
||||
* 对话流ID
|
||||
* @example oc_433b1cb7a9dbb7ebe70a4e1a59cb8bb1
|
||||
*/
|
||||
open_chat_id: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
/**
|
||||
* token
|
||||
* @example tV9djUKSjzVnekV7xTg2Od06NFTcsBnj
|
||||
*/
|
||||
token: string;
|
||||
/**
|
||||
* 事件结果
|
||||
*/
|
||||
action: {
|
||||
/**
|
||||
* 传的参数
|
||||
*/
|
||||
value: any;
|
||||
/**
|
||||
* 标签名
|
||||
* @example picker_datetime
|
||||
*/
|
||||
tag: string;
|
||||
/**
|
||||
* 选择的事件
|
||||
* @example 2023-09-03 10:35 +0800
|
||||
*/
|
||||
option: string;
|
||||
/**
|
||||
* 时区
|
||||
*/
|
||||
timezone: string;
|
||||
};
|
||||
}
|
||||
}
|
163
types/larkEvent.ts
Normal file
163
types/larkEvent.ts
Normal file
@ -0,0 +1,163 @@
|
||||
export namespace LarkEvent {
|
||||
/**
|
||||
* 消息事件头
|
||||
*/
|
||||
export interface Header {
|
||||
/**
|
||||
* 事件ID
|
||||
* @example 0f8ab23b60993cf8dd15c8cde4d7b0f5
|
||||
*/
|
||||
event_id: string;
|
||||
/**
|
||||
* token
|
||||
* @example tV9djUKSjzVnekV7xTg2Od06NFTcsBnj
|
||||
*/
|
||||
token: string;
|
||||
/**
|
||||
* 创建时间戳
|
||||
* @example 1693565712117
|
||||
*/
|
||||
create_time: string;
|
||||
/**
|
||||
* 事件类型
|
||||
* @example im.message.receive_v1
|
||||
*/
|
||||
event_type: string;
|
||||
/**
|
||||
* tenant_key
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
/**
|
||||
* app_id
|
||||
* @example cli_a1eff35b43b89063
|
||||
*/
|
||||
app_id: string;
|
||||
}
|
||||
/**
|
||||
* 被AT的人的信息
|
||||
*/
|
||||
export interface Mention {
|
||||
/**
|
||||
* 被艾特的人的ID信息
|
||||
*/
|
||||
id: UserIdInfo;
|
||||
/**
|
||||
* 对应到文本内的内容
|
||||
* @example "@_user_1"
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example 小煎蛋
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
}
|
||||
/**
|
||||
* 消息内容信息
|
||||
*/
|
||||
export interface Message {
|
||||
/**
|
||||
* 对话流ID
|
||||
* @example oc_433b1cb7a9dbb7ebe70a4e1a59cb8bb1
|
||||
*/
|
||||
chat_id: string;
|
||||
/**
|
||||
* 消息类型
|
||||
* @example group | p2p
|
||||
*/
|
||||
chat_type: "group" | "p2p";
|
||||
/**
|
||||
* JSON字符串文本内容
|
||||
* @example "{\"text\":\"@_user_1 测试\"}"
|
||||
*/
|
||||
content: string;
|
||||
/**
|
||||
* 消息发送时间戳
|
||||
* @example 1693565711996
|
||||
*/
|
||||
create_time: string;
|
||||
/**
|
||||
* 被艾特的人信息
|
||||
*/
|
||||
mentions?: Mention[];
|
||||
/**
|
||||
* 当前消息的ID
|
||||
* @example om_038fc0eceed6224a1abc1cdaa4266405
|
||||
*/
|
||||
message_id: string;
|
||||
/**
|
||||
* 消息类型
|
||||
* @example text、post、image、file、audio、media、sticker、interactive、share_chat、share_user
|
||||
*/
|
||||
message_type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户ID信息
|
||||
*/
|
||||
export interface UserIdInfo {
|
||||
/**
|
||||
* 用户标记
|
||||
* @example ou_032f507d08f9a7f28b042fcd086daef5
|
||||
*/
|
||||
open_id: string;
|
||||
/**
|
||||
* 用户标记
|
||||
* @example on_7111660fddd8302ce47bf1999147c011
|
||||
*/
|
||||
union_id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
user_id: string;
|
||||
}
|
||||
/**
|
||||
* 消息发送者信息
|
||||
*/
|
||||
export interface Sender {
|
||||
/**
|
||||
* id 相关信息
|
||||
*/
|
||||
sender_id: UserIdInfo;
|
||||
/**
|
||||
* 发送者类型
|
||||
* @example user
|
||||
*/
|
||||
sender_type: string;
|
||||
/**
|
||||
* 应用ID
|
||||
* @example 2ee61fe50f4f1657
|
||||
*/
|
||||
tenant_key: string;
|
||||
}
|
||||
/**
|
||||
* 事件详情
|
||||
*/
|
||||
export interface Event {
|
||||
message: Message;
|
||||
sender: Sender;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
/**
|
||||
* 协议版本
|
||||
* @example 2.0
|
||||
*/
|
||||
schema: string;
|
||||
/**
|
||||
* 事件头
|
||||
*/
|
||||
header: Header;
|
||||
/**
|
||||
* 事件详情
|
||||
*/
|
||||
event: Event;
|
||||
}
|
||||
}
|
78
types/larkServer.ts
Normal file
78
types/larkServer.ts
Normal file
@ -0,0 +1,78 @@
|
||||
export namespace LarkServer {
|
||||
export interface UserSession {
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
access_token: string;
|
||||
|
||||
/**
|
||||
* 员工ID
|
||||
*/
|
||||
employee_id: string;
|
||||
|
||||
/**
|
||||
* 令牌过期时间
|
||||
*/
|
||||
expires_in: number;
|
||||
|
||||
/**
|
||||
* 开放ID
|
||||
*/
|
||||
open_id: string;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
refresh_token: string;
|
||||
|
||||
/**
|
||||
* 会话密钥
|
||||
*/
|
||||
session_key: string;
|
||||
|
||||
/**
|
||||
* 租户密钥
|
||||
*/
|
||||
tenant_key: string;
|
||||
|
||||
/**
|
||||
* 联盟ID
|
||||
*/
|
||||
union_id: string;
|
||||
}
|
||||
|
||||
export interface BaseRes {
|
||||
code: number;
|
||||
data: any;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
export interface UserSessionRes extends BaseRes {
|
||||
data: UserSession;
|
||||
}
|
||||
|
||||
export interface UserInfoRes extends BaseRes {
|
||||
data: {
|
||||
user: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type ReceiveIDType =
|
||||
| "open_id"
|
||||
| "user_id"
|
||||
| "union_id"
|
||||
| "email"
|
||||
| "chat_id";
|
||||
|
||||
export type MsgType =
|
||||
| "text"
|
||||
| "post"
|
||||
| "image"
|
||||
| "file"
|
||||
| "audio"
|
||||
| "media"
|
||||
| "sticker"
|
||||
| "interactive"
|
||||
| "share_chat"
|
||||
| "share_user";
|
||||
}
|
16
types/msgProxy.ts
Normal file
16
types/msgProxy.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { LarkServer } from "./larkServer";
|
||||
|
||||
export namespace MsgProxy {
|
||||
export interface BaseBody {
|
||||
msg_type: LarkServer.MsgType;
|
||||
content: string;
|
||||
}
|
||||
export interface GroupBody extends BaseBody {
|
||||
group_id: string;
|
||||
}
|
||||
export interface NormalBody extends BaseBody {
|
||||
receive_id: string;
|
||||
receive_id_type: LarkServer.ReceiveIDType;
|
||||
}
|
||||
export type Body = GroupBody & NormalBody;
|
||||
}
|
214
types/remind.ts
Normal file
214
types/remind.ts
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
export interface User {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 用户名
|
||||
* @example zhaoyingbo
|
||||
*/
|
||||
userId: string;
|
||||
/**
|
||||
* open_id
|
||||
*/
|
||||
openId: string;
|
||||
/**
|
||||
* 提醒列表
|
||||
*/
|
||||
remindList: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 提醒列表
|
||||
*/
|
||||
export interface Remind {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 所有者信息,绑定用户表的id
|
||||
*/
|
||||
owner: string;
|
||||
/**
|
||||
* 消息Id
|
||||
*/
|
||||
messageId: string;
|
||||
/**
|
||||
* 接收者类型
|
||||
*/
|
||||
subscriberType: "open_id" | "user_id" | "union_id" | "email" | "chat_id";
|
||||
/**
|
||||
* 接收者Id
|
||||
*/
|
||||
subscriberId: string;
|
||||
/**
|
||||
* 是否需要回复,不需要回复的也不会重复提醒
|
||||
*/
|
||||
needReply: boolean;
|
||||
/**
|
||||
* 延迟时间
|
||||
*/
|
||||
delayTime: number;
|
||||
/**
|
||||
* 卡片信息,用于绘制初始卡片、确认卡片、取消卡片、延迟卡片
|
||||
*/
|
||||
cardInfo: {
|
||||
/**
|
||||
* 提醒标题,必须要有
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* 插图key
|
||||
*/
|
||||
imageKey?: string;
|
||||
/**
|
||||
* 提醒内容,为空不显示
|
||||
*/
|
||||
content?: string;
|
||||
/**
|
||||
* 确认文本,为空不显示,为需要回复卡片时,如果为空则默认为“完成”
|
||||
*/
|
||||
confirmText?: string;
|
||||
/**
|
||||
* 取消文本,为空不显示
|
||||
*/
|
||||
cancelText?: string;
|
||||
/**
|
||||
* 延迟文本,为空不显示
|
||||
*/
|
||||
delayText?: string;
|
||||
} | null;
|
||||
/**
|
||||
* 卡片模板信息
|
||||
*/
|
||||
templateInfo: {
|
||||
/**
|
||||
* 卡片模板ID,会注入变量
|
||||
* ${owner} 所有者
|
||||
* ${remindTime} 提醒时间
|
||||
*/
|
||||
pendingTemplateId: string;
|
||||
/**
|
||||
* 交互之后的卡片模板ID,如果有这个就不会用下边三个但是都会注入变量
|
||||
* ${owner} 所有者
|
||||
* ${remindTime} 提醒时间
|
||||
* ${result} 交互结果,会读卡片按钮绑定的变量text,如果没有则是绑定的result对应的 已确认、已取消、已延迟
|
||||
* ${interactTime} 交互时间
|
||||
*/
|
||||
interactedTemplateId: string;
|
||||
/**
|
||||
* 确认之后的卡片模板ID
|
||||
*/
|
||||
confirmedTemplateId: string;
|
||||
/**
|
||||
* 取消之后的卡片模板ID
|
||||
*/
|
||||
cancelededTemplateId: string;
|
||||
/**
|
||||
* 延迟之后的卡片模板ID
|
||||
*/
|
||||
delayedTemplateId: string;
|
||||
} | null;
|
||||
|
||||
/**
|
||||
* 提醒时间
|
||||
*/
|
||||
remindTimes: RemindTime[];
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
enabled: boolean;
|
||||
/**
|
||||
* 下次提醒的时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
nextRemindTime: string;
|
||||
/**
|
||||
* 下次提醒时间的中文
|
||||
*/
|
||||
nextRemindTimeCHS: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提醒时间
|
||||
* 为了支持多个时间点提醒,将时间存成数组
|
||||
*/
|
||||
export interface RemindTime {
|
||||
/**
|
||||
* 重复类型
|
||||
* single: 一次性
|
||||
* daily: 每天
|
||||
* weekly: 每周
|
||||
* monthly: 每月
|
||||
* yearly: 每年
|
||||
* workday: 工作日
|
||||
* holiday: 节假日
|
||||
*/
|
||||
frequency:
|
||||
| "single"
|
||||
| "daily"
|
||||
| "weekly"
|
||||
| "monthly"
|
||||
| "yearly"
|
||||
| "workday"
|
||||
| "holiday";
|
||||
/**
|
||||
* 提醒时间,格式为HH:mm, single类型时仅作展示用,类型为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
time: string;
|
||||
/**
|
||||
* 星期几[1-7],当frequency为weekly时有效
|
||||
*/
|
||||
daysOfWeek: number[];
|
||||
/**
|
||||
* 每月的几号[1-31],当frequency为monthly时有效
|
||||
*/
|
||||
daysOfMonth: number[];
|
||||
/**
|
||||
* 每年的哪天提醒,当frequency为 yearly 时有效,格式为MM-dd
|
||||
*/
|
||||
dayOfYear: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提醒记录
|
||||
* 记录提醒时间,回答结果等
|
||||
*/
|
||||
export interface RemindRecord {
|
||||
/**
|
||||
* 记录Id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 关联的提醒Id
|
||||
*/
|
||||
remindId: string;
|
||||
/**
|
||||
* 发送的卡片Id
|
||||
*/
|
||||
messageId: string;
|
||||
/**
|
||||
* 提醒状态
|
||||
* pending: 待确认
|
||||
* delay: 已延迟
|
||||
* confirmed: 已确认
|
||||
* canceled: 已取消
|
||||
*/
|
||||
status: "pending" | "delayed" | "confirmed" | "canceled";
|
||||
/**
|
||||
* 本次提醒时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
remindTime: string;
|
||||
/**
|
||||
* 用户交互的时间,格式为yyyy-MM-dd HH:mm
|
||||
*/
|
||||
interactTime: string;
|
||||
/**
|
||||
* 用户回答的结果,类似每天 07:00
|
||||
*/
|
||||
result: object;
|
||||
}
|
@ -1,63 +1,63 @@
|
||||
import { LarkMessageEvent, LarkUserAction } from "../types";
|
||||
import { LarkAction, LarkEvent } from "../types";
|
||||
|
||||
/**
|
||||
* 是否为事件消息
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
*/
|
||||
export const getIsEventMsg = (body: LarkMessageEvent) => {
|
||||
export const getIsEventMsg = (body: LarkEvent.Data) => {
|
||||
return body?.header?.event_type === "im.message.receive_v1";
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取事件文本类型
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns
|
||||
*/
|
||||
export const getMsgType = (body: LarkMessageEvent) => {
|
||||
export const getMsgType = (body: LarkEvent.Data) => {
|
||||
return body?.event?.message?.message_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取对话流Id
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns
|
||||
*/
|
||||
export const getChatId = (body: LarkMessageEvent) => {
|
||||
export const getChatId = (body: LarkEvent.Data) => {
|
||||
return body?.event?.message?.chat_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户Id
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns
|
||||
*/
|
||||
export const getUserId = (body: LarkMessageEvent) => {
|
||||
export const getUserId = (body: LarkEvent.Data) => {
|
||||
return body?.event?.sender?.sender_id?.user_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* 是否为Action消息
|
||||
* @param {LarkUserAction} body
|
||||
* @param {LarkAction.Data} body
|
||||
*/
|
||||
export const getIsActionMsg = (body: LarkUserAction) => {
|
||||
export const getIsActionMsg = (body: LarkAction.Data) => {
|
||||
return body?.action;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取Action类型
|
||||
* @param {LarkUserAction} body
|
||||
* @param {LarkAction.Data} body
|
||||
* @returns {string} Action类型
|
||||
*/
|
||||
export const getActionType = (body: LarkUserAction) => {
|
||||
export const getActionType = (body: LarkAction.Data) => {
|
||||
return body?.action?.tag;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取文本内容并剔除艾特信息
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns {string} 文本内容
|
||||
*/
|
||||
export const getMsgText = (body: LarkMessageEvent) => {
|
||||
export const getMsgText = (body: LarkEvent.Data) => {
|
||||
try {
|
||||
const { text }: { text: string } = JSON.parse(
|
||||
body?.event?.message?.content
|
||||
@ -74,18 +74,18 @@ export const getMsgText = (body: LarkMessageEvent) => {
|
||||
|
||||
/**
|
||||
* 获取聊天类型
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns {string} 聊天类型
|
||||
*/
|
||||
export const getChatType = (body: LarkMessageEvent) => {
|
||||
export const getChatType = (body: LarkEvent.Data) => {
|
||||
return body?.event?.message?.chat_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取艾特信息
|
||||
* @param {LarkMessageEvent} body
|
||||
* @param {LarkEvent.Data} body
|
||||
* @returns {Array} 艾特信息
|
||||
*/
|
||||
export const getMentions = (body: LarkMessageEvent) => {
|
||||
export const getMentions = (body: LarkEvent.Data) => {
|
||||
return body?.event?.message?.mentions;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user