wip
This commit is contained in:
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* API错误
|
||||
*/
|
||||
export declare class WeChatError extends Error {
|
||||
errcode: number;
|
||||
errmsg: string;
|
||||
constructor(errcode: number, errmsg: string);
|
||||
}
|
||||
//# sourceMappingURL=wechat-error.d.ts.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wechat-error.d.ts","sourceRoot":"","sources":["../../src/common/wechat-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IAEvB,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;gBADd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;CAI5B"}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* API错误
|
||||
*/
|
||||
export class WeChatError extends Error {
|
||||
errcode;
|
||||
errmsg;
|
||||
constructor(errcode, errmsg) {
|
||||
super(`企业微信API错误 [${errcode}]: ${errmsg}`);
|
||||
this.errcode = errcode;
|
||||
this.errmsg = errmsg;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=wechat-error.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wechat-error.js","sourceRoot":"","sources":["../../src/common/wechat-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAEvB;IACA;IAFX,YACW,OAAe,EACf,MAAc;QAErB,KAAK,CAAC,cAAc,OAAO,MAAM,MAAM,EAAE,CAAC,CAAC;QAHpC,YAAO,GAAP,OAAO,CAAQ;QACf,WAAM,GAAN,MAAM,CAAQ;IAGzB,CAAC;CACJ"}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=main.d.ts.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
import { handleServer } from './server.js';
|
||||
/**
|
||||
* 主函数:演示如何使用企业微信客户联系API
|
||||
*/
|
||||
async function main() {
|
||||
await handleServer();
|
||||
}
|
||||
main().catch(console.error);
|
||||
//# sourceMappingURL=main.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C;;GAEG;AACH,KAAK,UAAU,IAAI;IACf,MAAM,YAAY,EAAE,CAAC;AACzB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export declare function handleServer(): Promise<void>;
|
||||
//# sourceMappingURL=server.d.ts.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAeA,wBAAsB,YAAY,kBAsHjC"}
|
||||
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
import { serve } from "@hono/node-server";
|
||||
import { Hono } from "hono";
|
||||
import { getSignature, decrypt, encrypt } from '@wecom/crypto';
|
||||
import { parseStringPromise } from 'xml2js';
|
||||
function validateSignature(msgSignature, timestamp, nonce, encrypt) {
|
||||
const { WEIXIN_EVENT_TOKEN, } = process.env;
|
||||
if (!WEIXIN_EVENT_TOKEN)
|
||||
throw new Error('static param error');
|
||||
const devMsgSignature = getSignature(WEIXIN_EVENT_TOKEN, timestamp, nonce, encrypt);
|
||||
return devMsgSignature === msgSignature;
|
||||
}
|
||||
export async function handleServer() {
|
||||
const app = new Hono();
|
||||
app.get('/we-comp/event', ({ req, ...args }) => {
|
||||
try {
|
||||
const { 'msg_signature': msgSignature, timestamp, nonce, echostr } = req.query();
|
||||
const { WEIXIN_EVENT_TOKEN, WEIXIN_EVENT_ENCODING_AES_KEY, } = process.env;
|
||||
if (!WEIXIN_EVENT_TOKEN
|
||||
|| !WEIXIN_EVENT_ENCODING_AES_KEY
|
||||
|| !msgSignature
|
||||
|| !timestamp
|
||||
|| !nonce
|
||||
|| !echostr) {
|
||||
throw new Error('static param error');
|
||||
}
|
||||
if (!validateSignature(msgSignature, timestamp, nonce, echostr)) {
|
||||
throw new Error('validate error');
|
||||
}
|
||||
const { message, id } = decrypt(WEIXIN_EVENT_ENCODING_AES_KEY, echostr);
|
||||
console.log('URL验证成功,解密后的消息:', message);
|
||||
console.log('接收者ID:', id);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return args.text("");
|
||||
});
|
||||
app.post('/we-comp/event', async ({ req, ...args }) => {
|
||||
const { 'msg_signature': msgSignature, timestamp, nonce } = req.query();
|
||||
try {
|
||||
const result = await parseStringPromise(await req.text());
|
||||
const encrypt = result.xml.Encrypt.at(0);
|
||||
const { WEIXIN_EVENT_TOKEN, WEIXIN_EVENT_ENCODING_AES_KEY, } = process.env;
|
||||
if (!WEIXIN_EVENT_TOKEN
|
||||
|| !WEIXIN_EVENT_ENCODING_AES_KEY
|
||||
|| !msgSignature
|
||||
|| !timestamp
|
||||
|| !nonce) {
|
||||
throw new Error('static param error');
|
||||
}
|
||||
// 2. 验证签名
|
||||
if (!validateSignature(msgSignature, timestamp, nonce, encrypt)) {
|
||||
throw new Error('签名验证失败');
|
||||
}
|
||||
const { message, id } = decrypt(WEIXIN_EVENT_ENCODING_AES_KEY, encrypt);
|
||||
console.log('解密后的消息:', message);
|
||||
console.log('接收者ID:', id);
|
||||
// 5. 解析明文XML
|
||||
const decryptedXml = await parseStringPromise(message);
|
||||
const msgData = decryptedXml.xml;
|
||||
const msgType = msgData.MsgType?.[0];
|
||||
const fromUserName = msgData.FromUserName?.[0];
|
||||
const toUserName = msgData.ToUserName?.[0];
|
||||
const createTime = msgData.CreateTime?.[0];
|
||||
console.log('========== 消息详情 ==========');
|
||||
console.log('消息类型:', msgType);
|
||||
console.log('发送者:', fromUserName);
|
||||
console.log('接收者:', toUserName);
|
||||
console.log('创建时间:', createTime);
|
||||
console.log('============================');
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return args.text('');
|
||||
});
|
||||
const server = serve({
|
||||
fetch: app.fetch,
|
||||
port: 3080,
|
||||
});
|
||||
process.on('SIGINT', () => {
|
||||
server.close();
|
||||
process.exit(0);
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=server.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAG5C,SAAS,iBAAiB,CAAC,YAAoB,EAAE,SAAiB,EAAE,KAAa,EAAE,OAAe;IAC9F,MAAM,EACF,kBAAkB,GACrB,GAAG,OAAO,CAAC,GAAG,CAAC;IAChB,IAAI,CAAC,kBAAkB;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/D,MAAM,eAAe,GAAG,YAAY,CAAC,kBAAkB,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACpF,OAAO,eAAe,KAAK,YAAY,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAE9B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;QAE3C,IAAI,CAAC;YACD,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YAEjF,MAAM,EACF,kBAAkB,EAClB,6BAA6B,GAChC,GAAG,OAAO,CAAC,GAAG,CAAC;YAEhB,IACI,CAAC,kBAAkB;mBAChB,CAAC,6BAA6B;mBAC9B,CAAC,YAAY;mBACb,CAAC,SAAS;mBACV,CAAC,KAAK;mBACN,CAAC,OAAO,EACb,CAAC;gBACC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC;YAExE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;QAElD,MAAM,EACF,eAAe,EAAE,YAAY,EAC7B,SAAS,EACT,KAAK,EACR,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;QAEhB,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAEzC,MAAM,EACF,kBAAkB,EAClB,6BAA6B,GAChC,GAAG,OAAO,CAAC,GAAG,CAAC;YAEhB,IACI,CAAC,kBAAkB;mBAChB,CAAC,6BAA6B;mBAC9B,CAAC,YAAY;mBACb,CAAC,SAAS;mBACV,CAAC,KAAK,EACX,CAAC;gBACC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC1C,CAAC;YAED,UAAU;YACV,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC;YACxE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAG1B,aAAa;YACb,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC;YAEjC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;YAE3C,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAEhD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;QAGD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC;QACjB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI,EAAE,IAAI;KACb,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,MAAM,CAAC,KAAK,EAAE,CAAA;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,IAAI,GAAG,EAAE,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACnB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AAEN,CAAC"}
|
||||
Vendored
+343
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* 企业微信客户联系 API 类型定义
|
||||
*/
|
||||
/**
|
||||
* 外部联系人详情
|
||||
*/
|
||||
export interface ExternalContact {
|
||||
/** 外部联系人userid */
|
||||
external_userid: string;
|
||||
/** 名称(微信用户返回昵称,企业微信用户返回对外展示名称) */
|
||||
name: string;
|
||||
/** 头像URL(部分应用不可获取) */
|
||||
avatar?: string;
|
||||
/** 1-微信用户,2-企业微信用户 */
|
||||
type: 1 | 2;
|
||||
/** 0-未知,1-男性,2-女性 */
|
||||
gender: 0 | 1 | 2;
|
||||
/** 微信unionid(需绑定微信开发者ID) */
|
||||
unionid?: string;
|
||||
/** 职位(仅企业微信用户) */
|
||||
position?: string;
|
||||
/** 企业简称(仅企业微信用户) */
|
||||
corp_name?: string;
|
||||
/** 企业主体名称(仅企业微信用户) */
|
||||
corp_full_name?: string;
|
||||
/** 自定义展示信息(仅企业微信用户) */
|
||||
external_profile?: ExternalProfile;
|
||||
}
|
||||
/**
|
||||
* 外部联系人自定义展示信息
|
||||
*/
|
||||
export interface ExternalProfile {
|
||||
/** 自定义展示字段列表 */
|
||||
external_attr: ExternalAttr[];
|
||||
}
|
||||
/**
|
||||
* 自定义展示字段
|
||||
*/
|
||||
export interface ExternalAttr {
|
||||
/** 0-文本,1-网页,2-小程序 */
|
||||
type: number;
|
||||
/** 属性名称 */
|
||||
name: string;
|
||||
/** 文本内容(type=0时) */
|
||||
text?: {
|
||||
value: string;
|
||||
};
|
||||
/** 网页内容(type=1时) */
|
||||
web?: {
|
||||
url: string;
|
||||
title: string;
|
||||
};
|
||||
/** 小程序内容(type=2时) */
|
||||
miniprogram?: {
|
||||
appid: string;
|
||||
pagepath: string;
|
||||
title: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 标签信息
|
||||
*/
|
||||
export interface Tag {
|
||||
/** 标签分组名称 */
|
||||
group_name: string;
|
||||
/** 标签名称 */
|
||||
tag_name: string;
|
||||
/** 企业标签ID(用户自定义标签不返回) */
|
||||
tag_id?: string;
|
||||
/** 1-企业设置,2-用户自定义,3-规则组标签 */
|
||||
type: 1 | 2 | 3;
|
||||
}
|
||||
/**
|
||||
* 视频号信息
|
||||
*/
|
||||
export interface WechatChannels {
|
||||
/** 视频号名称 */
|
||||
nickname: string;
|
||||
/** 0-未知,1-主页,2-直播间,3-留资服务 */
|
||||
source: 0 | 1 | 2 | 3;
|
||||
}
|
||||
/**
|
||||
* 跟进用户信息
|
||||
*/
|
||||
export interface FollowUser {
|
||||
/** 成员userid */
|
||||
userid: string;
|
||||
/** 该成员对客户的备注 */
|
||||
remark: string;
|
||||
/** 该成员对客户的描述 */
|
||||
description: string;
|
||||
/** 添加时间(Unix时间戳) */
|
||||
createtime: number;
|
||||
/** 标签列表 */
|
||||
tags: Tag[];
|
||||
/** 备注的企业名称 */
|
||||
remark_corp_name: string;
|
||||
/** 备注的手机号(部分应用不可获取) */
|
||||
remark_mobiles?: string[];
|
||||
/** 添加来源 */
|
||||
add_way: number;
|
||||
/** 视频号信息(add_way=10时有此字段) */
|
||||
wechat_channels?: WechatChannels;
|
||||
/** 发起添加的userid */
|
||||
oper_userid: string;
|
||||
/** 自定义state参数(联系我/获客链接) */
|
||||
state?: string;
|
||||
}
|
||||
/**
|
||||
* 获取客户详情API响应
|
||||
*/
|
||||
export interface GetExternalContactResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 外部联系人详情 */
|
||||
external_contact: ExternalContact;
|
||||
/** 添加了此外部联系人的企业成员列表 */
|
||||
follow_user: FollowUser[];
|
||||
/** 分页cursor(跟进人>500时返回) */
|
||||
next_cursor?: string;
|
||||
}
|
||||
/**
|
||||
* 获取access_token API响应
|
||||
*/
|
||||
export interface AccessTokenResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 获取到的凭证 */
|
||||
access_token?: string;
|
||||
/** 凭证有效期(秒) */
|
||||
expires_in?: number;
|
||||
}
|
||||
/**
|
||||
* 获取配置了客户联系功能的成员列表API响应
|
||||
*/
|
||||
export interface GetFollowUserListResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 配置了客户联系功能的成员userid列表 */
|
||||
follow_user?: string[];
|
||||
}
|
||||
/**
|
||||
* 获取客户列表API响应
|
||||
*/
|
||||
export interface GetExternalContactListResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 外部联系人的userid列表 */
|
||||
external_userid?: string[];
|
||||
}
|
||||
/**
|
||||
* 批量获取客户详情API响应
|
||||
*/
|
||||
export interface BatchGetExternalContactResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 外部联系人详情列表 */
|
||||
external_contact_list?: ExternalContact[];
|
||||
/** 下一次分页的起始位置 */
|
||||
next_cursor?: string;
|
||||
}
|
||||
/**
|
||||
* 结束语文本内容
|
||||
*/
|
||||
export interface ConclusionText {
|
||||
/** 文本内容 */
|
||||
content: string;
|
||||
}
|
||||
/**
|
||||
* 结束语
|
||||
*/
|
||||
export interface Conclusion {
|
||||
/** 文本结束语 */
|
||||
text?: ConclusionText;
|
||||
}
|
||||
/**
|
||||
* 添加「联系我」方式请求参数
|
||||
*/
|
||||
export interface AddContactWayRequest {
|
||||
/** 联系方式类型,1-单人,2-多人 */
|
||||
type: 1 | 2;
|
||||
/** 场景,1-在小程序中联系,2-通过二维码联系 */
|
||||
scene: 1 | 2;
|
||||
/** 在小程序中联系时使用的控件样式 */
|
||||
style?: number;
|
||||
/** 联系方式的备注信息,用于助记,不超过30个字符 */
|
||||
remark?: string;
|
||||
/** 外部客户添加时是否无需验证,默认为true */
|
||||
skip_verify?: boolean;
|
||||
/** 企业自定义的state参数,用于区分不同的添加渠道 */
|
||||
state?: string;
|
||||
/** 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个 */
|
||||
user?: string[];
|
||||
/** 使用该联系方式的部门id列表,只在type为2时有效 */
|
||||
party?: number[];
|
||||
/** 是否临时会话模式 */
|
||||
is_temp?: boolean;
|
||||
/** 临时会话二维码有效期,以秒为单位 */
|
||||
expires_in?: number;
|
||||
/** 临时会话有效期,以秒为单位 */
|
||||
chat_expires_in?: number;
|
||||
/** 可进行临时会话的客户unionid */
|
||||
unionid?: string;
|
||||
/** 是否开启同一外部企业客户只能添加同一个员工 */
|
||||
is_exclusive?: boolean;
|
||||
/** 是否标记客户添加来源 */
|
||||
mark_source?: boolean;
|
||||
/** 结束语 */
|
||||
conclusions?: Conclusion;
|
||||
}
|
||||
/**
|
||||
* 添加「联系我」方式响应
|
||||
*/
|
||||
export interface AddContactWayResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 联系方式的配置id */
|
||||
config_id?: string;
|
||||
/** 联系方式二维码的URL,开发者需要自行将此二维码转换为图片 */
|
||||
qr_code?: string;
|
||||
}
|
||||
/**
|
||||
* 获取「联系我」方式请求参数
|
||||
*/
|
||||
export interface GetContactWayRequest {
|
||||
/** 联系方式的配置id */
|
||||
config_id: string;
|
||||
}
|
||||
/**
|
||||
* 获取「联系我」方式响应
|
||||
*/
|
||||
export interface GetContactWayResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
/** 联系方式配置信息 */
|
||||
contact_way?: ContactWayInfo;
|
||||
}
|
||||
/**
|
||||
* 联系方式配置信息
|
||||
*/
|
||||
export interface ContactWayInfo {
|
||||
/** 联系方式配置id */
|
||||
config_id: string;
|
||||
/** 联系方式类型 */
|
||||
type: 1 | 2;
|
||||
/** 场景 */
|
||||
scene: 1 | 2;
|
||||
/** 在小程序中联系时使用的控件样式 */
|
||||
style?: number;
|
||||
/** 联系方式的备注信息 */
|
||||
remark?: string;
|
||||
/** 是否无需验证 */
|
||||
skip_verify: boolean;
|
||||
/** state参数 */
|
||||
state?: string;
|
||||
/** 使用该联系方式的用户userID列表 */
|
||||
user?: string[];
|
||||
/** 使用该联系方式的部门id列表 */
|
||||
party?: number[];
|
||||
/** 是否临时会话模式 */
|
||||
is_temp: boolean;
|
||||
/** 临时会话二维码有效期 */
|
||||
expires_in?: number;
|
||||
/** 临时会话有效期 */
|
||||
chat_expires_in?: number;
|
||||
/** 临时会话指定的客户unionid */
|
||||
unionid?: string;
|
||||
/** 是否开启同一外部企业客户只能添加同一个员工 */
|
||||
is_exclusive: boolean;
|
||||
/** 结束语 */
|
||||
conclusions?: Conclusion;
|
||||
/** 二维码的URL */
|
||||
qr_code?: string;
|
||||
}
|
||||
/**
|
||||
* 更新「联系我」方式请求参数
|
||||
*/
|
||||
export interface UpdateContactWayRequest {
|
||||
/** 联系方式的配置id */
|
||||
config_id: string;
|
||||
/** 在小程序中联系时使用的控件样式 */
|
||||
style?: number;
|
||||
/** 联系方式的备注信息 */
|
||||
remark?: string;
|
||||
/** 是否无需验证 */
|
||||
skip_verify?: boolean;
|
||||
/** 使用该联系方式的用户userID列表 */
|
||||
user?: string[];
|
||||
/** 使用该联系方式的部门id列表 */
|
||||
party?: number[];
|
||||
/** 是否临时会话模式 */
|
||||
is_temp?: boolean;
|
||||
/** 临时会话二维码有效期 */
|
||||
expires_in?: number;
|
||||
/** 临时会话有效期 */
|
||||
chat_expires_in?: number;
|
||||
/** 临时会话指定的客户unionid */
|
||||
unionid?: string;
|
||||
/** 是否开启同一外部企业客户只能添加同一个员工 */
|
||||
is_exclusive?: boolean;
|
||||
/** 结束语 */
|
||||
conclusions?: Conclusion;
|
||||
}
|
||||
/**
|
||||
* 更新「联系我」方式响应
|
||||
*/
|
||||
export interface UpdateContactWayResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
}
|
||||
/**
|
||||
* 删除「联系我」方式请求参数
|
||||
*/
|
||||
export interface DeleteContactWayRequest {
|
||||
/** 联系方式的配置id */
|
||||
config_id: string;
|
||||
}
|
||||
/**
|
||||
* 删除「联系我」方式响应
|
||||
*/
|
||||
export interface DeleteContactWayResponse {
|
||||
/** 返回码 */
|
||||
errcode: number;
|
||||
/** 返回信息 */
|
||||
errmsg: string;
|
||||
}
|
||||
//# sourceMappingURL=wechat.d.ts.map
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 企业微信客户联系 API 类型定义
|
||||
*/
|
||||
export {};
|
||||
//# sourceMappingURL=wechat.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wechat.js","sourceRoot":"","sources":["../../src/types/wechat.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
||||
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
import type { GetExternalContactResponse, GetExternalContactListResponse, GetFollowUserListResponse, BatchGetExternalContactResponse, ExternalContact, AddContactWayRequest, AddContactWayResponse, GetContactWayRequest, GetContactWayResponse, UpdateContactWayRequest, UpdateContactWayResponse, DeleteContactWayRequest, DeleteContactWayResponse } from './types/wechat.js';
|
||||
/**
|
||||
* 企业微信API客户端配置
|
||||
*/
|
||||
export interface WeChatClientConfig {
|
||||
/** 企业ID */
|
||||
corpId: string;
|
||||
/** 应用的secret */
|
||||
corpSecret: string;
|
||||
/** API基础URL */
|
||||
baseUrl?: string;
|
||||
}
|
||||
/**
|
||||
* 企业微信API客户端
|
||||
*/
|
||||
export declare class WeChatClient {
|
||||
private config;
|
||||
private accessToken;
|
||||
private tokenExpireTime;
|
||||
constructor(config: WeChatClientConfig);
|
||||
/**
|
||||
* 获取access_token
|
||||
* @returns access_token
|
||||
*/
|
||||
getAccessToken(): Promise<string>;
|
||||
/**
|
||||
* 获取客户详情
|
||||
* @param externalUserId 外部联系人的userid
|
||||
* @param cursor 上次请求返回的next_cursor,用于分页
|
||||
* @returns 客户详情
|
||||
*/
|
||||
getExternalContact(externalUserId: string, cursor?: string): Promise<GetExternalContactResponse>;
|
||||
/**
|
||||
* 获取客户详情(支持分页,自动获取所有跟进人)
|
||||
* @param externalUserId 外部联系人的userid
|
||||
* @returns 客户详情(包含所有跟进人)
|
||||
*/
|
||||
getExternalContactFull(externalUserId: string): Promise<GetExternalContactResponse>;
|
||||
/**
|
||||
* 获取配置了客户联系功能的成员列表
|
||||
* @returns 配置了客户联系功能的成员userid列表
|
||||
*/
|
||||
getFollowUserList(): Promise<GetFollowUserListResponse>;
|
||||
/**
|
||||
* 获取客户列表
|
||||
* @param userId 企业成员的userid
|
||||
* @returns 外部联系人的userid列表
|
||||
*/
|
||||
getExternalContactList(userId: string): Promise<GetExternalContactListResponse>;
|
||||
/**
|
||||
* 批量获取客户详情
|
||||
* @param userId 企业成员的userid
|
||||
* @param cursor 上次请求返回的next_cursor,用于分页
|
||||
* @param limit 返回的最大记录数,整型,最大值1000,默认值为100
|
||||
* @returns 客户详情列表
|
||||
*/
|
||||
batchGetExternalContact(userId: string, cursor?: string, limit?: number): Promise<BatchGetExternalContactResponse>;
|
||||
/**
|
||||
* 批量获取客户详情(自动分页,获取所有客户)
|
||||
* @param userId 企业成员的userid
|
||||
* @returns 所有客户详情列表
|
||||
*/
|
||||
batchGetExternalContactFull(userId: string): Promise<ExternalContact[]>;
|
||||
/**
|
||||
* 添加「联系我」方式
|
||||
* @param params 联系方式配置参数
|
||||
* @returns 联系方式配置信息(包含config_id和qr_code)
|
||||
*/
|
||||
addContactWay(params: AddContactWayRequest): Promise<AddContactWayResponse>;
|
||||
/**
|
||||
* 获取「联系我」方式
|
||||
* @param params 查询参数(包含config_id)
|
||||
* @returns 联系方式配置信息
|
||||
*/
|
||||
getContactWay(params: GetContactWayRequest): Promise<GetContactWayResponse>;
|
||||
/**
|
||||
* 更新「联系我」方式
|
||||
* @param params 更新参数(包含config_id和要更新的字段)
|
||||
* @returns 更新结果
|
||||
*/
|
||||
updateContactWay(params: UpdateContactWayRequest): Promise<UpdateContactWayResponse>;
|
||||
/**
|
||||
* 删除「联系我」方式
|
||||
* @param params 删除参数(包含config_id)
|
||||
* @returns 删除结果
|
||||
*/
|
||||
deleteContactWay(params: DeleteContactWayRequest): Promise<DeleteContactWayResponse>;
|
||||
/**
|
||||
* 重置access_token(强制重新获取)
|
||||
*/
|
||||
resetAccessToken(): void;
|
||||
}
|
||||
//# sourceMappingURL=wechat-client.d.ts.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wechat-client.d.ts","sourceRoot":"","sources":["../src/wechat-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,0BAA0B,EAC1B,8BAA8B,EAC9B,yBAAyB,EACzB,+BAA+B,EAC/B,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,eAAe,CAAqB;gBAEhC,MAAM,EAAE,kBAAkB;IAOtC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAwBvC;;;;;OAKG;IACG,kBAAkB,CACtB,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,0BAA0B,CAAC;IAwBtC;;;;OAIG;IACG,sBAAsB,CAC1B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,0BAA0B,CAAC;IAyBtC;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAoB7D;;;;OAIG;IACG,sBAAsB,CAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,8BAA8B,CAAC;IAqB1C;;;;;;OAMG;IACG,uBAAuB,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,GAAE,MAAY,GAClB,OAAO,CAAC,+BAA+B,CAAC;IAyB3C;;;;OAIG;IACG,2BAA2B,CAC/B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,EAAE,CAAC;IAe7B;;;;OAIG;IACG,aAAa,CACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IA2BjC;;;;OAIG;IACG,aAAa,CACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IA2BjC;;;;OAIG;IACG,gBAAgB,CACpB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,wBAAwB,CAAC;IA2BpC;;;;OAIG;IACG,gBAAgB,CACpB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,wBAAwB,CAAC;IA2BpC;;OAEG;IACH,gBAAgB,IAAI,IAAI;CAIzB"}
|
||||
Vendored
+287
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* 企业微信 API 客户端
|
||||
*/
|
||||
import { WeChatError } from './common/wechat-error.js';
|
||||
/**
|
||||
* 企业微信API客户端
|
||||
*/
|
||||
export class WeChatClient {
|
||||
config;
|
||||
accessToken;
|
||||
tokenExpireTime;
|
||||
constructor(config) {
|
||||
this.config = {
|
||||
baseUrl: process.env.WEIXIN_CORP_URL ?? 'https://qyapi.weixin.qq.com',
|
||||
...config,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 获取access_token
|
||||
* @returns access_token
|
||||
*/
|
||||
async getAccessToken() {
|
||||
// 检查token是否有效
|
||||
if (this.accessToken && this.tokenExpireTime && Date.now() < this.tokenExpireTime) {
|
||||
return this.accessToken;
|
||||
}
|
||||
const url = new URL('/cgi-bin/gettoken', this.config.baseUrl);
|
||||
url.searchParams.set('corpid', this.config.corpId);
|
||||
url.searchParams.set('corpsecret', this.config.corpSecret);
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
if (data.errcode !== 0 || !data.access_token) {
|
||||
throw new Error(`获取access_token失败: ${data.errmsg}`);
|
||||
}
|
||||
this.accessToken = data.access_token;
|
||||
// 提前5分钟过期,避免临界点问题
|
||||
this.tokenExpireTime = Date.now() + (data.expires_in || 7200) * 1000 - 5 * 60 * 1000;
|
||||
return this.accessToken;
|
||||
}
|
||||
/**
|
||||
* 获取客户详情
|
||||
* @param externalUserId 外部联系人的userid
|
||||
* @param cursor 上次请求返回的next_cursor,用于分页
|
||||
* @returns 客户详情
|
||||
*/
|
||||
async getExternalContact(externalUserId, cursor) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/get', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
url.searchParams.set('external_userid', externalUserId);
|
||||
if (cursor) {
|
||||
url.searchParams.set('cursor', cursor);
|
||||
}
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 获取客户详情(支持分页,自动获取所有跟进人)
|
||||
* @param externalUserId 外部联系人的userid
|
||||
* @returns 客户详情(包含所有跟进人)
|
||||
*/
|
||||
async getExternalContactFull(externalUserId) {
|
||||
let result = null;
|
||||
let cursor;
|
||||
do {
|
||||
const data = await this.getExternalContact(externalUserId, cursor);
|
||||
if (!result) {
|
||||
// 第一次请求,直接使用返回的数据
|
||||
result = data;
|
||||
}
|
||||
else {
|
||||
// 后续请求,合并follow_user列表
|
||||
result.follow_user.push(...data.follow_user);
|
||||
// 更新next_cursor
|
||||
if (data.next_cursor !== undefined) {
|
||||
result.next_cursor = data.next_cursor;
|
||||
}
|
||||
}
|
||||
cursor = data.next_cursor;
|
||||
} while (cursor);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 获取配置了客户联系功能的成员列表
|
||||
* @returns 配置了客户联系功能的成员userid列表
|
||||
*/
|
||||
async getFollowUserList() {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/get_follow_user_list', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 获取客户列表
|
||||
* @param userId 企业成员的userid
|
||||
* @returns 外部联系人的userid列表
|
||||
*/
|
||||
async getExternalContactList(userId) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/list', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
url.searchParams.set('userid', userId);
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 批量获取客户详情
|
||||
* @param userId 企业成员的userid
|
||||
* @param cursor 上次请求返回的next_cursor,用于分页
|
||||
* @param limit 返回的最大记录数,整型,最大值1000,默认值为100
|
||||
* @returns 客户详情列表
|
||||
*/
|
||||
async batchGetExternalContact(userId, cursor, limit = 100) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/batch/get_by_user', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
url.searchParams.set('userid', userId);
|
||||
if (cursor) {
|
||||
url.searchParams.set('cursor', cursor);
|
||||
}
|
||||
url.searchParams.set('limit', limit.toString());
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 批量获取客户详情(自动分页,获取所有客户)
|
||||
* @param userId 企业成员的userid
|
||||
* @returns 所有客户详情列表
|
||||
*/
|
||||
async batchGetExternalContactFull(userId) {
|
||||
const allContacts = [];
|
||||
let cursor;
|
||||
do {
|
||||
const data = await this.batchGetExternalContact(userId, cursor);
|
||||
if (data.external_contact_list) {
|
||||
allContacts.push(...data.external_contact_list);
|
||||
}
|
||||
cursor = data.next_cursor;
|
||||
} while (cursor);
|
||||
return allContacts;
|
||||
}
|
||||
/**
|
||||
* 添加「联系我」方式
|
||||
* @param params 联系方式配置参数
|
||||
* @returns 联系方式配置信息(包含config_id和qr_code)
|
||||
*/
|
||||
async addContactWay(params) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/add_contact_way', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 获取「联系我」方式
|
||||
* @param params 查询参数(包含config_id)
|
||||
* @returns 联系方式配置信息
|
||||
*/
|
||||
async getContactWay(params) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/get_contact_way', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 更新「联系我」方式
|
||||
* @param params 更新参数(包含config_id和要更新的字段)
|
||||
* @returns 更新结果
|
||||
*/
|
||||
async updateContactWay(params) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/update_contact_way', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 删除「联系我」方式
|
||||
* @param params 删除参数(包含config_id)
|
||||
* @returns 删除结果
|
||||
*/
|
||||
async deleteContactWay(params) {
|
||||
const token = await this.getAccessToken();
|
||||
const url = new URL('/cgi-bin/externalcontact/del_contact_way', this.config.baseUrl);
|
||||
url.searchParams.set('access_token', token);
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const data = await response.json();
|
||||
// 检查API错误
|
||||
if (data.errcode !== 0) {
|
||||
const error = new WeChatError(data.errcode, data.errmsg);
|
||||
error.errcode = data.errcode;
|
||||
error.errmsg = data.errmsg;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 重置access_token(强制重新获取)
|
||||
*/
|
||||
resetAccessToken() {
|
||||
this.accessToken = undefined;
|
||||
this.tokenExpireTime = undefined;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=wechat-client.js.map
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export declare function handleWecomp(): Promise<void>;
|
||||
//# sourceMappingURL=wecomp.d.ts.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wecomp.d.ts","sourceRoot":"","sources":["../src/wecomp.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,kBA2DjC"}
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
import { WeChatClient } from "./wechat-client.js";
|
||||
export async function handleWecomp() {
|
||||
// 检查环境变量
|
||||
if (process.env.WEIXIN_CORP_ID == null ||
|
||||
process.env.WEIXIN_CORP_SECRET == null) {
|
||||
throw new Error('环境变量错误:请设置 WEIXIN_CORP_ID 和 WEIXIN_CORP_SECRET');
|
||||
}
|
||||
// 创建企业微信客户端
|
||||
const client = new WeChatClient({
|
||||
corpId: process.env.WEIXIN_CORP_ID,
|
||||
corpSecret: process.env.WEIXIN_CORP_SECRET,
|
||||
baseUrl: process.env.WEIXIN_CORP_URL || 'https://qyapi.weixin.qq.com',
|
||||
});
|
||||
try {
|
||||
// 示例:获取配置了客户联系功能的成员列表
|
||||
console.log('\n=== 获取配置了客户联系功能的成员列表 ===');
|
||||
const followUserList = await client.getFollowUserList();
|
||||
console.log('\n--- 成员列表 ---');
|
||||
console.log('成员数量:', followUserList.follow_user?.length || 0);
|
||||
if (!followUserList.follow_user || followUserList.follow_user.length === 0) {
|
||||
console.log('没有配置了客户联系功能的成员');
|
||||
return;
|
||||
}
|
||||
console.log('成员ID列表:');
|
||||
followUserList.follow_user.forEach((id, index) => {
|
||||
console.log(` ${index + 1}. ${id}`);
|
||||
});
|
||||
let userId = 'YeDeLiang';
|
||||
if (!userId) {
|
||||
console.log('错误:无法获取有效的成员userid');
|
||||
return;
|
||||
}
|
||||
const res = await client.getContactWay({
|
||||
config_id: 'd5990127d833c10d9db8ba7f192e7b19'
|
||||
});
|
||||
console.log(res);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.error('发生错误:', error.message);
|
||||
const err = error;
|
||||
if (err.errcode !== undefined) {
|
||||
console.error('错误码:', err.errcode);
|
||||
}
|
||||
if (err.errmsg !== undefined) {
|
||||
console.error('错误信息:', err.errmsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=wecomp.js.map
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wecomp.js","sourceRoot":"","sources":["../src/wecomp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,YAAY;IAC9B,SAAS;IACT,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI;QAClC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,EACxC,CAAC;QACC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACtE,CAAC;IAED,YAAY;IACZ,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;QAC5B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;QAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC1C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,6BAA6B;KACxE,CAAC,CAAC;IAEH,IAAI,CAAC;QACD,sBAAsB;QACtB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAExD,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;QAE9D,IAAI,CAAC,cAAc,CAAC,WAAW,IAAI,cAAc,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC9B,OAAO;QACX,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvB,cAAc,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,WAAW,CAAC;QAEzB,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAClC,OAAO;QACX,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC;YACnC,SAAS,EAAE,kCAAkC;SAChD,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,KAAyD,CAAC;YACtE,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,KAAK,CAAC;QAChB,CAAC;IACL,CAAC;AACL,CAAC"}
|
||||
Reference in New Issue
Block a user