更新发送消息结构体
This commit is contained in:
parent
55cf87e294
commit
72338d99bb
@ -3,6 +3,7 @@ package openwechat
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func defaultBot(modes ...mode) *Bot {
|
func defaultBot(modes ...mode) *Bot {
|
||||||
@ -189,6 +190,7 @@ func TestSendMessage(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
if err = self.SendTextToFriend(helper, "send test message twice ! received?"); err != nil {
|
if err = self.SendTextToFriend(helper, "send test message twice ! received?"); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
438
message.go
438
message.go
@ -1,270 +1,271 @@
|
|||||||
package openwechat
|
package openwechat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strconv"
|
||||||
"sync"
|
"strings"
|
||||||
"time"
|
"sync"
|
||||||
"unicode"
|
"time"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
IsAt bool
|
IsAt bool
|
||||||
AppInfo struct {
|
AppInfo struct {
|
||||||
Type int
|
Type int
|
||||||
AppID string
|
AppID string
|
||||||
}
|
}
|
||||||
AppMsgType int
|
AppMsgType int
|
||||||
HasProductId int
|
HasProductId int
|
||||||
ImgHeight int
|
ImgHeight int
|
||||||
ImgStatus int
|
ImgStatus int
|
||||||
ImgWidth int
|
ImgWidth int
|
||||||
ForwardFlag int
|
ForwardFlag int
|
||||||
MsgType int
|
MsgType int
|
||||||
Status int
|
Status int
|
||||||
StatusNotifyCode int
|
StatusNotifyCode int
|
||||||
SubMsgType int
|
SubMsgType int
|
||||||
VoiceLength int
|
VoiceLength int
|
||||||
CreateTime int64
|
CreateTime int64
|
||||||
NewMsgId int64
|
NewMsgId int64
|
||||||
PlayLength int64
|
PlayLength int64
|
||||||
MediaId string
|
MediaId string
|
||||||
MsgId string
|
MsgId string
|
||||||
EncryFileName string
|
EncryFileName string
|
||||||
FileName string
|
FileName string
|
||||||
FileSize string
|
FileSize string
|
||||||
Content string
|
Content string
|
||||||
FromUserName string
|
FromUserName string
|
||||||
OriContent string
|
OriContent string
|
||||||
StatusNotifyUserName string
|
StatusNotifyUserName string
|
||||||
Ticket string
|
Ticket string
|
||||||
ToUserName string
|
ToUserName string
|
||||||
Url string
|
Url string
|
||||||
senderInGroupUserName string
|
senderInGroupUserName string
|
||||||
RecommendInfo RecommendInfo
|
RecommendInfo RecommendInfo
|
||||||
Bot *Bot
|
Bot *Bot
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
Context context.Context
|
Context context.Context
|
||||||
item map[string]interface{}
|
item map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取消息的发送者
|
// 获取消息的发送者
|
||||||
func (m *Message) Sender() (*User, error) {
|
func (m *Message) Sender() (*User, error) {
|
||||||
members, err := m.Bot.self.Members(true)
|
members, err := m.Bot.self.Members(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if m.FromUserName == m.Bot.self.User.UserName {
|
if m.FromUserName == m.Bot.self.User.UserName {
|
||||||
return m.Bot.self.User, nil
|
return m.Bot.self.User, nil
|
||||||
}
|
}
|
||||||
user := members.SearchByUserName(1, m.FromUserName)
|
user := members.SearchByUserName(1, m.FromUserName)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, noSuchUserFoundError
|
return nil, noSuchUserFoundError
|
||||||
}
|
}
|
||||||
return user.First().Detail()
|
return user.First().Detail()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取消息在群里面的发送者
|
// 获取消息在群里面的发送者
|
||||||
func (m *Message) SenderInGroup() (*User, error) {
|
func (m *Message) SenderInGroup() (*User, error) {
|
||||||
if !m.IsSendByGroup() {
|
if !m.IsSendByGroup() {
|
||||||
return nil, errors.New("message is not from group")
|
return nil, errors.New("message is not from group")
|
||||||
}
|
}
|
||||||
group, err := m.Sender()
|
group, err := m.Sender()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
group, err = group.Detail()
|
group, err = group.Detail()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
users := group.MemberList.SearchByUserName(1, m.senderInGroupUserName)
|
users := group.MemberList.SearchByUserName(1, m.senderInGroupUserName)
|
||||||
if users == nil {
|
if users == nil {
|
||||||
return nil, noSuchUserFoundError
|
return nil, noSuchUserFoundError
|
||||||
}
|
}
|
||||||
return users.First(), nil
|
return users.First(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取消息的接收者
|
// 获取消息的接收者
|
||||||
func (m *Message) Receiver() (*User, error) {
|
func (m *Message) Receiver() (*User, error) {
|
||||||
if m.IsSendByGroup() {
|
if m.IsSendByGroup() {
|
||||||
if sender, err := m.Sender(); err != nil {
|
if sender, err := m.Sender(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
users := sender.MemberList.SearchByUserName(1, m.ToUserName)
|
users := sender.MemberList.SearchByUserName(1, m.ToUserName)
|
||||||
if users == nil {
|
if users == nil {
|
||||||
return nil, noSuchUserFoundError
|
return nil, noSuchUserFoundError
|
||||||
}
|
}
|
||||||
return users.First(), nil
|
return users.First(), nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
users := m.Bot.self.MemberList.SearchByUserName(1, m.ToUserName)
|
users := m.Bot.self.MemberList.SearchByUserName(1, m.ToUserName)
|
||||||
if users == nil {
|
if users == nil {
|
||||||
return nil, noSuchUserFoundError
|
return nil, noSuchUserFoundError
|
||||||
}
|
}
|
||||||
return users.First(), nil
|
return users.First(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断消息是否由自己发送
|
// 判断消息是否由自己发送
|
||||||
func (m *Message) IsSendBySelf() bool {
|
func (m *Message) IsSendBySelf() bool {
|
||||||
return m.FromUserName == m.Bot.self.User.UserName
|
return m.FromUserName == m.Bot.self.User.UserName
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断消息是否由好友发送
|
// 判断消息是否由好友发送
|
||||||
func (m *Message) IsSendByFriend() bool {
|
func (m *Message) IsSendByFriend() bool {
|
||||||
return !m.IsSendByGroup() && strings.HasPrefix(m.FromUserName, "@")
|
return !m.IsSendByGroup() && strings.HasPrefix(m.FromUserName, "@")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断消息是否由群组发送
|
// 判断消息是否由群组发送
|
||||||
func (m *Message) IsSendByGroup() bool {
|
func (m *Message) IsSendByGroup() bool {
|
||||||
return strings.HasPrefix(m.FromUserName, "@@")
|
return strings.HasPrefix(m.FromUserName, "@@")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回复消息
|
// 回复消息
|
||||||
func (m *Message) Reply(msgType int, content, mediaId string) error {
|
func (m *Message) Reply(msgType int, content, mediaId string) error {
|
||||||
msg := NewSendMessage(msgType, content, m.Bot.self.User.UserName, m.FromUserName, mediaId)
|
msg := NewSendMessage(msgType, content, m.Bot.self.User.UserName, m.FromUserName, mediaId)
|
||||||
info := m.Bot.storage.LoginInfo
|
info := m.Bot.storage.LoginInfo
|
||||||
request := m.Bot.storage.Request
|
request := m.Bot.storage.Request
|
||||||
return m.Bot.Caller.WebWxSendMsg(msg, info, request)
|
return m.Bot.Caller.WebWxSendMsg(msg, info, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回复文本消息
|
// 回复文本消息
|
||||||
func (m *Message) ReplyText(content string) error {
|
func (m *Message) ReplyText(content string) error {
|
||||||
return m.Reply(TextMessage, content, "")
|
return m.Reply(TextMessage, content, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回复图片消息
|
// 回复图片消息
|
||||||
func (m *Message) ReplyImage(file *os.File) error {
|
func (m *Message) ReplyImage(file *os.File) error {
|
||||||
info := m.Bot.storage.LoginInfo
|
info := m.Bot.storage.LoginInfo
|
||||||
request := m.Bot.storage.Request
|
request := m.Bot.storage.Request
|
||||||
return m.Bot.Caller.WebWxSendImageMsg(file, request, info, m.Bot.self.UserName, m.FromUserName)
|
return m.Bot.Caller.WebWxSendImageMsg(file, request, info, m.Bot.self.UserName, m.FromUserName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsText() bool {
|
func (m *Message) IsText() bool {
|
||||||
return m.MsgType == 1 && m.Url == ""
|
return m.MsgType == 1 && m.Url == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsMap() bool {
|
func (m *Message) IsMap() bool {
|
||||||
return m.MsgType == 1 && m.Url != ""
|
return m.MsgType == 1 && m.Url != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsPicture() bool {
|
func (m *Message) IsPicture() bool {
|
||||||
return m.MsgType == 3 || m.MsgType == 47
|
return m.MsgType == 3 || m.MsgType == 47
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsVoice() bool {
|
func (m *Message) IsVoice() bool {
|
||||||
return m.MsgType == 34
|
return m.MsgType == 34
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsFriendAdd() bool {
|
func (m *Message) IsFriendAdd() bool {
|
||||||
return m.MsgType == 37
|
return m.MsgType == 37
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsCard() bool {
|
func (m *Message) IsCard() bool {
|
||||||
return m.MsgType == 42
|
return m.MsgType == 42
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsVideo() bool {
|
func (m *Message) IsVideo() bool {
|
||||||
return m.MsgType == 43 || m.MsgType == 62
|
return m.MsgType == 43 || m.MsgType == 62
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsMedia() bool {
|
func (m *Message) IsMedia() bool {
|
||||||
return m.MsgType == 49
|
return m.MsgType == 49
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsRecalled() bool {
|
func (m *Message) IsRecalled() bool {
|
||||||
return m.MsgType == 10002
|
return m.MsgType == 10002
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsSystem() bool {
|
func (m *Message) IsSystem() bool {
|
||||||
return m.MsgType == 10000
|
return m.MsgType == 10000
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) IsNotify() bool {
|
func (m *Message) IsNotify() bool {
|
||||||
return m.MsgType == 51 && m.StatusNotifyCode != 0
|
return m.MsgType == 51 && m.StatusNotifyCode != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断消息是否为文件类型的消息
|
// 判断消息是否为文件类型的消息
|
||||||
func (m *Message) HasFile() bool {
|
func (m *Message) HasFile() bool {
|
||||||
return m.IsPicture() || m.IsVoice() || m.IsVideo() || m.IsMedia()
|
return m.IsPicture() || m.IsVoice() || m.IsVideo() || m.IsMedia()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件消息的文件
|
// 获取文件消息的文件
|
||||||
func (m *Message) GetFile() (*http.Response, error) {
|
func (m *Message) GetFile() (*http.Response, error) {
|
||||||
if !m.HasFile() {
|
if !m.HasFile() {
|
||||||
return nil, errors.New("invalid message type")
|
return nil, errors.New("invalid message type")
|
||||||
}
|
}
|
||||||
if m.IsPicture() {
|
if m.IsPicture() {
|
||||||
return m.Bot.Caller.Client.WebWxGetMsgImg(m, m.Bot.storage.LoginInfo)
|
return m.Bot.Caller.Client.WebWxGetMsgImg(m, m.Bot.storage.LoginInfo)
|
||||||
}
|
}
|
||||||
if m.IsVoice() {
|
if m.IsVoice() {
|
||||||
return m.Bot.Caller.Client.WebWxGetVoice(m, m.Bot.storage.LoginInfo)
|
return m.Bot.Caller.Client.WebWxGetVoice(m, m.Bot.storage.LoginInfo)
|
||||||
}
|
}
|
||||||
if m.IsVideo() {
|
if m.IsVideo() {
|
||||||
return m.Bot.Caller.Client.WebWxGetVideo(m, m.Bot.storage.LoginInfo)
|
return m.Bot.Caller.Client.WebWxGetVideo(m, m.Bot.storage.LoginInfo)
|
||||||
}
|
}
|
||||||
if m.IsMedia() {
|
if m.IsMedia() {
|
||||||
return m.Bot.Caller.Client.WebWxGetMedia(m, m.Bot.storage.LoginInfo)
|
return m.Bot.Caller.Client.WebWxGetMedia(m, m.Bot.storage.LoginInfo)
|
||||||
}
|
}
|
||||||
return nil, errors.New("unsupported type")
|
return nil, errors.New("unsupported type")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取card类型
|
// 获取card类型
|
||||||
func (m *Message) Card() (*Card, error) {
|
func (m *Message) Card() (*Card, error) {
|
||||||
if !m.IsCard() {
|
if !m.IsCard() {
|
||||||
return nil, errors.New("card message required")
|
return nil, errors.New("card message required")
|
||||||
}
|
}
|
||||||
var card Card
|
var card Card
|
||||||
content := XmlFormString(m.Content)
|
content := XmlFormString(m.Content)
|
||||||
err := xml.Unmarshal([]byte(content), &card)
|
err := xml.Unmarshal([]byte(content), &card)
|
||||||
return &card, err
|
return &card, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 往消息上下文中设置值
|
// 往消息上下文中设置值
|
||||||
// goroutine safe
|
// goroutine safe
|
||||||
func (m *Message) Set(key string, value interface{}) {
|
func (m *Message) Set(key string, value interface{}) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
if m.item == nil {
|
if m.item == nil {
|
||||||
m.item = make(map[string]interface{})
|
m.item = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
m.item[key] = value
|
m.item[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从消息上下文中获取值
|
// 从消息上下文中获取值
|
||||||
// goroutine safe
|
// goroutine safe
|
||||||
func (m *Message) Get(key string) (value interface{}, exist bool) {
|
func (m *Message) Get(key string) (value interface{}, exist bool) {
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
defer m.mu.RUnlock()
|
defer m.mu.RUnlock()
|
||||||
value, exist = m.item[key]
|
value, exist = m.item[key]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 消息初始化,根据不同的消息作出不同的处理
|
// 消息初始化,根据不同的消息作出不同的处理
|
||||||
func (m *Message) init(bot *Bot) {
|
func (m *Message) init(bot *Bot) {
|
||||||
m.Bot = bot
|
m.Bot = bot
|
||||||
if m.IsSendByGroup() {
|
if m.IsSendByGroup() {
|
||||||
data := strings.Split(m.Content, ":<br/>")
|
data := strings.Split(m.Content, ":<br/>")
|
||||||
m.Content = strings.Join(data[1:], "")
|
m.Content = strings.Join(data[1:], "")
|
||||||
m.senderInGroupUserName = data[0]
|
m.senderInGroupUserName = data[0]
|
||||||
receiver, err := m.Receiver()
|
receiver, err := m.Receiver()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
displayName := receiver.DisplayName
|
displayName := receiver.DisplayName
|
||||||
if displayName == "" {
|
if displayName == "" {
|
||||||
displayName = receiver.NickName
|
displayName = receiver.NickName
|
||||||
}
|
}
|
||||||
atFlag := "@" + displayName
|
atFlag := "@" + displayName
|
||||||
index := len(atFlag) + 1 + 1
|
index := len(atFlag) + 1 + 1
|
||||||
if strings.HasPrefix(m.Content, atFlag) && unicode.IsSpace(rune(m.Content[index])) {
|
if strings.HasPrefix(m.Content, atFlag) && unicode.IsSpace(rune(m.Content[index])) {
|
||||||
m.IsAt = true
|
m.IsAt = true
|
||||||
m.Content = m.Content[index+1:]
|
m.Content = m.Content[index+1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (m *Message) Agree() error {
|
//func (m *Message) Agree() error {
|
||||||
@ -276,76 +277,77 @@ func (m *Message) init(bot *Bot) {
|
|||||||
|
|
||||||
// 发送消息的结构体
|
// 发送消息的结构体
|
||||||
type SendMessage struct {
|
type SendMessage struct {
|
||||||
Type int
|
Type int
|
||||||
Content string
|
Content string
|
||||||
FromUserName string
|
FromUserName string
|
||||||
ToUserName string
|
ToUserName string
|
||||||
LocalID int64
|
LocalID string
|
||||||
ClientMsgId int64
|
ClientMsgId string
|
||||||
MediaId string
|
MediaId string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessage的构造方法
|
// SendMessage的构造方法
|
||||||
func NewSendMessage(msgType int, content, fromUserName, toUserName, mediaId string) *SendMessage {
|
func NewSendMessage(msgType int, content, fromUserName, toUserName, mediaId string) *SendMessage {
|
||||||
return &SendMessage{
|
id := strconv.FormatInt(time.Now().Unix()*1e4, 10)
|
||||||
Type: msgType,
|
return &SendMessage{
|
||||||
Content: content,
|
Type: msgType,
|
||||||
FromUserName: fromUserName,
|
Content: content,
|
||||||
ToUserName: toUserName,
|
FromUserName: fromUserName,
|
||||||
LocalID: time.Now().Unix() * 1e4,
|
ToUserName: toUserName,
|
||||||
ClientMsgId: time.Now().Unix() * 1e4,
|
LocalID: id,
|
||||||
MediaId: mediaId,
|
ClientMsgId: id,
|
||||||
}
|
MediaId: mediaId,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文本消息的构造方法
|
// 文本消息的构造方法
|
||||||
func NewTextSendMessage(content, fromUserName, toUserName string) *SendMessage {
|
func NewTextSendMessage(content, fromUserName, toUserName string) *SendMessage {
|
||||||
return NewSendMessage(TextMessage, content, fromUserName, toUserName, "")
|
return NewSendMessage(TextMessage, content, fromUserName, toUserName, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 媒体消息的构造方法
|
// 媒体消息的构造方法
|
||||||
func NewMediaSendMessage(msgType int, fromUserName, toUserName, mediaId string) *SendMessage {
|
func NewMediaSendMessage(msgType int, fromUserName, toUserName, mediaId string) *SendMessage {
|
||||||
return NewSendMessage(msgType, "", fromUserName, toUserName, mediaId)
|
return NewSendMessage(msgType, "", fromUserName, toUserName, mediaId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一些特殊类型的消息会携带该结构体信息
|
// 一些特殊类型的消息会携带该结构体信息
|
||||||
type RecommendInfo struct {
|
type RecommendInfo struct {
|
||||||
Alias string
|
OpCode int
|
||||||
AttrStatus int64
|
Scene int
|
||||||
City string
|
Sex int
|
||||||
Content string
|
VerifyFlag int
|
||||||
NickName string
|
AttrStatus int64
|
||||||
OpCode int
|
QQNum int64
|
||||||
Province string
|
Alias string
|
||||||
QQNum int64
|
City string
|
||||||
Scene int
|
Content string
|
||||||
Sex int
|
NickName string
|
||||||
Signature string
|
Province string
|
||||||
Ticket string
|
Signature string
|
||||||
UserName string
|
Ticket string
|
||||||
VerifyFlag int
|
UserName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 名片消息内容
|
// 名片消息内容
|
||||||
type Card struct {
|
type Card struct {
|
||||||
XMLName xml.Name `xml:"msg"`
|
XMLName xml.Name `xml:"msg"`
|
||||||
BigHeadImgUrl string `xml:"bigheadimgurl,attr"`
|
ImageStatus int `xml:"imagestatus,attr"`
|
||||||
SmallHeadImgUrl string `xml:"smallheadimgurl,attr"`
|
Scene int `xml:"scene,attr"`
|
||||||
UserName string `xml:"username,attr"`
|
Sex int `xml:"sex,attr"`
|
||||||
NickName string `xml:"nickname,attr"`
|
Certflag int `xml:"certflag,attr"`
|
||||||
ShortPy string `xml:"shortpy,attr"`
|
BigHeadImgUrl string `xml:"bigheadimgurl,attr"`
|
||||||
Alias string `xml:"alias,attr"` // Note: 这个是名片用户的微信号
|
SmallHeadImgUrl string `xml:"smallheadimgurl,attr"`
|
||||||
ImageStatus int `xml:"imagestatus,attr"`
|
UserName string `xml:"username,attr"`
|
||||||
Scene int `xml:"scene,attr"`
|
NickName string `xml:"nickname,attr"`
|
||||||
Province string `xml:"province,attr"`
|
ShortPy string `xml:"shortpy,attr"`
|
||||||
City string `xml:"city,attr"`
|
Alias string `xml:"alias,attr"` // Note: 这个是名片用户的微信号
|
||||||
Sign string `xml:"sign,attr"`
|
Province string `xml:"province,attr"`
|
||||||
Sex int `xml:"sex,attr"`
|
City string `xml:"city,attr"`
|
||||||
Certflag int `xml:"certflag,attr"`
|
Sign string `xml:"sign,attr"`
|
||||||
Certinfo string `xml:"certinfo,attr"`
|
Certinfo string `xml:"certinfo,attr"`
|
||||||
BrandIconUrl string `xml:"brandIconUrl,attr"`
|
BrandIconUrl string `xml:"brandIconUrl,attr"`
|
||||||
BrandHomeUr string `xml:"brandHomeUr,attr"`
|
BrandHomeUr string `xml:"brandHomeUr,attr"`
|
||||||
BrandSubscriptConfigUrl string `xml:"brandSubscriptConfigUrl,attr"`
|
BrandSubscriptConfigUrl string `xml:"brandSubscriptConfigUrl,attr"`
|
||||||
BrandFlags string `xml:"brandFlags,attr"`
|
BrandFlags string `xml:"brandFlags,attr"`
|
||||||
RegionCode string `xml:"regionCode,attr"`
|
RegionCode string `xml:"regionCode,attr"`
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user