wip
This commit is contained in:
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
|
||||
Reference in New Issue
Block a user