287 lines
10 KiB
JavaScript
287 lines
10 KiB
JavaScript
/**
|
||
* 企业微信 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
|