forked from royalrick/weapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
customer_service_message.go
268 lines (222 loc) · 6.94 KB
/
customer_service_message.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
package weapp
import (
"encoding/json"
"errors"
"net/http"
"strings"
)
const (
apiSendMessage = "/cgi-bin/message/custom/send"
apiSetTyping = "/cgi-bin/message/custom/typing"
apiUploadTemplateMedia = "/cgi-bin/media/upload"
apiGetTemplateMedia = "/cgi-bin/media/get"
)
// csMsgType 消息类型
type csMsgType string
// 所有消息类型
const (
csMsgTypeText csMsgType = "text" // 文本消息类型
csMsgTypeLink = "link" // 图文链接消息类型
csMsgTypeImage = "image" // 图片消息类型
csMsgTypeMPCard = "miniprogrampage" // 小程序卡片消息类型
)
// csMessage 消息体
type csMessage struct {
Receiver string `json:"touser"` // user openID
Type csMsgType `json:"msgtype"` // text | image | link | miniprogrampage
Text CSMsgText `json:"text,omitempty"`
Image CSMsgImage `json:"image,omitempty"`
Link CSMsgLink `json:"link,omitempty"`
MPCard CSMsgMPCard `json:"miniprogrampage,omitempty"`
}
// CSMsgText 接收的文本消息
type CSMsgText struct {
Content string `json:"content"`
}
// SendTo 发送文本消息
//
// openID 用户openID
// token 微信 access_token
func (msg CSMsgText) SendTo(openID, token string) (*CommonError, error) {
params := csMessage{
Receiver: openID,
Type: csMsgTypeText,
Text: msg,
}
return sendMessage(token, params)
}
// CSMsgImage 客服图片消息
type CSMsgImage struct {
MediaID string `json:"media_id"` // 发送的图片的媒体ID,通过 新增素材接口 上传图片文件获得。
}
// SendTo 发送图片消息
//
// openID 用户openID
// token 微信 access_token
func (msg CSMsgImage) SendTo(openID, token string) (*CommonError, error) {
params := csMessage{
Receiver: openID,
Type: csMsgTypeImage,
Image: msg,
}
return sendMessage(token, params)
}
// CSMsgLink 图文链接消息
type CSMsgLink struct {
Title string `json:"title"`
Description string `json:"description"`
URL string `json:"url"`
ThumbURL string `json:"thumb_url"`
}
// SendTo 发送图文链接消息
//
// openID 用户openID
// token 微信 access_token
func (msg CSMsgLink) SendTo(openID, token string) (*CommonError, error) {
params := csMessage{
Receiver: openID,
Type: csMsgTypeLink,
Link: msg,
}
return sendMessage(token, params)
}
// CSMsgMPCard 接收的卡片消息
type CSMsgMPCard struct {
Title string `json:"title"` // 标题
PagePath string `json:"pagepath"` // 小程序页面路径
ThumbMediaID string `json:"thumb_media_id"` // 小程序消息卡片的封面, image 类型的 media_id,通过 新增素材接口 上传图片文件获得,建议大小为 520*416
}
// SendTo 发送卡片消息
//
// openID 用户openID
// token 微信 access_token
func (msg CSMsgMPCard) SendTo(openID, token string) (*CommonError, error) {
params := csMessage{
Receiver: openID,
Type: "miniprogrampage",
MPCard: msg,
}
return sendMessage(token, params)
}
// send 发送消息
//
// token 微信 access_token
func sendMessage(token string, params interface{}) (*CommonError, error) {
api := baseURL + apiSendMessage
return doSendMessage(token, params, api)
}
func doSendMessage(token string, params interface{}, api string) (*CommonError, error) {
url, err := tokenAPI(api, token)
if err != nil {
return nil, err
}
res := new(CommonError)
if err := postJSON(url, params, res); err != nil {
return nil, err
}
return res, nil
}
// SetTypingCommand 下发客服当前输入状态命令
type SetTypingCommand = string
// 所有下发客服当前输入状态命令
const (
SetTypingCommandTyping SetTypingCommand = "Typing" // 对用户下发"正在输入"状态
SetTypingCommandCancelTyping = "CancelTyping" // 取消对用户的"正在输入"状态
)
// SetTyping 下发客服当前输入状态给用户。
//
// token 接口调用凭证
// openID 用户的 OpenID
// cmd 命令
func SetTyping(token, openID string, cmd SetTypingCommand) (*CommonError, error) {
api := baseURL + apiSetTyping
return setTyping(token, openID, cmd, api)
}
func setTyping(token, openID string, cmd SetTypingCommand, api string) (*CommonError, error) {
url, err := tokenAPI(api, token)
if err != nil {
return nil, err
}
params := requestParams{
"touser": openID,
"command": cmd,
}
res := new(CommonError)
if err := postJSON(url, params, res); err != nil {
return nil, err
}
return res, nil
}
// TempMediaType 文件类型
type TempMediaType = string
// 所有文件类型
const (
TempMediaTypeImage TempMediaType = "image" // 图片
)
// UploadTempMediaResponse 上传媒体文件返回
type UploadTempMediaResponse struct {
CommonError
Type string `json:"type"` // 文件类型
MediaID string `json:"media_id"` // 媒体文件上传后,获取标识,3天内有效。
CreatedAt uint `json:"created_at"` // 媒体文件上传时间戳
}
// UploadTempMedia 把媒体文件上传到微信服务器。目前仅支持图片。用于发送客服消息或被动回复用户消息。
//
// token 接口调用凭证
// mediaType 文件类型
// medianame 媒体文件名
func UploadTempMedia(token string, mediaType TempMediaType, medianame string) (*UploadTempMediaResponse, error) {
api := baseURL + apiUploadTemplateMedia
return uploadTempMedia(token, mediaType, medianame, api)
}
func uploadTempMedia(token string, mediaType TempMediaType, medianame, api string) (*UploadTempMediaResponse, error) {
queries := requestQueries{
"type": mediaType,
"access_token": token,
}
url, err := encodeURL(api, queries)
if err != nil {
return nil, err
}
res := new(UploadTempMediaResponse)
if err := postFormByFile(url, "media", medianame, res); err != nil {
return nil, err
}
return res, nil
}
// GetTempMedia 获取客服消息内的临时素材。即下载临时的多媒体文件。目前小程序仅支持下载图片文件。
//
// token 接口调用凭证
// mediaID 媒体文件 ID
func GetTempMedia(token, mediaID string) (*http.Response, *CommonError, error) {
api := baseURL + apiGetTemplateMedia
return getTempMedia(token, mediaID, api)
}
func getTempMedia(token, mediaID, api string) (*http.Response, *CommonError, error) {
queries := requestQueries{
"access_token": token,
"media_id": mediaID,
}
url, err := encodeURL(api, queries)
if err != nil {
return nil, nil, err
}
res, err := http.Get(url)
if err != nil {
return nil, nil, err
}
response := new(CommonError)
switch header := res.Header.Get("Content-Type"); {
case strings.HasPrefix(header, "application/json"): // 返回错误信息
if err := json.NewDecoder(res.Body).Decode(response); err != nil {
res.Body.Close()
return nil, nil, err
}
return res, response, nil
case strings.HasPrefix(header, "image"): // 返回文件 TODO: 应该确认一下
return res, response, nil
default:
res.Body.Close()
return nil, nil, errors.New("invalid response header: " + header)
}
}