|
- 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)
- }
- }
|