diff --git a/platformapi/enterprise_wechat/create_group.go b/platformapi/enterprise_wechat/create_group.go index 9b5c6715..89c08d5e 100644 --- a/platformapi/enterprise_wechat/create_group.go +++ b/platformapi/enterprise_wechat/create_group.go @@ -1,18 +1,101 @@ package enterprise_wechat -type CreateGroup struct { - AccessToken string `json:"access_token"` // 调用接口凭证 [必填] - Scene int `json:"scene"` // 1 - 群的小程序插件, 2 - 群的二维码插件 [必填] - ChatIDList []string `json:"chat_id_list"` // 使用该配置的客户群ID列表,支持5个 [必填] +import ( + "errors" + "git.rosy.net.cn/baseapi/utils" + "net/http" +) - Remark string `json:"remark"` // 联系方式的备注信息,用于助记,超过30个字符将被截断 - AutoCreateRoom int `json:"auto_create_room"` // 当群满了后,是否自动新建群。0-否;1-是。 默认为1 - RoomBaseName string `json:"room_base_name"` // 自动建群的群名前缀 - RoomBaseID int `json:"room_base_id"` // 自动建群的群起始序号 - State string `json:"state"` // 企业自定义的state参数,用于区分不同的入群渠道。 +// 创建成员,将门店老板创建为京西员工 +func (a *API) CreateBoss2JxStaff(param *CreateBoos2JXStaffReq) error { + a.CheckAccessTokenExpiresIn() + result, err := a.AccessAPI(WeChatBaseApi, CreateBoosToJxStaff, http.MethodPost, utils.Struct2FlatMap(param)) + if err != nil { + return err + } + + errResult := &Err{} + if err := utils.Map2StructByJson(result, errResult, false); err != nil { + return err + } + if errResult.ErrCode != 0 { + return errors.New(errResult.ErrMsg) + } + return nil } -// 创建客户入群方式 -func (a *API) CreateUserGroup() { - +// 创建会话群聊 +// 只允许企业自建应用调用,且应用的可见范围必须是根部门; +// 群成员人数不可超过管理端配置的“群成员人数上限”,且最大不可超过2000人; +// 每企业创建群数不可超过1000/天; +func (a *API) CreateAppChat(param *CreateAppChatParamReq) error { + a.CheckAccessTokenExpiresIn() + data, err := a.AccessAPI(WeChatBaseApi, CreateAppChat, http.MethodPost, utils.Struct2FlatMap(param)) + if err != nil { + return err + } + errResult := &Err{} + if err := utils.Map2StructByJson(data, errResult, false); err != nil { + return err + } + if errResult.ErrCode != 0 { + return errors.New(errResult.ErrMsg) + } + return nil +} + +// 获取所有的部门列表 +func (a *API) GetAllDepartmentList() ([]*Department, error) { + a.CheckAccessTokenExpiresIn() + data, err := a.AccessAPI(WeChatBaseApi, GetAllDepartmentListById, http.MethodGet, map[string]interface{}{"access_token": a.accessToken}) + if err != nil { + return nil, err + } + result := &GetAllDepartmentListRes{} + if err := utils.Map2StructByJson(data, result, false); err != nil { + return nil, err + } + if result.ErrCode != 0 { + return nil, errors.New(result.ErrMsg) + } + + return result.Department, nil +} + +// 获取企业部门用户详细情况 +func (a *API) GetEnterpriseStaffInfo(department int) ([]*UserList, error) { + a.CheckAccessTokenExpiresIn() + departmentUserDetail, err := a.AccessAPI(WeChatBaseApi, GetDepartmentUserDetail, http.MethodGet, map[string]interface{}{"department_id": department, "fetch_child": 0}) + if err != nil { + return nil, err + } + result := &GetEnterpriseStaffInfoRes{} + if err := utils.Map2StructByJson(departmentUserDetail, result, false); err != nil { + return nil, err + } + + if result.ErrCode != 0 { + return nil, errors.New(result.ErrMsg) + } + + return result.UserList, nil +} + +// 通过手机号获取用户消息 +func (a *API) GetUserIdByMobile(mobile string) (string, error) { + a.CheckAccessTokenExpiresIn() + data, err := a.AccessAPI(WeChatBaseApi, GetUserByMobileUrl, http.MethodPost, map[string]interface{}{"mobile": mobile}) + if err != nil { + return "", err + } + + result := &GetUserByMobileRes{} + if err := utils.Map2StructByJson(data, result, false); err != nil { + return "", err + } + if result.ErrCode != 0 { + return "", errors.New(result.ErrMsg) + } + + return result.UserId, nil } diff --git a/platformapi/enterprise_wechat/create_group_model.go b/platformapi/enterprise_wechat/create_group_model.go new file mode 100644 index 00000000..f5f9b1e9 --- /dev/null +++ b/platformapi/enterprise_wechat/create_group_model.go @@ -0,0 +1,66 @@ +package enterprise_wechat + +type CreateBoos2JXStaffReq struct { + Userid string `json:"userid"` // y 用户id 成员UserID。对应管理端的帐号,企业内必须唯一。长度为1~64个字节。只能由数字、字母和“_-@.”四种字符组成,且第一个字符必须是数字或字母。系统进行唯一性检查时会忽略大小写 + Name string `json:"name"` // y 成员名称。长度为1~64个utf8字符 + Alias string `json:"alias"` // n 成员别名。长度1~64个utf8字符 + Mobile string `json:"mobile"` // y 手机号码。企业内必须唯一,mobile/email二者不能同时为空 + Department []int `json:"department"` // y 成员所属部门id列表,不超过100个 + Order []int `json:"order"` // n 部门内的排序值,默认为0, + Position string `json:"position"` // n 职务信息。 + Gender string `json:"gender"` // n 性别。1表示男性,2表示女性性别。1表示男性,2表示女性 + Email string `json:"email"` // y 邮箱 + IsLeaderInDept []int `json:"is_leader_in_dept"` // n 个数必须和参数department的个数一致,表示在所在的部门内是否为部门负责人。1表示为部门负责人,0表示非部门负责人 + Enable int `json:"enable"` // n 直属上级UserID + AvatarMediaid string `json:"avatar_mediaid"` // n 成员头像的mediaid + Telephone string `json:"telephone"` // n 座机 + Address string `json:"address"` // n 地址 + Extattr Extattr `json:"extattr"` // n 自定义字段。自定义字段需要先在WEB管理端添加,见扩展属性添加方法,否则忽略未知属性的赋值。 + MainDepartment int `json:"main_department"` // n 主部门 + ToInvite bool `json:"to_invite"` // n 是否邀请该成员使用企业微信(将通过微信服务通知或短信或邮件下发邀请,每天自动下发一次,最多持续3个工作日),默认值为true + ExternalPosition string `json:"external_position"` // n 对外职务,如果设置了该值,则以此作为对外展示的职务,否则以position来展示。长度12个汉字内 + ExternalProfile ExternalProfile `json:"external_profile"` // n 成员对外属性,字段详情见对外属性 +} + +type Extattr struct { + Attrs []Attrs `json:"attrs"` +} + +type ExternalAttr struct { + Type int `json:"type"` + Name string `json:"name"` + Text Text `json:"text,omitempty"` + Web Web `json:"web,omitempty"` + Miniprogram Miniprogram `json:"miniprogram,omitempty"` +} + +type ExternalProfile struct { + ExternalCorpName string `json:"external_corp_name"` + ExternalAttr []ExternalAttr `json:"external_attr"` +} + +type Attrs struct { + Type int `json:"type"` + Name string `json:"name"` + Text Text `json:"text,omitempty"` + Web Web `json:"web,omitempty"` +} + +type Text struct { + Value string `json:"value"` +} + +type Web struct { + URL string `json:"url"` + Title string `json:"title"` +} + +type Miniprogram struct { + Appid string `json:"appid"` + Pagepath string `json:"pagepath"` + Title string `json:"title"` +} + +/*获取部门列表*/ +type GetAllDepartmentList struct { +} diff --git a/platformapi/enterprise_wechat/enterprise_test.go b/platformapi/enterprise_wechat/enterprise_test.go index b71d17e6..0471403a 100644 --- a/platformapi/enterprise_wechat/enterprise_test.go +++ b/platformapi/enterprise_wechat/enterprise_test.go @@ -4,6 +4,7 @@ import ( "fmt" "git.rosy.net.cn/baseapi" "go.uber.org/zap" + "strconv" "testing" ) @@ -16,7 +17,9 @@ func init() { logger, _ := zap.NewDevelopment() sugarLogger = logger.Sugar() baseapi.Init(sugarLogger) - api = New("ww9a156bfa070e1857", "JQsEmSTltHhNgdPIT320YJFphiYmRs-YZa-rCBwplss") + //api = New("ww9a156bfa070e1857", "JQsEmSTltHhNgdPIT320YJFphiYmRs-YZa-rCBwplss") // 小程序 + api = New("ww9a156bfa070e1857", "0jBdCjSmoFiOoHIXyeCK9VbGQ82fVNJZ8uMl6JNN7X4") // 通讯录 + api = New("ww9a156bfa070e1857", "JQsEmSTltHhNgdPIT320YJFphiYmRs-YZa-rCBwplss") // 小程序 //api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu") //token, _ := api.GetAccessToken() //api.accessToken = token.BusinessDataObj.AccessToken @@ -36,5 +39,66 @@ func TestGetToken(t *testing.T) { } func TestAPI_GetDepartmentList(t *testing.T) { - + var aa int = 10004 + fmt.Println(aa) + cc := strconv.Itoa(int(aa)) + bb := string(aa) + fmt.Println(bb) + fmt.Println(cc) + ee := "四川省" + fmt.Println(ee[0:6]) +} + +// 获取所有的部门 +func TestGetAllDepartmentList(t *testing.T) { + data, err := api.GetAllDepartmentList() + fmt.Println(err) + for _, v := range data { + fmt.Println(v.Name) + } +} + +// 创建员工 +func TestCreateStaff(t *testing.T) { + err := api.CreateBoss2JxStaff(&CreateBoos2JXStaffReq{ + Userid: "jx2022524_668511", + Name: "门店老板", + Alias: "", + Mobile: "18981810341", + Department: []int{18}, // 四川省 + Order: nil, + Position: "老板_群主", + Gender: "1", + Email: "", + IsLeaderInDept: []int{1}, + Enable: 0, + AvatarMediaid: "", + Telephone: "", + Address: "", + Extattr: Extattr{}, + MainDepartment: 0, + ToInvite: true, + ExternalPosition: "", + ExternalProfile: ExternalProfile{}, + }) + fmt.Println("err", err) +} + +// 手机账号获取用户信息 +func TestGetUserByMobile(t *testing.T) { + mobile, err := api.GetUserIdByMobile("18981810351") + fmt.Println(err) + fmt.Println(mobile) +} + +// 创建会话群聊 +func TestCreateSession(t *testing.T) { + api = New("ww9a156bfa070e1857", "JQsEmSTltHhNgdPIT320YJFphiYmRs-YZa-rCBwplss") // 小程序 + err := api.CreateAppChat(&CreateAppChatParamReq{ + UserList: []string{"jx2022524_668511", "LiuLei"}, + Name: "test1liulei", + Owner: "LiuLei", + ChatId: "11112", + }) + fmt.Println(err) } diff --git a/platformapi/enterprise_wechat/wechat_client.go b/platformapi/enterprise_wechat/wechat_client.go index b20192b6..e5b5743e 100644 --- a/platformapi/enterprise_wechat/wechat_client.go +++ b/platformapi/enterprise_wechat/wechat_client.go @@ -13,6 +13,7 @@ import ( "time" ) +// 通讯录 func New(corpId, corpSecret string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { @@ -28,9 +29,26 @@ func New(corpId, corpSecret string, config ...*platformapi.APIConfig) *API { } } +// 会话 +func NewMin(corpId, corpSecret string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + + return &API{ + corpId: corpId, + corpSecret: corpSecret, + locker: sync.RWMutex{}, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + // 获取token type EnterpriseToken struct { - PublicCode + ErrCode int `json:"errcode"` // 错误码 + ErrMsg string `json:"errmsg"` // 错误消息 AccessToken string `json:"access_token"` // 权限说明 ExpiresIn int64 `json:"expires_in"` // 过期时间 } @@ -72,19 +90,17 @@ func (a *API) GetAccessToken() (tokenInfo *EnterpriseToken, err error) { // 数据发送 func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) { - bizParams["access_token"] = a.accessToken data, err := json.Marshal(bizParams) // 序列化 if err != nil { return nil, err } - // 全路径请求参数 - fullURL := utils.GenerateGetURL(baseUrl, actionApi, nil) - // 发送请求 sendUrl := func() *http.Request { var request *http.Request if http.MethodPost == method { + // 全路径请求参数 + fullURL := utils.GenerateGetURL(baseUrl, actionApi, map[string]interface{}{"access_token": a.accessToken}) request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data))) } else { request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(baseUrl, actionApi, bizParams), nil) @@ -114,8 +130,9 @@ func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string] return retVal, err } +// 检查token是否应该更新 func (a *API) CheckAccessTokenExpiresIn() { - if a.expiresIn == 0 || a.expiresIn <= time.Now().Unix() { + if a.expiresIn == 0 || a.expiresIn <= time.Now().Unix() || a.accessToken == "" { a.GetAccessToken() } return diff --git a/platformapi/enterprise_wechat/wechat_model.go b/platformapi/enterprise_wechat/wechat_model.go index c5db8ac3..6a6008d2 100644 --- a/platformapi/enterprise_wechat/wechat_model.go +++ b/platformapi/enterprise_wechat/wechat_model.go @@ -10,7 +10,12 @@ const ( WeChatBaseApi = "https://qyapi.weixin.qq.com" // 企业微信基础访问链接 // api接口 - GetToken = "cgi-bin/gettoken" // 获取token + GetToken = "cgi-bin/gettoken" // 获取token + CreateAppChat = "cgi-bin/appchat/create" // 创建会话群聊 + GetAllDepartmentListById = "cgi-bin/department/list" // 获取所有的部门 + CreateBoosToJxStaff = "cgi-bin/user/create" // 将京西老板创建为企业员工 + GetDepartmentUserDetail = "cgi-bin/user/list" // 获取部门用户详细情况 + GetUserByMobileUrl = "cgi-bin/user/getuserid" // 通过手机号获取用户id ) // 注册请求api @@ -24,9 +29,73 @@ type API struct { config *platformapi.APIConfig } -// 公共错误码 -type PublicCode struct { - ErrCode int `json:"errcode"` // 错误码 - ErrMsg string `json:"errmsg"` // 错误消息 - +// 创建群聊 +type CreateAppChatParamReq struct { + UserList []string `json:"userlist"` // 成员列表(至少两个) + Name string `json:"name"` // 群聊名,最多50个utf8字符,超过将截断 + Owner string `json:"owner"` // 群主id + ChatId string `json:"chatid"` // 群聊的唯一标志,不能与已有的群重复 +} + +// 获取所有的部门 +type Department struct { + ID int `json:"id"` // id + Name string `json:"name"` // 名称 + ParentId int `json:"parentid"` // 父部门id + Order int `json:"order"` // 排序 + DepartmentLeader []string `json:"department_leader"` // 部门负责人的UserID;第三方仅通讯录应用可获取 +} +type GetAllDepartmentListRes struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + Department []*Department `json:"department"` +} + +// 错误消息 +type Err struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + ChatId string `json:"chatid"` // 群聊的唯一标志,不能与已有的群重复 +} + +// 获取部门全部用户详细信息 + +type GetEnterpriseStaffInfoRes struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + UserList []*UserList `json:"userlist"` +} + +type UserList struct { + Userid string `json:"userid"` + Name string `json:"name"` + Department []int `json:"department"` + Position string `json:"position"` + Mobile string `json:"mobile"` + Gender string `json:"gender"` + Email string `json:"email"` + Avatar string `json:"avatar"` + Status int `json:"status"` + Enable int `json:"enable"` + IsLeader int `json:"isleader"` + ExtAttr Extattr `json:"extattr"` + HideMobile int `json:"hide_mobile"` + Telephone string `json:"telephone"` + Order []int `json:"order"` + ExternalProfile ExternalProfile `json:"external_profile"` + MainDepartment int `json:"main_department"` + QrCode string `json:"qr_code"` + Alias string `json:"alias"` + IsLeaderInDept []int `json:"is_leader_in_dept"` + Address string `json:"address"` + ThumbAvatar string `json:"thumb_avatar"` + DirectLeader []string `json:"direct_leader"` + BizMail string `json:"biz_mail"` +} + +// 手机号获取用户信息 +type GetUserByMobileRes struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + UserId string `json:"userid"` }