feat: 优化请求处理 & 拆分Type
All checks were successful
Egg CI/CD / build-image (push) Successful in 49s
Egg CI/CD / deploy (push) Successful in 23s

This commit is contained in:
zhaoyingbo 2024-06-08 09:15:14 +00:00
parent ae199d661e
commit b7437f47e4
27 changed files with 884 additions and 720 deletions

View File

@ -1,10 +1,6 @@
import { RecordModel } from "pocketbase";
import pbClient from "../pbClient"; import pbClient from "../pbClient";
import { managePb404 } from "../../utils/pbTools"; import { managePb404 } from "../../utils/pbTools";
import { DB } from "../../types";
export interface AppConfigRecordModel extends RecordModel {
value: string;
}
/** /**
* *
@ -12,7 +8,7 @@ export interface AppConfigRecordModel extends RecordModel {
* @returns * @returns
*/ */
const get = async (key: string) => { const get = async (key: string) => {
const config = await managePb404<AppConfigRecordModel>( const config = await managePb404<DB.AppConfig>(
async () => async () =>
await await pbClient.collection("config").getFirstListItem(`key='${key}'`) await await pbClient.collection("config").getFirstListItem(`key='${key}'`)
); );

View File

@ -1,23 +1,9 @@
import { DB } from "../../types";
import { managePb404 } from "../../utils/pbTools"; import { managePb404 } from "../../utils/pbTools";
import pbClient from "../pbClient"; 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) => const getOne = (groupId: string) =>
managePb404<PBMessageGroup>( managePb404<DB.MessageGroup>(
async () => await pbClient.collection("message_group").getOne(groupId) async () => await pbClient.collection("message_group").getOne(groupId)
); );

View File

@ -1,5 +1,6 @@
import { manageBotReq } from "./routes/bot"; import { manageBotReq } from "./routes/bot";
import { manageMessageReq } from "./routes/message"; import { manageMessageReq } from "./routes/message";
import { manageMicroAppReq } from "./routes/microApp";
import { initSchedule } from "./schedule"; import { initSchedule } from "./schedule";
initSchedule(); initSchedule();
@ -14,6 +15,8 @@ Bun.serve({
if (url.pathname === "/bot") return await manageBotReq(req); if (url.pathname === "/bot") return await manageBotReq(req);
// 消息代理发送 // 消息代理发送
if (url.pathname === "/message") return await manageMessageReq(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!"); return new Response("hello, glade to see you!");
} catch (error: any) { } catch (error: any) {

View File

@ -1,9 +1,14 @@
import { sleep } from "bun"; import { sleep } from "bun";
import { getActionType, getIsActionMsg } from "../../utils/msgTools"; 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); await sleep(500);
return JSON.stringify({ return JSON.stringify({
type: "template", 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 { const { action } = body?.action?.value as {
action: keyof typeof ACTION_MAP; action: keyof typeof ACTION_MAP;
}; };
@ -37,15 +42,15 @@ const manageBtnClick = async (body: LarkUserAction) => {
const card = await func(body); const card = await func(body);
if (!card) return; if (!card) return;
// 更新飞书的卡片 // 更新飞书的卡片
await lark.updateCard(body.open_message_id, card); await service.lark.message.update(body.open_message_id, card);
}; };
/** /**
* Action消息 * Action消息
* @param {LarkUserAction} body * @param {LarkAction.Data} body
* @returns {boolean} * @returns {boolean}
*/ */
export const manageActionMsg = (body: LarkUserAction) => { export const manageActionMsg = (body: LarkAction.Data) => {
// 过滤非Action消息 // 过滤非Action消息
if (!getIsActionMsg(body)) { if (!getIsActionMsg(body)) {
return false; return false;

View File

@ -1,6 +1,5 @@
import { fetchCIMonitor, fetchReportCollector } from "../../service"; import service from "../../services";
import lark from "../../service/lark"; import { LarkEvent } from "../../types";
import { LarkMessageEvent } from "../../types";
import { import {
getChatId, getChatId,
getChatType, getChatType,
@ -12,10 +11,10 @@ import {
/** /**
* P2P或者群聊并且艾特了小煎蛋 * P2P或者群聊并且艾特了小煎蛋
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns {boolean} P2P或者群聊并且艾特了小煎蛋 * @returns {boolean} P2P或者群聊并且艾特了小煎蛋
*/ */
const getIsP2pOrGroupAtBot = (body: LarkMessageEvent) => { const getIsP2pOrGroupAtBot = (body: LarkEvent.Data) => {
const isP2p = getChatType(body) === "p2p"; const isP2p = getChatType(body) === "p2p";
const isAtBot = getMentions(body)?.some?.( const isAtBot = getMentions(body)?.some?.(
(mention) => mention.name === "小煎蛋" (mention) => mention.name === "小煎蛋"
@ -25,10 +24,10 @@ const getIsP2pOrGroupAtBot = (body: LarkMessageEvent) => {
/** /**
* *
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns {boolean} * @returns {boolean}
*/ */
const filterIllegalMsg = (body: LarkMessageEvent) => { const filterIllegalMsg = (body: LarkEvent.Data) => {
// 没有chatId的消息不处理 // 没有chatId的消息不处理
const chatId = getChatId(body); const chatId = getChatId(body);
if (!chatId) return true; if (!chatId) return true;
@ -49,7 +48,7 @@ const filterIllegalMsg = (body: LarkMessageEvent) => {
// 发表情包就直接发回去 // 发表情包就直接发回去
if (msgType === "sticker") { if (msgType === "sticker") {
const content = body?.event?.message?.content; 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({ const content = JSON.stringify({
text: "哇!这是什么东东?我只懂普通文本啦![可爱]", 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 - * @param body -
* @returns * @returns
*/ */
const manageCMDMsg = (body: LarkMessageEvent) => { const manageCMDMsg = (body: LarkEvent.Data) => {
const text = getMsgText(body); const text = getMsgText(body);
const chatId = getChatId(body); const chatId = getChatId(body);
if (text === "/id") { if (text === "/id") {
@ -97,16 +96,16 @@ const manageCMDMsg = (body: LarkMessageEvent) => {
return true; return true;
} }
if (text === "/ci") { if (text === "/ci") {
fetchCIMonitor(chatId); service.attach.ciMonitor(chatId);
return true; return true;
} }
if (text.includes("share") && text.includes("简报")) { if (text.includes("share") && text.includes("简报")) {
fetchReportCollector(body); service.attach.reportCollector(body);
// 这个用时比较久,先发一条提醒用户收到了请求 // 这个用时比较久,先发一条提醒用户收到了请求
const content = JSON.stringify({ const content = JSON.stringify({
text: "正在为您收集简报,请稍等片刻~", text: "正在为您收集简报,请稍等片刻~",
}); });
lark.sendMsg("chat_id", chatId, "text", content); service.lark.message.send("chat_id", chatId, "text", content);
return true; return true;
} }
return false; 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 chatId = getChatId(body);
const content = JSON.stringify({ const content = JSON.stringify({
type: "template", 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 * @param {LarkUserAction} body
* @returns {boolean} * @returns {boolean}
*/ */
export const manageEventMsg = (body: LarkMessageEvent) => { export const manageEventMsg = (body: LarkEvent.Data) => {
// 过滤非Event消息 // 过滤非Event消息
if (!getIsEventMsg(body)) { if (!getIsEventMsg(body)) {
return false; return false;

View File

@ -1,4 +1,4 @@
import { manageActionMsg } from "./activeMsg"; import { manageActionMsg } from "./actionMsg";
import { manageEventMsg } from "./eventMsg"; import { manageEventMsg } from "./eventMsg";
export const manageBotReq = async (req: Request) => { export const manageBotReq = async (req: Request) => {

View File

@ -1,24 +1,9 @@
import db from "../../db"; import db from "../../db";
import lark from "../../service/lark"; import service from "../../services";
import { MsgType, ReceiveIDType } from "../../types"; import { LarkServer, MsgProxy } from "../../types";
interface BaseMsg {
msg_type: MsgType;
content: string;
}
interface GroupMsg extends BaseMsg { const validateMessageReq = (body: MsgProxy.Body) => {
group_id: string;
}
interface NormalMsg extends BaseMsg {
receive_id: string;
receive_id_type: ReceiveIDType;
}
type MessageReqJson = GroupMsg & NormalMsg;
const validateMessageReq = (body: MessageReqJson) => {
if (!body.group_id && !body.receive_id) { if (!body.group_id && !body.receive_id) {
return new Response("group_id or receive_id is required", { status: 400 }); 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) => { 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); const validateRes = validateMessageReq(body);
if (validateRes) return validateRes; 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 { 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) => { return (receive_id: string) => {
sendList.push( sendList.push(
lark service.lark.message
.sendMsg(receive_id_type, receive_id, body.msg_type, finalContent) .send(receive_id_type, receive_id, body.msg_type, finalContent)
.then((res) => { .then((res) => {
sendRes[receive_id_type][receive_id] = 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) { if (body.receive_id && body.receive_id_type) {
sendList.push( sendList.push(
lark service.lark.message
.sendMsg( .send(
body.receive_id_type, body.receive_id_type,
body.receive_id, body.receive_id,
body.msg_type, body.msg_type,

View File

@ -1 +0,0 @@
# 批量发送消息,给已经订阅的用户和群组发送消息

7
routes/microApp/index.ts Normal file
View 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
View File

View 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 "";
}
};

View File

@ -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 IDID类型应与查询参数receive_id_type
* @param {MsgType} msg_type textpostimagefileaudiomediastickerinteractiveshare_chatshare_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 textpostimagefileaudiomediastickerinteractiveshare_chatshare_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
View 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
View 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
View File

@ -0,0 +1,10 @@
import message from "./message";
import user from "./user";
const lark = {
message,
user,
};
export default lark;

View 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
View 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 IDID类型应与查询参数receive_id_type
* @param {MsgType} msg_type textpostimagefileaudiomediastickerinteractiveshare_chatshare_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
View 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
View 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
View 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[];
}
}

View File

@ -1,466 +1,7 @@
/** import type { DB } from "./db";
* import type { LarkAction } from "./larkAction";
*/ import type { LarkEvent } from "./larkEvent";
export interface User { import type { LarkServer } from "./larkServer";
/** import type { MsgProxy } from "./msgProxy";
* id
*/
id: string;
/**
*
* @example zhaoyingbo
*/
userId: string;
/**
* open_id
*/
openId: string;
/**
*
*/
remindList: string[];
}
/** export { DB, LarkAction, LarkEvent, LarkServer, 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} textresult对应的
* ${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 textpostimagefileaudiomediastickerinteractiveshare_chatshare_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;
}

56
types/larkAction.ts Normal file
View 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
View 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 textpostimagefileaudiomediastickerinteractiveshare_chatshare_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
View 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
View 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
View 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} textresult对应的
* ${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;
}

View File

@ -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"; return body?.header?.event_type === "im.message.receive_v1";
}; };
/** /**
* *
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns * @returns
*/ */
export const getMsgType = (body: LarkMessageEvent) => { export const getMsgType = (body: LarkEvent.Data) => {
return body?.event?.message?.message_type; return body?.event?.message?.message_type;
}; };
/** /**
* Id * Id
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns * @returns
*/ */
export const getChatId = (body: LarkMessageEvent) => { export const getChatId = (body: LarkEvent.Data) => {
return body?.event?.message?.chat_id; return body?.event?.message?.chat_id;
}; };
/** /**
* Id * Id
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns * @returns
*/ */
export const getUserId = (body: LarkMessageEvent) => { export const getUserId = (body: LarkEvent.Data) => {
return body?.event?.sender?.sender_id?.user_id; return body?.event?.sender?.sender_id?.user_id;
}; };
/** /**
* Action消息 * Action消息
* @param {LarkUserAction} body * @param {LarkAction.Data} body
*/ */
export const getIsActionMsg = (body: LarkUserAction) => { export const getIsActionMsg = (body: LarkAction.Data) => {
return body?.action; return body?.action;
}; };
/** /**
* Action类型 * Action类型
* @param {LarkUserAction} body * @param {LarkAction.Data} body
* @returns {string} Action类型 * @returns {string} Action类型
*/ */
export const getActionType = (body: LarkUserAction) => { export const getActionType = (body: LarkAction.Data) => {
return body?.action?.tag; return body?.action?.tag;
}; };
/** /**
* *
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns {string} * @returns {string}
*/ */
export const getMsgText = (body: LarkMessageEvent) => { export const getMsgText = (body: LarkEvent.Data) => {
try { try {
const { text }: { text: string } = JSON.parse( const { text }: { text: string } = JSON.parse(
body?.event?.message?.content body?.event?.message?.content
@ -74,18 +74,18 @@ export const getMsgText = (body: LarkMessageEvent) => {
/** /**
* *
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns {string} * @returns {string}
*/ */
export const getChatType = (body: LarkMessageEvent) => { export const getChatType = (body: LarkEvent.Data) => {
return body?.event?.message?.chat_type; return body?.event?.message?.chat_type;
}; };
/** /**
* *
* @param {LarkMessageEvent} body * @param {LarkEvent.Data} body
* @returns {Array} * @returns {Array}
*/ */
export const getMentions = (body: LarkMessageEvent) => { export const getMentions = (body: LarkEvent.Data) => {
return body?.event?.message?.mentions; return body?.event?.message?.mentions;
}; };