wechat-ts 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/index.cjs +328 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +239 -0
- package/dist/index.d.ts +239 -0
- package/dist/index.global.js +321 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +283 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
- package/src/constants/index.ts +2 -0
- package/src/constants/wechat.ts +4 -0
- package/src/index.ts +5 -0
- package/src/jssdk/getJssdkConfig.ts +122 -0
- package/src/jssdk/index.ts +1 -0
- package/src/oauth2/authorize.ts +95 -0
- package/src/oauth2/index.ts +1 -0
- package/src/server/cgi-bin/getAccessToken.ts +28 -0
- package/src/server/cgi-bin/getStableAccessToken.ts +24 -0
- package/src/server/cgi-bin/index.ts +3 -0
- package/src/server/cgi-bin/message/index.ts +1 -0
- package/src/server/cgi-bin/message/template/index.ts +1 -0
- package/src/server/cgi-bin/message/template/sendTemplateMessage.ts +41 -0
- package/src/server/cgi-bin/ticket/getTicket.ts +28 -0
- package/src/server/cgi-bin/ticket/index.ts +1 -0
- package/src/server/index.ts +2 -0
- package/src/server/types/response.ts +4 -0
- package/src/server/utils/request.ts +25 -0
- package/src/server/utils/token.ts +21 -0
- package/src/sns/getUserInfo.ts +49 -0
- package/src/sns/index.ts +3 -0
- package/src/sns/snsAccessToken.ts +47 -0
- package/src/sns/snsUserInfo.ts +49 -0
- package/src/types/wechat-api.d.ts +164 -0
- package/src/utils/config.ts +35 -0
- package/src/utils/promise.ts +14 -0
- package/src/utils/request.ts +20 -0
- package/src/utils/string.ts +33 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +11 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './template'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './sendTemplateMessage'
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { WechatResponse } from '../../../types/response'
|
|
2
|
+
import { requestPost } from '../../../utils/request'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 发送模板消息参数
|
|
6
|
+
* @interface sendTemplateMessageDTO
|
|
7
|
+
*/
|
|
8
|
+
export interface SendTemplateMessageDTO {
|
|
9
|
+
/** 接收者openid */
|
|
10
|
+
touser: string
|
|
11
|
+
/** 模板ID */
|
|
12
|
+
template_id: string
|
|
13
|
+
/** 跳转URL */
|
|
14
|
+
url?: string
|
|
15
|
+
/** 小程序信息 */
|
|
16
|
+
miniprogram?: {
|
|
17
|
+
/** 小程序appid */
|
|
18
|
+
appid?: string
|
|
19
|
+
/** 小程序页面路径 */
|
|
20
|
+
pagepath?: string
|
|
21
|
+
}
|
|
22
|
+
/** 模板数据 */
|
|
23
|
+
data: Record<string, { value: string; color?: string }>
|
|
24
|
+
/** 防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效,超过10分钟不保证效果。若无防重入需求,可不填 */
|
|
25
|
+
client_msg_id?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SendTemplateMessageVO extends WechatResponse {
|
|
29
|
+
msgid: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 发送模板消息
|
|
34
|
+
* @param params
|
|
35
|
+
* @returns
|
|
36
|
+
*
|
|
37
|
+
* @see https://developers.weixin.qq.com/doc/service/api/notify/template/api_sendtemplatemessage.html
|
|
38
|
+
*/
|
|
39
|
+
export function sendTemplateMessage(params: SendTemplateMessageDTO) {
|
|
40
|
+
return requestPost<SendTemplateMessageVO>('/cgi-bin/message/template/send', params)
|
|
41
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { WechatResponse } from "../../types/response"
|
|
2
|
+
import { requestGet } from "../../utils/request"
|
|
3
|
+
|
|
4
|
+
export interface GetTicketDTO {
|
|
5
|
+
/** ticket 类型,jsapi 为 js-sdk 凭证;wx_card 为微信卡券凭证 */
|
|
6
|
+
type: 'jsapi' | 'wx_card'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GetTicketVO extends WechatResponse {
|
|
10
|
+
/** 临时票据 */
|
|
11
|
+
ticket: string
|
|
12
|
+
/**
|
|
13
|
+
* 有效期(秒)
|
|
14
|
+
* @default 7200
|
|
15
|
+
*/
|
|
16
|
+
expires_in: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获取sdk临时票据
|
|
21
|
+
* @param data GetTicketDTO
|
|
22
|
+
* @returns GetTicketVO
|
|
23
|
+
*
|
|
24
|
+
* @see https://developers.weixin.qq.com/doc/service/api/webdev/jssdk/api_getticket.html
|
|
25
|
+
*/
|
|
26
|
+
export function getTicket(data: GetTicketDTO) {
|
|
27
|
+
return requestGet<GetTicketVO>('/cgi-bin/ticket/getticket', data)
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getTicket'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { requestGetBase, requestPostBase } from '../../utils/request'
|
|
2
|
+
import { getToken } from './token'
|
|
3
|
+
|
|
4
|
+
async function urlAddToken(url: string) {
|
|
5
|
+
if (url.includes('?')) {
|
|
6
|
+
url += '&'
|
|
7
|
+
}
|
|
8
|
+
url += `access_token=${await getToken()}`
|
|
9
|
+
return url
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function requestGet<T>(
|
|
13
|
+
url: string,
|
|
14
|
+
params: Record<string, any>,
|
|
15
|
+
options?: RequestInit
|
|
16
|
+
) {
|
|
17
|
+
return requestGetBase<T>(await urlAddToken(url), params, options)
|
|
18
|
+
}
|
|
19
|
+
export async function requestPost<T>(
|
|
20
|
+
url: string,
|
|
21
|
+
data: Record<string, any>,
|
|
22
|
+
options?: RequestInit
|
|
23
|
+
) {
|
|
24
|
+
return requestPostBase<T>(await urlAddToken(url), data, options)
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getStableAccessToken } from '../cgi-bin/getStableAccessToken'
|
|
2
|
+
import { getConfig } from '../../utils/config'
|
|
3
|
+
|
|
4
|
+
let token = '',
|
|
5
|
+
expires = 0
|
|
6
|
+
|
|
7
|
+
export async function getToken() {
|
|
8
|
+
const { appId, appSecret } = getConfig()
|
|
9
|
+
const now = Date.now()
|
|
10
|
+
if (expires < now) {
|
|
11
|
+
const resToken = await getStableAccessToken({
|
|
12
|
+
appid: appId,
|
|
13
|
+
secret: appSecret,
|
|
14
|
+
grant_type: 'client_credential'
|
|
15
|
+
})
|
|
16
|
+
token = resToken.access_token
|
|
17
|
+
// 设置过期时间,留出5%的缓冲时间
|
|
18
|
+
expires = now + resToken.expires_in * 950
|
|
19
|
+
}
|
|
20
|
+
return token
|
|
21
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { snsAccessToken } from './snsAccessToken'
|
|
2
|
+
import { snsUserInfo } from './snsUserInfo'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取微信用户信息
|
|
6
|
+
* @param {WeixinGetUserInfoDTO} params - 获取微信用户信息参数
|
|
7
|
+
* @returns {Promise<SnsUserInfo>} 用户信息
|
|
8
|
+
*/
|
|
9
|
+
export async function getSnsUserInfo(code: string) {
|
|
10
|
+
// 通过code换取网页授权access_token
|
|
11
|
+
// const { code } = params
|
|
12
|
+
// const accessToken: WeixinAccessToken = await OpenMpSnsAccessTokenApi.getSnsAccessToken(
|
|
13
|
+
// code,
|
|
14
|
+
// appid
|
|
15
|
+
// )
|
|
16
|
+
// console.log('accessToken:', accessToken)
|
|
17
|
+
|
|
18
|
+
// // 拉取用户信息(需scope为 snsapi_userinfo)
|
|
19
|
+
// const { access_token, openid } = accessToken
|
|
20
|
+
// const userInfo: TableUser = await OpenMpSnsAccessTokenApi.getUserInfo(
|
|
21
|
+
// access_token,
|
|
22
|
+
// openid,
|
|
23
|
+
// Lang.ZH_CN
|
|
24
|
+
// )
|
|
25
|
+
|
|
26
|
+
// if (userInfo.openid) {
|
|
27
|
+
// // 3. 使用user.ts中的函数保存用户信息
|
|
28
|
+
// saveUser(userInfo)
|
|
29
|
+
// return userInfo
|
|
30
|
+
// } else {
|
|
31
|
+
// throw new Error('获取用户信息失败')
|
|
32
|
+
// }
|
|
33
|
+
// 1. 获取access_token和openid
|
|
34
|
+
const tokenData = await snsAccessToken(code)
|
|
35
|
+
const { access_token, openid } = tokenData
|
|
36
|
+
|
|
37
|
+
if (!openid) {
|
|
38
|
+
throw new Error('获取openid失败')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 2. 获取用户信息
|
|
42
|
+
const userInfo = await snsUserInfo({ access_token, openid })
|
|
43
|
+
if (userInfo.openid) {
|
|
44
|
+
// 3. 使用user.ts中的函数保存用户信息
|
|
45
|
+
return userInfo
|
|
46
|
+
} else {
|
|
47
|
+
throw new Error('获取用户信息失败')
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/sns/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getConfig } from '../utils/config'
|
|
2
|
+
import { requestGetBase } from '../utils/request'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取微信用户信息参数
|
|
6
|
+
* @interface WeixinGetUserInfoDTO
|
|
7
|
+
*/
|
|
8
|
+
export interface WeixinGetUserInfoDTO {
|
|
9
|
+
/** 授权码 */
|
|
10
|
+
code: string
|
|
11
|
+
/** 重定向后会带上 state 参数,开发者可以填写任意参数值,最多 128 字节 */
|
|
12
|
+
state?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 微信访问令牌接口
|
|
17
|
+
*/
|
|
18
|
+
export interface SnsAccessTokenVO {
|
|
19
|
+
/** 访问令牌 */
|
|
20
|
+
access_token: string
|
|
21
|
+
/** 过期时间(秒) */
|
|
22
|
+
expires_in: number
|
|
23
|
+
/** 刷新令牌 */
|
|
24
|
+
refresh_token: string
|
|
25
|
+
/** 用户openid */
|
|
26
|
+
openid: string
|
|
27
|
+
/** 授权作用域 */
|
|
28
|
+
scope: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 获取微信访问令牌
|
|
33
|
+
* @param code 授权码
|
|
34
|
+
* @returns 微信访问令牌信息
|
|
35
|
+
*
|
|
36
|
+
* @see https://developers.weixin.qq.com/doc/service/api/webdev/access/api_snsaccesstoken.html
|
|
37
|
+
*/
|
|
38
|
+
export async function snsAccessToken(code: string) {
|
|
39
|
+
const { appId, appSecret } = getConfig()
|
|
40
|
+
// 通过code换取网页授权access_token
|
|
41
|
+
return requestGetBase<SnsAccessTokenVO>('/sns/oauth2/access_token', {
|
|
42
|
+
appid: appId,
|
|
43
|
+
secret: appSecret,
|
|
44
|
+
code,
|
|
45
|
+
grant_type: 'authorization_code'
|
|
46
|
+
})
|
|
47
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { requestGetBase } from '../utils/request'
|
|
2
|
+
import { SnsAccessTokenVO } from './snsAccessToken'
|
|
3
|
+
|
|
4
|
+
export interface SnsUserInfoDTO extends Pick<SnsAccessTokenVO, 'access_token' | 'openid'> {
|
|
5
|
+
/**
|
|
6
|
+
* 语言
|
|
7
|
+
* @default zh_CN
|
|
8
|
+
*/
|
|
9
|
+
lang?: 'zh_CN' | 'zh_TW' | 'en'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SnsUserInfoVO {
|
|
13
|
+
/** 用户的微信openid */
|
|
14
|
+
openid?: string
|
|
15
|
+
/** 用户昵称 */
|
|
16
|
+
nickname?: string
|
|
17
|
+
/** 性别 0-未知 1-男 2-女 */
|
|
18
|
+
sex?: 0 | 1 | 2
|
|
19
|
+
/** 用户语言 */
|
|
20
|
+
language?: string
|
|
21
|
+
/** 用户所在城市 */
|
|
22
|
+
city?: string
|
|
23
|
+
/** 用户所在省份 */
|
|
24
|
+
province?: string
|
|
25
|
+
/** 用户所在国家 */
|
|
26
|
+
country?: string
|
|
27
|
+
/** 用户头像URL */
|
|
28
|
+
headimgurl?: string
|
|
29
|
+
/** 用户特权信息 */
|
|
30
|
+
privilege?: any[]
|
|
31
|
+
/** 用户在开放平台的唯一标识符 */
|
|
32
|
+
unionid?: string
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 获取授权用户信息
|
|
36
|
+
* @param data SnsUserInfoDTO
|
|
37
|
+
* @returns SnsUserInfoVO
|
|
38
|
+
*
|
|
39
|
+
* @see https://developers.weixin.qq.com/doc/service/api/webdev/access/api_snsuserinfo.html
|
|
40
|
+
*/
|
|
41
|
+
export async function snsUserInfo(data: SnsUserInfoDTO) {
|
|
42
|
+
const { access_token, openid, lang = 'zh_CN' } = data
|
|
43
|
+
// 2. 获取用户信息
|
|
44
|
+
return requestGetBase<SnsUserInfoVO>(`/sns/userinfo`, {
|
|
45
|
+
access_token: access_token,
|
|
46
|
+
openid: openid,
|
|
47
|
+
lang: lang
|
|
48
|
+
})
|
|
49
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
declare module 'wechat-api' {
|
|
2
|
+
// export interface WeixinGetJssdkConfigDTO {
|
|
3
|
+
// /** 当前页面URL */
|
|
4
|
+
// url: string
|
|
5
|
+
// /** 需要使用的JS API列表 */
|
|
6
|
+
// jsApiList?: string[]
|
|
7
|
+
// /** 是否开启调试模式 */
|
|
8
|
+
// debug?: boolean
|
|
9
|
+
// /** 微信硬件开发用 */
|
|
10
|
+
// beta?: boolean
|
|
11
|
+
// }
|
|
12
|
+
|
|
13
|
+
// /**
|
|
14
|
+
// * 微信JS-SDK配置接口
|
|
15
|
+
// */
|
|
16
|
+
// export interface WeixinGetJssdkConfigVO {
|
|
17
|
+
// /** 开启调试模式,调用的所有API的返回值会在客户端alert出来,若要查看传入的参数,可以在PC端打开,参数信息会通过log打出,仅在PC端时才会打印 */
|
|
18
|
+
// debug: boolean
|
|
19
|
+
// /** 微信硬件开发用 */
|
|
20
|
+
// beta?: boolean
|
|
21
|
+
// /** 必填,公众号的唯一标识 */
|
|
22
|
+
// appId: string
|
|
23
|
+
// /** 必填,生成签名的时间戳 */
|
|
24
|
+
// timestamp: string
|
|
25
|
+
// /** 必填,生成签名的随机串 */
|
|
26
|
+
// nonceStr: string
|
|
27
|
+
// /** 必填,签名 */
|
|
28
|
+
// signature: string
|
|
29
|
+
// /** 必填,需要使用的JS接口列表 */
|
|
30
|
+
// jsApiList: string[]
|
|
31
|
+
// }
|
|
32
|
+
|
|
33
|
+
/** 微信API错误码 */
|
|
34
|
+
export enum WechatErrorCode {
|
|
35
|
+
/** -1 */
|
|
36
|
+
SYSTEM_ERROR = -1,
|
|
37
|
+
/** 40001 */
|
|
38
|
+
INVALID_CREDENTIAL = 40001,
|
|
39
|
+
/** 40003 */
|
|
40
|
+
INVALID_OPENID = 40003,
|
|
41
|
+
/** 40008 */
|
|
42
|
+
INVALID_MESSAGE_TYPE = 40008,
|
|
43
|
+
/** 40013 */
|
|
44
|
+
INVALID_APPID = 40013,
|
|
45
|
+
/** 40036 */
|
|
46
|
+
INVALID_TEMPLATE_ID_SIZE = 40036,
|
|
47
|
+
/** 40037 */
|
|
48
|
+
INVALID_TEMPLATE_ID = 40037,
|
|
49
|
+
/** 40039 */
|
|
50
|
+
INVALID_URL_SIZE = 40039,
|
|
51
|
+
/** 40249 */
|
|
52
|
+
FORBID_MARKETING_CONTENT = 40249,
|
|
53
|
+
/** 43116 */
|
|
54
|
+
TEMPLATE_RESTRICTED = 43116,
|
|
55
|
+
/** 47003 */
|
|
56
|
+
PARAM_FORMAT_ERROR = 47003
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 微信API错误码映射 */
|
|
60
|
+
export type WechatErrorMessage = {
|
|
61
|
+
[WechatErrorCode.SYSTEM_ERROR]: string
|
|
62
|
+
[WechatErrorCode.INVALID_CREDENTIAL]: string
|
|
63
|
+
[WechatErrorCode.INVALID_OPENID]: string
|
|
64
|
+
[WechatErrorCode.INVALID_MESSAGE_TYPE]: string
|
|
65
|
+
[WechatErrorCode.INVALID_APPID]: string
|
|
66
|
+
[WechatErrorCode.INVALID_TEMPLATE_ID_SIZE]: string
|
|
67
|
+
[WechatErrorCode.INVALID_TEMPLATE_ID]: string
|
|
68
|
+
[WechatErrorCode.INVALID_URL_SIZE]: string
|
|
69
|
+
[WechatErrorCode.FORBID_MARKETING_CONTENT]: string
|
|
70
|
+
[WechatErrorCode.TEMPLATE_RESTRICTED]: string
|
|
71
|
+
[WechatErrorCode.PARAM_FORMAT_ERROR]: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 微信API错误码描述映射 */
|
|
75
|
+
export const WechatErrorMessages: WechatErrorMessage = {
|
|
76
|
+
[WechatErrorCode.SYSTEM_ERROR]: '系统繁忙,此时请开发者稍候再试',
|
|
77
|
+
[WechatErrorCode.INVALID_CREDENTIAL]: 'access_token isinvalid or not latest',
|
|
78
|
+
[WechatErrorCode.INVALID_OPENID]: '不合法的 OpenID',
|
|
79
|
+
[WechatErrorCode.INVALID_MESSAGE_TYPE]: '不合法的消息类型',
|
|
80
|
+
[WechatErrorCode.INVALID_APPID]: '不合法的 AppID',
|
|
81
|
+
[WechatErrorCode.INVALID_TEMPLATE_ID_SIZE]: '不合法的 template_id 长度',
|
|
82
|
+
[WechatErrorCode.INVALID_TEMPLATE_ID]: '不合法的 template_id',
|
|
83
|
+
[WechatErrorCode.INVALID_URL_SIZE]: '不合法的 URL 长度',
|
|
84
|
+
[WechatErrorCode.FORBID_MARKETING_CONTENT]: '禁止发送营销内容',
|
|
85
|
+
[WechatErrorCode.TEMPLATE_RESTRICTED]: '模板被限制下发',
|
|
86
|
+
[WechatErrorCode.PARAM_FORMAT_ERROR]: '参数格式错误'
|
|
87
|
+
}
|
|
88
|
+
export interface WechatAPICallbackResult {
|
|
89
|
+
errcode: 0
|
|
90
|
+
errmsg: 'ok'
|
|
91
|
+
msgid: number
|
|
92
|
+
}
|
|
93
|
+
export interface WechatAPICallbackError {
|
|
94
|
+
errcode: number
|
|
95
|
+
errmsg: string
|
|
96
|
+
}
|
|
97
|
+
export type WechatAPICallback<T = WechatAPICallbackError> = (err: WechatAPICallbackError, result: T) => void
|
|
98
|
+
|
|
99
|
+
export default class WechatAPI {
|
|
100
|
+
/**
|
|
101
|
+
* 初始化
|
|
102
|
+
* @param appId appId
|
|
103
|
+
* @param appSecret 秘钥
|
|
104
|
+
*/
|
|
105
|
+
constructor(appId: string, appSecret: string)
|
|
106
|
+
getAccessToken(callback: WechatAPICallback): void
|
|
107
|
+
|
|
108
|
+
getJsConfig(
|
|
109
|
+
params: WeixinGetJssdkConfigDTO,
|
|
110
|
+
callback: WechatAPICallback<WeixinGetJssdkConfigVO>
|
|
111
|
+
): void
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 发送模板消息
|
|
115
|
+
* 详细细节: https://developers.weixin.qq.com/doc/service/api/notify/template/api_sendtemplatemessage.html
|
|
116
|
+
* Examples:
|
|
117
|
+
* ```
|
|
118
|
+
* var templateId: '模板id';
|
|
119
|
+
* // URL置空,则在发送后,点击模板消息会进入一个空白页面(ios), 或无法点击(android)
|
|
120
|
+
* var url: 'http://weixin.qq.com/download';
|
|
121
|
+
* var data = {
|
|
122
|
+
* "first": {
|
|
123
|
+
* "value":"恭喜你购买成功!",
|
|
124
|
+
* "color":"#173177"
|
|
125
|
+
* },
|
|
126
|
+
* "keyword1":{
|
|
127
|
+
* "value":"巧克力",
|
|
128
|
+
* "color":"#173177"
|
|
129
|
+
* },
|
|
130
|
+
* "keyword2": {
|
|
131
|
+
* "value":"39.8元",
|
|
132
|
+
* "color":"#173177"
|
|
133
|
+
* },
|
|
134
|
+
* "keyword3": {
|
|
135
|
+
* "value":"2014年9月22日",
|
|
136
|
+
* "color":"#173177"
|
|
137
|
+
* },
|
|
138
|
+
* "remark":{
|
|
139
|
+
* "value":"欢迎再次购买!",
|
|
140
|
+
* "color":"#173177"
|
|
141
|
+
* }
|
|
142
|
+
* };
|
|
143
|
+
* api.sendTemplate('openid', templateId, dest, data, callback);
|
|
144
|
+
* ```
|
|
145
|
+
* Callback:
|
|
146
|
+
*
|
|
147
|
+
* - `err`, 调用失败时得到的异常
|
|
148
|
+
* - `result`, 调用正常时得到的对象
|
|
149
|
+
*
|
|
150
|
+
* @param {String} openid 用户的openid
|
|
151
|
+
* @param {String} templateId 模板ID
|
|
152
|
+
* @param {Object} dest 跳转目的地置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)
|
|
153
|
+
* @param {Object} data 渲染模板的数据
|
|
154
|
+
* @param {Function} callback 回调函数
|
|
155
|
+
*/
|
|
156
|
+
sendTemplate(
|
|
157
|
+
openid: string,
|
|
158
|
+
templateId: string,
|
|
159
|
+
dest: string | { url: string; miniprogram: string },
|
|
160
|
+
data: Record<string, { value: string; color?: string }>,
|
|
161
|
+
callback: WechatAPICallback
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// 微信配置
|
|
2
|
+
export let appId = ''
|
|
3
|
+
export let appSecret = ''
|
|
4
|
+
|
|
5
|
+
/** WechatAPI实例 */
|
|
6
|
+
// let api: WechatAPI
|
|
7
|
+
// export function createApi() {
|
|
8
|
+
// getConfig()
|
|
9
|
+
// if (!api) {
|
|
10
|
+
// api = new WechatAPI(appId, appSecret)
|
|
11
|
+
// }
|
|
12
|
+
// return api
|
|
13
|
+
// }
|
|
14
|
+
|
|
15
|
+
export interface WechatConfig {
|
|
16
|
+
/** 微信公众号appid */
|
|
17
|
+
appId: string
|
|
18
|
+
/** 微信公众号appsecret */
|
|
19
|
+
appSecret: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function setConfig(config: WechatConfig) {
|
|
23
|
+
appId = config.appId
|
|
24
|
+
appSecret = config.appSecret
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getConfig(): WechatConfig {
|
|
28
|
+
if (!appId || !appSecret) {
|
|
29
|
+
throw new Error('请先调用setConfig配置appId/appSecret')
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
appId,
|
|
33
|
+
appSecret
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function usePromiseWithResolvers<T>() {
|
|
2
|
+
let resolve: (value: T) => void = () => {},
|
|
3
|
+
reject: (reason?: any) => void= () => {}
|
|
4
|
+
const promise = new Promise<T>((_resolve, _reject) => {
|
|
5
|
+
resolve = _resolve
|
|
6
|
+
reject = _reject
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
promise,
|
|
11
|
+
resolve,
|
|
12
|
+
reject
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { baseDemain } from '../constants'
|
|
2
|
+
export function requestGetBase<T>(
|
|
3
|
+
url: string,
|
|
4
|
+
params: Record<string, any>,
|
|
5
|
+
options: RequestInit = {}
|
|
6
|
+
) {
|
|
7
|
+
const urlParams = new URLSearchParams(params)
|
|
8
|
+
return requestBase<T>(`${url}?${urlParams}`, { ...options, method: 'GET' })
|
|
9
|
+
}
|
|
10
|
+
export function requestPostBase<T>(
|
|
11
|
+
url: string,
|
|
12
|
+
data: Record<string, any>,
|
|
13
|
+
options: RequestInit = {}
|
|
14
|
+
) {
|
|
15
|
+
return requestBase<T>(url, { ...options, method: 'POST', body: JSON.stringify(data) })
|
|
16
|
+
}
|
|
17
|
+
export async function requestBase<T>(url: string, options: RequestInit = {}) {
|
|
18
|
+
const res = await fetch(`${baseDemain}${url}`, options)
|
|
19
|
+
return (await res.json()) as T
|
|
20
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* 生成随机字符串
|
|
3
|
+
*/
|
|
4
|
+
export const createNonceStr = function () {
|
|
5
|
+
return Math.random().toString(36).substr(2, 15)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/*!
|
|
9
|
+
* 生成时间戳
|
|
10
|
+
*/
|
|
11
|
+
export const createTimestamp = function () {
|
|
12
|
+
return Math.round(new Date().getTime() / 1000) + ''
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/*!
|
|
16
|
+
* 排序查询字符串
|
|
17
|
+
*/
|
|
18
|
+
export const raw = function (args: Record<string, string | number>) {
|
|
19
|
+
var keys = Object.keys(args)
|
|
20
|
+
keys = keys.sort()
|
|
21
|
+
var newArgs: typeof args = {}
|
|
22
|
+
keys.forEach(function (key) {
|
|
23
|
+
newArgs[key.toLowerCase()] = args[key]
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
var string = ''
|
|
27
|
+
var newKeys = Object.keys(newArgs)
|
|
28
|
+
for (var i = 0; i < newKeys.length; i++) {
|
|
29
|
+
var k = newKeys[i]
|
|
30
|
+
string += '&' + k + '=' + newArgs[k]
|
|
31
|
+
}
|
|
32
|
+
return string.substr(1)
|
|
33
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"sourceMap": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["index.ts", "src/**/*"],
|
|
14
|
+
"exclude": ["node_modules", "dist"]
|
|
15
|
+
}
|