From c4d2e363f4b641d26bc51e3231a5bb3b15a45b6b Mon Sep 17 00:00:00 2001 From: ssfyn Date: Mon, 17 Aug 2026 11:56:20 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E9=A2=84=E7=BA=A6=E4=BC=9A=E8=AE=AE?= =?UTF-8?q?=E9=AB=98=E7=BA=A7=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/README.md | 77 ++++++++- work/meeting/attendee.go | 216 +++++++++++++++++++++++ work/meeting/client.go | 17 ++ work/meeting/customer_url.go | 83 +++++++++ work/meeting/enroll.go | 321 +++++++++++++++++++++++++++++++++++ work/meeting/guest.go | 72 ++++++++ work/meeting/invitee.go | 77 +++++++++ work/meeting/meeting.go | 216 +++++++++++++++++++++++ work/meeting/types.go | 115 +++++++++++++ work/meeting/waitingroom.go | 101 +++++++++++ work/work.go | 6 + 11 files changed, 1300 insertions(+), 1 deletion(-) create mode 100644 work/meeting/attendee.go create mode 100644 work/meeting/client.go create mode 100644 work/meeting/customer_url.go create mode 100644 work/meeting/enroll.go create mode 100644 work/meeting/guest.go create mode 100644 work/meeting/invitee.go create mode 100644 work/meeting/meeting.go create mode 100644 work/meeting/types.go create mode 100644 work/meeting/waitingroom.go diff --git a/work/README.md b/work/README.md index aeaa134f4..a21ea7422 100644 --- a/work/README.md +++ b/work/README.md @@ -2,4 +2,79 @@ [官方文档](https://work.weixin.qq.com/api/doc) -## 快速入门 \ No newline at end of file +## 快速入门 + +## 会议-预约会议高级管理 + +[官方文档](https://developer.work.weixin.qq.com/document/path/98148) + +### 使用示例 + +```go +//初始化 +wc := work.NewWork(&config.Config{ + CorpID: "corp_id", + CorpSecret: "corp_secret", +}) + +//获取会议接口实例 +meetingClient := wc.GetMeeting() + +//创建预约会议 +resp, err := meetingClient.MeetingCreate(&meeting.MeetingCreateRequest{ + AdminUserID: "zhangsan", + Title: "新建会议", + MeetingStart: 1600000000, + MeetingDuration: 3600, + Description: "新建会议描述", + Location: "广州媒体港", + Invitees: &meeting.Invitees{ + UserID: []string{"lisi", "wangwu"}, + }, + Settings: &meeting.Settings{ + Password: "1234", + EnableWaitingRoom: &[]bool{false}[0], + AllowEnterBeforeHost: &[]bool{true}[0], + EnableEnterMute: 1, + }, +}) + +//获取会议详情 +info, err := meetingClient.MeetingGetInfo(&meeting.MeetingGetInfoRequest{ + MeetingID: "XXXXXXXXX", +}) + +//取消预约会议 +err = meetingClient.MeetingCancel(&meeting.MeetingCancelRequest{ + MeetingID: "XXXXXXXXX", +}) +``` + +### 接口列表 + +| 接口 | 方法 | 文档 | +| --- | --- | --- | +| 创建预约会议 | `MeetingCreate` | [98148](https://developer.work.weixin.qq.com/document/path/98148) | +| 修改预约会议 | `MeetingUpdate` | [98154](https://developer.work.weixin.qq.com/document/path/98154) | +| 取消预约会议 | `MeetingCancel` | [98153](https://developer.work.weixin.qq.com/document/path/98153) | +| 获取会议详情 | `MeetingGetInfo` | [98149](https://developer.work.weixin.qq.com/document/path/98149) | +| 获取会议受邀成员列表 | `GetInvitees` | [98160](https://developer.work.weixin.qq.com/document/path/98160) | +| 更新会议受邀成员列表 | `SetInvitees` | [98162](https://developer.work.weixin.qq.com/document/path/98162) | +| 获取成员会议ID列表 | `GetUserMeetingID` | [98714](https://developer.work.weixin.qq.com/document/path/98714) | +| 创建用户专属参会链接 | `CreateCustomerShortURL` | [98818](https://developer.work.weixin.qq.com/document/path/98818) | +| 获取用户专属参会链接 | `GetCustomerShortURL` | [98819](https://developer.work.weixin.qq.com/document/path/98819) | +| 获取实时会中成员列表 | `GetRealtimeAttendeeList` | [98157](https://developer.work.weixin.qq.com/document/path/98157) | +| 获取已参会成员列表 | `GetAttendeeList` | [98156](https://developer.work.weixin.qq.com/document/path/98156) | +| 获取实时等候室成员列表 | `WaitingRoomGetCurrentUserList` | [98163](https://developer.work.weixin.qq.com/document/path/98163) | +| 获取等候室成员记录 | `WaitingRoomGetUserList` | [98164](https://developer.work.weixin.qq.com/document/path/98164) | +| 获取成员设备是否入会 | `CheckDeviceInMeeting` | [98165](https://developer.work.weixin.qq.com/document/path/98165) | +| 获取会议嘉宾列表 | `GetGuests` | [99039](https://developer.work.weixin.qq.com/document/path/99039) | +| 更新会议嘉宾列表 | `SetGuests` | [99040](https://developer.work.weixin.qq.com/document/path/99040) | +| 获取会议健康度 | `GetQuality` | [98821](https://developer.work.weixin.qq.com/document/path/98821) | +| 修改会议报名配置 | `EnrollSetConfig` | [98797](https://developer.work.weixin.qq.com/document/path/98797) | +| 获取会议报名配置 | `EnrollGetConfig` | [98800](https://developer.work.weixin.qq.com/document/path/98800) | +| 获取会议成员报名ID | `EnrollQueryByTmpOpenID` | [98794](https://developer.work.weixin.qq.com/document/path/98794) | +| 获取会议报名信息 | `EnrollList` | [98810](https://developer.work.weixin.qq.com/document/path/98810) | +| 审批会议报名信息 | `EnrollApprove` | [98807](https://developer.work.weixin.qq.com/document/path/98807) | +| 导入会议报名信息 | `EnrollImport` | [98816](https://developer.work.weixin.qq.com/document/path/98816) | +| 删除会议报名信息 | `EnrollDelete` | [98817](https://developer.work.weixin.qq.com/document/path/98817) | \ No newline at end of file diff --git a/work/meeting/attendee.go b/work/meeting/attendee.go new file mode 100644 index 000000000..b53b9868e --- /dev/null +++ b/work/meeting/attendee.go @@ -0,0 +1,216 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingGetRealtimeAttendeeListURL 获取实时会中成员列表 + meetingGetRealtimeAttendeeListURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_realtime_attendee_list?access_token=%s" + // meetingGetAttendeeListURL 获取已参会成员列表 + meetingGetAttendeeListURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_attendee_list?access_token=%s" + // meetingCheckDeviceInMeetingURL 获取成员设备是否入会 + meetingCheckDeviceInMeetingURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/check_device_in_meeting?access_token=%s" + // meetingGetQualityURL 获取会议健康度 + meetingGetQualityURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_quality?access_token=%s" +) + +type ( + // GetRealtimeAttendeeListRequest 获取实时会中成员列表请求 + GetRealtimeAttendeeListRequest struct { + MeetingID string `json:"meetingid"` + SubMeetingID string `json:"sub_meetingid,omitempty"` + Cursor string `json:"cursor,omitempty"` + Limit uint32 `json:"limit,omitempty"` + } + + // GetRealtimeAttendeeListResponse 获取实时会中成员列表响应 + GetRealtimeAttendeeListResponse struct { + util.CommonError + Status string `json:"status"` + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + Attendees []*RealtimeAttendee `json:"attendees"` + } + + // RealtimeAttendee 实时会中成员 + RealtimeAttendee struct { + UserID string `json:"userid"` + TmpOpenID string `json:"tmp_openid"` + JoinTime string `json:"join_time"` + InstanceID uint32 `json:"instance_id"` + Role uint32 `json:"role"` + JoinType uint32 `json:"join_type"` + AudioState bool `json:"audio_state"` + VideoState bool `json:"video_state"` + ScreenSharedState bool `json:"screen_shared_state"` + } + + // GetAttendeeListRequest 获取已参会成员列表请求 + GetAttendeeListRequest struct { + MeetingID string `json:"meetingid"` + SubMeetingID string `json:"sub_meetingid,omitempty"` + StartTime uint32 `json:"start_time,omitempty"` + EndTime uint32 `json:"end_time,omitempty"` + Cursor string `json:"cursor,omitempty"` + Limit uint32 `json:"limit,omitempty"` + } + + // GetAttendeeListResponse 获取已参会成员列表响应 + GetAttendeeListResponse struct { + util.CommonError + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + Attendees []*AttendedMember `json:"attendees"` + } + + // AttendedMember 已参会成员 + AttendedMember struct { + UserID string `json:"userid"` + TmpOpenID string `json:"tmp_openid"` + JoinTime string `json:"join_time"` + QuitTime string `json:"quit_time"` + InstanceID uint32 `json:"instance_id"` + Role uint32 `json:"role"` + WebinarRole uint32 `json:"webinar_role"` + JoinType uint32 `json:"join_type"` + Net string `json:"net"` + AudioState bool `json:"audio_state"` + VideoState bool `json:"video_state"` + ScreenSharedState bool `json:"screen_shared_state"` + CustomerData string `json:"customer_data"` + } + + // CheckDeviceInMeetingRequest 获取成员设备是否入会请求 + CheckDeviceInMeetingRequest struct { + UserID string `json:"userid"` + InstanceIDList []uint32 `json:"instance_id_list,omitempty"` + MeetingIDList []string `json:"meetingid_list"` + } + + // CheckDeviceInMeetingResponse 获取成员设备是否入会响应 + CheckDeviceInMeetingResponse struct { + util.CommonError + ResultList []*DeviceMeetingResult `json:"result_list"` + } + + // DeviceMeetingResult 设备会议结果 + DeviceMeetingResult struct { + MeetingID string `json:"meetingid"` + InstanceID uint32 `json:"instance_id"` + } + + // GetQualityRequest 获取会议健康度请求 + GetQualityRequest struct { + MeetingID string `json:"meetingid"` + SubMeetingID string `json:"sub_meetingid,omitempty"` + StartTime uint32 `json:"start_time,omitempty"` + Cursor string `json:"cursor,omitempty"` + Limit uint32 `json:"limit,omitempty"` + } + + // GetQualityResponse 获取会议健康度响应 + GetQualityResponse struct { + util.CommonError + Quality int32 `json:"quality"` + AudioQuality int32 `json:"audio_quality"` + VideoQuality int32 `json:"video_quality"` + ScreenShareQuality int32 `json:"screen_share_quality"` + NetworkQuality int32 `json:"network_quality"` + Problems []string `json:"problems"` + Attendees []*QualityAttendee `json:"attendees"` + NextCursor string `json:"next_cursor"` + HasMore bool `json:"has_more"` + } + + // QualityAttendee 参会人员健康度 + QualityAttendee struct { + UserID string `json:"userid"` + TmpOpenID string `json:"tmp_openid"` + InstanceID uint32 `json:"instance_id"` + Quality int32 `json:"quality"` + AudioQuality int32 `json:"audio_quality"` + VideoQuality int32 `json:"video_quality"` + ScreenShareQuality int32 `json:"screen_share_quality"` + NetworkQuality int32 `json:"network_quality"` + Problems []string `json:"problems"` + } +) + +// GetRealtimeAttendeeList 获取实时会中成员列表 +// see https://developer.work.weixin.qq.com/document/path/98157 +func (r *Client) GetRealtimeAttendeeList(req *GetRealtimeAttendeeListRequest) (*GetRealtimeAttendeeListResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetRealtimeAttendeeListURL, accessToken), req); err != nil { + return nil, err + } + result := &GetRealtimeAttendeeListResponse{} + err = util.DecodeWithError(response, result, "GetRealtimeAttendeeList") + return result, err +} + +// GetAttendeeList 获取已参会成员列表 +// see https://developer.work.weixin.qq.com/document/path/98156 +func (r *Client) GetAttendeeList(req *GetAttendeeListRequest) (*GetAttendeeListResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetAttendeeListURL, accessToken), req); err != nil { + return nil, err + } + result := &GetAttendeeListResponse{} + err = util.DecodeWithError(response, result, "GetAttendeeList") + return result, err +} + +// CheckDeviceInMeeting 获取成员设备是否入会 +// see https://developer.work.weixin.qq.com/document/path/98165 +func (r *Client) CheckDeviceInMeeting(req *CheckDeviceInMeetingRequest) (*CheckDeviceInMeetingResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingCheckDeviceInMeetingURL, accessToken), req); err != nil { + return nil, err + } + result := &CheckDeviceInMeetingResponse{} + err = util.DecodeWithError(response, result, "CheckDeviceInMeeting") + return result, err +} + +// GetQuality 获取会议健康度 +// see https://developer.work.weixin.qq.com/document/path/98821 +func (r *Client) GetQuality(req *GetQualityRequest) (*GetQualityResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetQualityURL, accessToken), req); err != nil { + return nil, err + } + result := &GetQualityResponse{} + err = util.DecodeWithError(response, result, "GetQuality") + return result, err +} diff --git a/work/meeting/client.go b/work/meeting/client.go new file mode 100644 index 000000000..8e14a41d0 --- /dev/null +++ b/work/meeting/client.go @@ -0,0 +1,17 @@ +package meeting + +import ( + "github.com/silenceper/wechat/v2/work/context" +) + +// Client 会议接口实例 +type Client struct { + *context.Context +} + +// NewClient 初始化实例 +func NewClient(ctx *context.Context) *Client { + return &Client{ + ctx, + } +} diff --git a/work/meeting/customer_url.go b/work/meeting/customer_url.go new file mode 100644 index 000000000..4435d03b8 --- /dev/null +++ b/work/meeting/customer_url.go @@ -0,0 +1,83 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingCreateCustomerShortURLURL 创建用户专属参会链接 + meetingCreateCustomerShortURLURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/create_customer_short_url?access_token=%s" + // meetingGetCustomerShortURLURL 获取用户专属参会链接 + meetingGetCustomerShortURLURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_customer_short_url?access_token=%s" +) + +type ( + // CreateCustomerShortURLRequest 创建用户专属参会链接请求 + CreateCustomerShortURLRequest struct { + MeetingID string `json:"meetingid"` + CustomerData string `json:"customer_data"` + } + + // CreateCustomerShortURLResponse 创建用户专属参会链接响应 + CreateCustomerShortURLResponse struct { + util.CommonError + MeetingShortURLCustomerData *CustomerShortURLData `json:"meeting_short_url_customer_data"` + } + + // GetCustomerShortURLRequest 获取用户专属参会链接请求 + GetCustomerShortURLRequest struct { + MeetingID string `json:"meetingid"` + } + + // GetCustomerShortURLResponse 获取用户专属参会链接响应 + GetCustomerShortURLResponse struct { + util.CommonError + MeetingShortURLCustomerDataList []*CustomerShortURLData `json:"meeting_short_url_customer_data_list"` + } + + // CustomerShortURLData 用户专属参会链接数据 + CustomerShortURLData struct { + CustomerData string `json:"customer_data"` + MeetingShortURL string `json:"meeting_short_url"` + } +) + +// CreateCustomerShortURL 创建用户专属参会链接 +// see https://developer.work.weixin.qq.com/document/path/98818 +func (r *Client) CreateCustomerShortURL(req *CreateCustomerShortURLRequest) (*CreateCustomerShortURLResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingCreateCustomerShortURLURL, accessToken), req); err != nil { + return nil, err + } + result := &CreateCustomerShortURLResponse{} + err = util.DecodeWithError(response, result, "CreateCustomerShortURL") + return result, err +} + +// GetCustomerShortURL 获取用户专属参会链接 +// see https://developer.work.weixin.qq.com/document/path/98819 +func (r *Client) GetCustomerShortURL(req *GetCustomerShortURLRequest) (*GetCustomerShortURLResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetCustomerShortURLURL, accessToken), req); err != nil { + return nil, err + } + result := &GetCustomerShortURLResponse{} + err = util.DecodeWithError(response, result, "GetCustomerShortURL") + return result, err +} diff --git a/work/meeting/enroll.go b/work/meeting/enroll.go new file mode 100644 index 000000000..2e7e919d9 --- /dev/null +++ b/work/meeting/enroll.go @@ -0,0 +1,321 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingEnrollSetConfigURL 修改会议报名配置 + meetingEnrollSetConfigURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/set_config?access_token=%s" + // meetingEnrollGetConfigURL 获取会议报名配置 + meetingEnrollGetConfigURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/get_config?access_token=%s" + // meetingEnrollQueryByTmpOpenIDURL 获取会议成员报名ID + meetingEnrollQueryByTmpOpenIDURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/query_by_tmp_openid?access_token=%s" + // meetingEnrollListURL 获取会议报名信息 + meetingEnrollListURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/list?access_token=%s" + // meetingEnrollApproveURL 审批会议报名信息 + meetingEnrollApproveURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/approve?access_token=%s" + // meetingEnrollImportURL 导入会议报名信息 + meetingEnrollImportURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/import?access_token=%s" + // meetingEnrollDeleteURL 删除会议报名信息 + meetingEnrollDeleteURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/enroll/delete?access_token=%s" +) + +type ( + // EnrollSetConfigRequest 修改会议报名配置请求 + EnrollSetConfigRequest struct { + MeetingID string `json:"meetingid"` + ApproveType int32 `json:"approve_type,omitempty"` + IsCollectQuestion int32 `json:"is_collect_question,omitempty"` + QuestionList []*EnrollQuestion `json:"question_list,omitempty"` + NoRegistrationNeededForStaff *bool `json:"no_registration_needed_for_staff,omitempty"` + } + + // EnrollQuestion 报名问题 + EnrollQuestion struct { + IsRequired int32 `json:"is_required,omitempty"` + OptionList []*EnrollOption `json:"option_list,omitempty"` + QuestionTitle string `json:"question_title,omitempty"` + QuestionType int32 `json:"question_type,omitempty"` + SpecialType int32 `json:"special_type,omitempty"` + } + + // EnrollOption 报名问题选项 + EnrollOption struct { + Content string `json:"content"` + } + + // EnrollSetConfigResponse 修改会议报名配置响应 + EnrollSetConfigResponse struct { + util.CommonError + QuestionCount int32 `json:"question_count"` + } + + // EnrollGetConfigRequest 获取会议报名配置请求 + EnrollGetConfigRequest struct { + MeetingID string `json:"meetingid"` + } + + // EnrollGetConfigResponse 获取会议报名配置响应 + EnrollGetConfigResponse struct { + util.CommonError + ApproveType int32 `json:"approve_type"` + IsCollectQuestion int32 `json:"is_collect_question"` + NoRegistrationNeededForStaff bool `json:"no_registration_needed_for_staff"` + QuestionList []*EnrollQuestion `json:"question_list"` + } + + // EnrollQueryByTmpOpenIDRequest 获取会议成员报名ID请求 + EnrollQueryByTmpOpenIDRequest struct { + MeetingID string `json:"meetingid"` + SortingRules int32 `json:"sorting_rules,omitempty"` + TmpOpenIDList []string `json:"tmp_openid_list"` + } + + // EnrollQueryByTmpOpenIDResponse 获取会议成员报名ID响应 + EnrollQueryByTmpOpenIDResponse struct { + util.CommonError + EnrollIDList []*EnrollIDItem `json:"enroll_id_list"` + } + + // EnrollIDItem 报名ID项 + EnrollIDItem struct { + TmpOpenID string `json:"tmp_openid"` + EnrollID string `json:"enroll_id"` + } + + // EnrollListRequest 获取会议报名信息请求 + EnrollListRequest struct { + MeetingID string `json:"meetingid"` + Status int32 `json:"status,omitempty"` + Cursor string `json:"cursor,omitempty"` + Limit int32 `json:"limit,omitempty"` + } + + // EnrollListResponse 获取会议报名信息响应 + EnrollListResponse struct { + util.CommonError + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + EnrollList []*EnrollInfo `json:"enroll_list"` + } + + // EnrollInfo 报名信息 + EnrollInfo struct { + EnrollID string `json:"enroll_id"` + EnrollTime string `json:"enroll_time"` + EnrollSourceType int32 `json:"enroll_source_type"` + NickName string `json:"nick_name"` + Status int32 `json:"status"` + UserID string `json:"userid"` + TmpOpenID string `json:"tmp_openid"` + EnrollCode string `json:"enroll_code"` + AnswerList []*EnrollAnswer `json:"answer_list"` + } + + // EnrollAnswer 报名答题 + EnrollAnswer struct { + AnswerContent []string `json:"answer_content"` + IsRequired int32 `json:"is_required"` + QuestionNum int32 `json:"question_num"` + QuestionTitle string `json:"question_title"` + QuestionType int32 `json:"question_type"` + SpecialType int32 `json:"special_type"` + } + + // EnrollApproveRequest 审批会议报名信息请求 + EnrollApproveRequest struct { + MeetingID string `json:"meetingid"` + Action int32 `json:"action"` + EnrollIDList []string `json:"enroll_id_list"` + } + + // EnrollApproveResponse 审批会议报名信息响应 + EnrollApproveResponse struct { + util.CommonError + HandledCount int32 `json:"handled_count"` + } + + // EnrollImportRequest 导入会议报名信息请求 + EnrollImportRequest struct { + MeetingID string `json:"meetingid"` + EnrollList []*EnrollRequest `json:"enroll_list"` + } + + // EnrollRequest 报名成员请求 + EnrollRequest struct { + UserID string `json:"userid,omitempty"` + Area string `json:"area,omitempty"` + PhoneNumber string `json:"phone_number,omitempty"` + NickName string `json:"nick_name,omitempty"` + } + + // EnrollImportResponse 导入会议报名信息响应 + EnrollImportResponse struct { + util.CommonError + TotalCount uint32 `json:"total_count"` + EnrollList []*EnrollResponse `json:"enroll_list"` + } + + // EnrollResponse 报名成员响应 + EnrollResponse struct { + EnrollID string `json:"enroll_id"` + UserID string `json:"userid"` + Area string `json:"area"` + PhoneNumber string `json:"phone_number"` + NickName string `json:"nick_name"` + EnrollCode string `json:"enroll_code"` + } + + // EnrollDeleteRequest 删除会议报名信息请求 + EnrollDeleteRequest struct { + MeetingID string `json:"meetingid"` + EnrollIDList []*EnrollDeleteID `json:"enroll_id_list"` + } + + // EnrollDeleteID 报名ID + EnrollDeleteID struct { + EnrollID string `json:"enroll_id"` + } + + // EnrollDeleteResponse 删除会议报名信息响应 + EnrollDeleteResponse struct { + util.CommonError + TotalCount uint32 `json:"total_count"` + } +) + +// EnrollSetConfig 修改会议报名配置 +// see https://developer.work.weixin.qq.com/document/path/98797 +func (r *Client) EnrollSetConfig(req *EnrollSetConfigRequest) (*EnrollSetConfigResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollSetConfigURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollSetConfigResponse{} + err = util.DecodeWithError(response, result, "EnrollSetConfig") + return result, err +} + +// EnrollGetConfig 获取会议报名配置 +// see https://developer.work.weixin.qq.com/document/path/98800 +func (r *Client) EnrollGetConfig(req *EnrollGetConfigRequest) (*EnrollGetConfigResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollGetConfigURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollGetConfigResponse{} + err = util.DecodeWithError(response, result, "EnrollGetConfig") + return result, err +} + +// EnrollQueryByTmpOpenID 获取会议成员报名ID +// see https://developer.work.weixin.qq.com/document/path/98794 +func (r *Client) EnrollQueryByTmpOpenID(req *EnrollQueryByTmpOpenIDRequest) (*EnrollQueryByTmpOpenIDResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollQueryByTmpOpenIDURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollQueryByTmpOpenIDResponse{} + err = util.DecodeWithError(response, result, "EnrollQueryByTmpOpenID") + return result, err +} + +// EnrollList 获取会议报名信息 +// see https://developer.work.weixin.qq.com/document/path/98810 +func (r *Client) EnrollList(req *EnrollListRequest) (*EnrollListResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollListURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollListResponse{} + err = util.DecodeWithError(response, result, "EnrollList") + return result, err +} + +// EnrollApprove 审批会议报名信息 +// see https://developer.work.weixin.qq.com/document/path/98807 +func (r *Client) EnrollApprove(req *EnrollApproveRequest) (*EnrollApproveResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollApproveURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollApproveResponse{} + err = util.DecodeWithError(response, result, "EnrollApprove") + return result, err +} + +// EnrollImport 导入会议报名信息 +// see https://developer.work.weixin.qq.com/document/path/98816 +func (r *Client) EnrollImport(req *EnrollImportRequest) (*EnrollImportResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollImportURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollImportResponse{} + err = util.DecodeWithError(response, result, "EnrollImport") + return result, err +} + +// EnrollDelete 删除会议报名信息 +// see https://developer.work.weixin.qq.com/document/path/98817 +func (r *Client) EnrollDelete(req *EnrollDeleteRequest) (*EnrollDeleteResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingEnrollDeleteURL, accessToken), req); err != nil { + return nil, err + } + result := &EnrollDeleteResponse{} + err = util.DecodeWithError(response, result, "EnrollDelete") + return result, err +} diff --git a/work/meeting/guest.go b/work/meeting/guest.go new file mode 100644 index 000000000..d2f58cb22 --- /dev/null +++ b/work/meeting/guest.go @@ -0,0 +1,72 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingGetGuestsURL 获取会议嘉宾列表 + meetingGetGuestsURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_guests?access_token=%s" + // meetingSetGuestsURL 更新会议嘉宾列表 + meetingSetGuestsURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/set_guests?access_token=%s" +) + +type ( + // GetGuestsRequest 获取会议嘉宾列表请求 + GetGuestsRequest struct { + MeetingID string `json:"meetingid"` + } + + // GetGuestsResponse 获取会议嘉宾列表响应 + GetGuestsResponse struct { + util.CommonError + MeetingID string `json:"meetingid"` + MeetingCode string `json:"meeting_code"` + Title string `json:"title"` + Guests []*Guest `json:"guests"` + } + + // SetGuestsRequest 更新会议嘉宾列表请求 + SetGuestsRequest struct { + MeetingID string `json:"meetingid"` + Guests []*Guest `json:"guests"` + } +) + +// GetGuests 获取会议嘉宾列表 +// see https://developer.work.weixin.qq.com/document/path/99039 +func (r *Client) GetGuests(req *GetGuestsRequest) (*GetGuestsResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetGuestsURL, accessToken), req); err != nil { + return nil, err + } + result := &GetGuestsResponse{} + err = util.DecodeWithError(response, result, "GetGuests") + return result, err +} + +// SetGuests 更新会议嘉宾列表 +// see https://developer.work.weixin.qq.com/document/path/99040 +func (r *Client) SetGuests(req *SetGuestsRequest) error { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingSetGuestsURL, accessToken), req); err != nil { + return err + } + return util.DecodeWithCommonError(response, "SetGuests") +} diff --git a/work/meeting/invitee.go b/work/meeting/invitee.go new file mode 100644 index 000000000..883492e2e --- /dev/null +++ b/work/meeting/invitee.go @@ -0,0 +1,77 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingGetInviteesURL 获取会议受邀成员列表 + meetingGetInviteesURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_invitees?access_token=%s" + // meetingSetInviteesURL 更新会议受邀成员列表 + meetingSetInviteesURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/set_invitees?access_token=%s" +) + +type ( + // GetInviteesRequest 获取会议受邀成员列表请求 + GetInviteesRequest struct { + MeetingID string `json:"meetingid"` + Cursor string `json:"cursor,omitempty"` + } + + // GetInviteesResponse 获取会议受邀成员列表响应 + GetInviteesResponse struct { + util.CommonError + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + Invitees []*Invitee `json:"invitees"` + } + + // Invitee 受邀成员 + Invitee struct { + UserID string `json:"userid"` + } + + // SetInviteesRequest 更新会议受邀成员列表请求 + SetInviteesRequest struct { + MeetingID string `json:"meetingid"` + Invitees []*Invitee `json:"invitees"` + } +) + +// GetInvitees 获取会议受邀成员列表 +// see https://developer.work.weixin.qq.com/document/path/98160 +func (r *Client) GetInvitees(req *GetInviteesRequest) (*GetInviteesResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetInviteesURL, accessToken), req); err != nil { + return nil, err + } + result := &GetInviteesResponse{} + err = util.DecodeWithError(response, result, "GetInvitees") + return result, err +} + +// SetInvitees 更新会议受邀成员列表 +// see https://developer.work.weixin.qq.com/document/path/98162 +func (r *Client) SetInvitees(req *SetInviteesRequest) error { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingSetInviteesURL, accessToken), req); err != nil { + return err + } + return util.DecodeWithCommonError(response, "SetInvitees") +} diff --git a/work/meeting/meeting.go b/work/meeting/meeting.go new file mode 100644 index 000000000..755d8d54d --- /dev/null +++ b/work/meeting/meeting.go @@ -0,0 +1,216 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingCreateURL 创建预约会议 + meetingCreateURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/create?access_token=%s" + // meetingUpdateURL 修改预约会议 + meetingUpdateURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/update?access_token=%s" + // meetingCancelURL 取消预约会议 + meetingCancelURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/cancel?access_token=%s" + // meetingGetInfoURL 获取会议详情 + meetingGetInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_info?access_token=%s" + // meetingGetUserMeetingIDURL 获取成员会议ID列表 + meetingGetUserMeetingIDURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/get_user_meetingid?access_token=%s" +) + +type ( + // MeetingCreateRequest 创建预约会议请求 + MeetingCreateRequest struct { + AdminUserID string `json:"admin_userid"` + Title string `json:"title"` + MeetingStart uint32 `json:"meeting_start,omitempty"` + MeetingDuration uint32 `json:"meeting_duration,omitempty"` + Description string `json:"description,omitempty"` + Location string `json:"location,omitempty"` + AgentID uint32 `json:"agentid,omitempty"` + Invitees *Invitees `json:"invitees,omitempty"` + Guests []*Guest `json:"guests,omitempty"` + Settings *Settings `json:"settings,omitempty"` + CalID string `json:"cal_id,omitempty"` + Reminders *Reminders `json:"reminders,omitempty"` + } + + // MeetingCreateResponse 创建预约会议响应 + MeetingCreateResponse struct { + util.CommonError + MeetingID string `json:"meetingid"` + ExcessUsers []string `json:"excess_users"` + MeetingCode string `json:"meeting_code"` + MeetingLink string `json:"meeting_link"` + } + + // MeetingUpdateRequest 修改预约会议请求 + MeetingUpdateRequest struct { + MeetingID string `json:"meetingid"` + Title string `json:"title,omitempty"` + MeetingStart uint32 `json:"meeting_start,omitempty"` + MeetingDuration uint32 `json:"meeting_duration,omitempty"` + Description string `json:"description,omitempty"` + Location string `json:"location,omitempty"` + Invitees *Invitees `json:"invitees,omitempty"` + Settings *Settings `json:"settings,omitempty"` + CalID string `json:"cal_id,omitempty"` + Reminders *Reminders `json:"reminders,omitempty"` + } + + // MeetingUpdateResponse 修改预约会议响应 + MeetingUpdateResponse struct { + util.CommonError + ExcessUsers []string `json:"excess_users"` + } + + // MeetingCancelRequest 取消预约会议请求 + MeetingCancelRequest struct { + MeetingID string `json:"meetingid"` + SubMeetingID string `json:"sub_meetingid,omitempty"` + } + + // MeetingGetInfoRequest 获取会议详情请求 + MeetingGetInfoRequest struct { + MeetingID string `json:"meetingid,omitempty"` + MeetingCode string `json:"meeting_code,omitempty"` + SubMeetingID string `json:"sub_meetingid,omitempty"` + } + + // MeetingGetInfoResponse 获取会议详情响应 + MeetingGetInfoResponse struct { + util.CommonError + AdminUserID string `json:"admin_userid"` + Title string `json:"title"` + MeetingStart uint32 `json:"meeting_start"` + MeetingDuration uint32 `json:"meeting_duration"` + Description string `json:"description"` + Location string `json:"location"` + MainDepartment uint32 `json:"main_department"` + Status uint32 `json:"status"` + MeetingType uint32 `json:"meeting_type"` + Attendees *Attendees `json:"attendees"` + Guests []*Guest `json:"guests"` + Settings *Settings `json:"settings"` + CalID string `json:"cal_id"` + Reminders *Reminders `json:"reminders"` + MeetingCode string `json:"meeting_code"` + MeetingLink string `json:"meeting_link"` + HasVote bool `json:"has_vote"` + SubMeetings []*SubMeeting `json:"sub_meetings"` + HasMoreSubMeeting uint32 `json:"has_more_sub_meeting"` + RemainSubMeetings uint32 `json:"remain_sub_meetings"` + CurrentSubMeetingID string `json:"current_sub_meetingid"` + SubRepeatList []*SubRepeatInfo `json:"sub_repeat_list"` + } + + // GetUserMeetingIDRequest 获取成员会议ID列表请求 + GetUserMeetingIDRequest struct { + UserID string `json:"userid"` + Cursor string `json:"cursor,omitempty"` + Limit uint32 `json:"limit,omitempty"` + BeginTime uint32 `json:"begin_time,omitempty"` + EndTime uint32 `json:"end_time,omitempty"` + } + + // GetUserMeetingIDResponse 获取成员会议ID列表响应 + GetUserMeetingIDResponse struct { + util.CommonError + NextCursor string `json:"next_cursor"` + MeetingIDList []string `json:"meetingid_list"` + } +) + +// MeetingCreate 创建预约会议 +// see https://developer.work.weixin.qq.com/document/path/98148 +func (r *Client) MeetingCreate(req *MeetingCreateRequest) (*MeetingCreateResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingCreateURL, accessToken), req); err != nil { + return nil, err + } + result := &MeetingCreateResponse{} + err = util.DecodeWithError(response, result, "MeetingCreate") + return result, err +} + +// MeetingUpdate 修改预约会议 +// see https://developer.work.weixin.qq.com/document/path/98154 +func (r *Client) MeetingUpdate(req *MeetingUpdateRequest) (*MeetingUpdateResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingUpdateURL, accessToken), req); err != nil { + return nil, err + } + result := &MeetingUpdateResponse{} + err = util.DecodeWithError(response, result, "MeetingUpdate") + return result, err +} + +// MeetingCancel 取消预约会议 +// see https://developer.work.weixin.qq.com/document/path/98153 +func (r *Client) MeetingCancel(req *MeetingCancelRequest) error { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingCancelURL, accessToken), req); err != nil { + return err + } + return util.DecodeWithCommonError(response, "MeetingCancel") +} + +// MeetingGetInfo 获取会议详情 +// see https://developer.work.weixin.qq.com/document/path/98149 +func (r *Client) MeetingGetInfo(req *MeetingGetInfoRequest) (*MeetingGetInfoResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetInfoURL, accessToken), req); err != nil { + return nil, err + } + result := &MeetingGetInfoResponse{} + err = util.DecodeWithError(response, result, "MeetingGetInfo") + return result, err +} + +// GetUserMeetingID 获取成员会议ID列表 +// see https://developer.work.weixin.qq.com/document/path/98714 +func (r *Client) GetUserMeetingID(req *GetUserMeetingIDRequest) (*GetUserMeetingIDResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingGetUserMeetingIDURL, accessToken), req); err != nil { + return nil, err + } + result := &GetUserMeetingIDResponse{} + err = util.DecodeWithError(response, result, "GetUserMeetingID") + return result, err +} diff --git a/work/meeting/types.go b/work/meeting/types.go new file mode 100644 index 000000000..14808b231 --- /dev/null +++ b/work/meeting/types.go @@ -0,0 +1,115 @@ +package meeting + +// Invitees 邀请参与会议的成员 +type Invitees struct { + UserID []string `json:"userid"` +} + +// Guest 会议嘉宾 +type Guest struct { + Area string `json:"area"` + PhoneNumber string `json:"phone_number"` + GuestName string `json:"guest_name,omitempty"` +} + +// Hosts 会议主持人列表 +type Hosts struct { + UserID []string `json:"userid"` +} + +// RingUsers 指定响铃的成员列表 +type RingUsers struct { + UserID []string `json:"userid"` +} + +// Settings 会议配置 +type Settings struct { + Password string `json:"password,omitempty"` + EnableWaitingRoom *bool `json:"enable_waiting_room,omitempty"` + AllowEnterBeforeHost *bool `json:"allow_enter_before_host,omitempty"` + EnableEnterMute uint32 `json:"enable_enter_mute,omitempty"` + AllowUnmuteSelf *bool `json:"allow_unmute_self,omitempty"` + MuteAll *bool `json:"mute_all,omitempty"` + AllowExternalUser *bool `json:"allow_external_user,omitempty"` + EnableScreenWatermark *bool `json:"enable_screen_watermark,omitempty"` + WatermarkType uint32 `json:"watermark_type,omitempty"` + AutoRecordType string `json:"auto_record_type,omitempty"` + AttendeeJoinAutoRecord *bool `json:"attendee_join_auto_record,omitempty"` + EnableHostPauseAutoRecord *bool `json:"enable_host_pause_auto_record,omitempty"` + EnableInterpreter *bool `json:"enable_interpreter,omitempty"` + EnableEnroll *bool `json:"enable_enroll,omitempty"` + EnableHostKey *bool `json:"enable_host_key,omitempty"` + HostKey string `json:"host_key,omitempty"` + Hosts *Hosts `json:"hosts,omitempty"` + RemindScope uint32 `json:"remind_scope,omitempty"` + RingUsers *RingUsers `json:"ring_users,omitempty"` + // 以下字段仅在获取会议详情响应中返回 + NeedPassword *bool `json:"need_password,omitempty"` + EnableEnterMuteType uint32 `json:"enable_enter_mute_type,omitempty"` + EnableDocUploadPermission *bool `json:"enable_doc_upload_permission,omitempty"` + CurrentHosts *Hosts `json:"current_hosts,omitempty"` + CoHosts *Hosts `json:"co_hosts,omitempty"` +} + +// Reminders 周期性会议配置 +type Reminders struct { + IsRepeat uint32 `json:"is_repeat,omitempty"` + RepeatType uint32 `json:"repeat_type,omitempty"` + IsCustomRepeat uint32 `json:"is_custom_repeat,omitempty"` + RepeatUntilType uint32 `json:"repeat_until_type,omitempty"` + RepeatUntilCount uint32 `json:"repeat_until_count,omitempty"` + RepeatUntil uint32 `json:"repeat_until,omitempty"` + RepeatInterval uint32 `json:"repeat_interval,omitempty"` + RepeatDayOfWeek []uint32 `json:"repeat_day_of_week,omitempty"` + RepeatDayOfMonth []uint32 `json:"repeat_day_of_month,omitempty"` + RemindBefore []uint32 `json:"remind_before,omitempty"` +} + +// Attendees 会议成员 +type Attendees struct { + Member []*MeetingMember `json:"member"` + TmpExternalUser []*TmpExternalUser `json:"tmp_external_user"` +} + +// MeetingMember 企业内部成员 +type MeetingMember struct { + UserID string `json:"userid"` + Status uint32 `json:"status"` + FirstJoinTime uint32 `json:"first_join_time"` + LastQuitTime uint32 `json:"last_quit_time"` + TotalJoinCount uint32 `json:"total_join_count"` + CumulativeTime uint32 `json:"cumulative_time"` +} + +// TmpExternalUser 会中参会的外部联系人 +type TmpExternalUser struct { + TmpExternalUserID string `json:"tmp_external_userid"` + Status uint32 `json:"status"` + FirstJoinTime uint32 `json:"first_join_time"` + LastQuitTime uint32 `json:"last_quit_time"` + TotalJoinCount uint32 `json:"total_join_count"` + CumulativeTime uint32 `json:"cumulative_time"` +} + +// SubMeeting 周期性子会议 +type SubMeeting struct { + SubMeetingID string `json:"sub_meetingid"` + Status uint32 `json:"status"` + StartTime uint32 `json:"start_time"` + EndTime uint32 `json:"end_time"` + Title string `json:"title"` + RepeatID string `json:"repeat_id"` +} + +// SubRepeatInfo 周期性会议分段信息 +type SubRepeatInfo struct { + RepeatID string `json:"repeat_id"` + RepeatType uint32 `json:"repeat_type"` + IsCustomRepeat uint32 `json:"is_custom_repeat"` + RepeatInterval uint32 `json:"repeat_interval"` + RepeatDayOfWeek []uint32 `json:"repeat_day_of_week"` + RepeatDayOfMonth []uint32 `json:"repeat_day_of_month"` + RepeatUntilType uint32 `json:"repeat_until_type"` + RepeatUntilCount uint32 `json:"repeat_until_count"` + RepeatUntil uint32 `json:"repeat_until"` +} diff --git a/work/meeting/waitingroom.go b/work/meeting/waitingroom.go new file mode 100644 index 000000000..999af26be --- /dev/null +++ b/work/meeting/waitingroom.go @@ -0,0 +1,101 @@ +package meeting + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // meetingWaitingRoomGetCurrentUserListURL 获取实时等候室成员列表 + meetingWaitingRoomGetCurrentUserListURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/waitingroom/get_current_user_list?access_token=%s" + // meetingWaitingRoomGetUserListURL 获取等候室成员记录 + meetingWaitingRoomGetUserListURL = "https://qyapi.weixin.qq.com/cgi-bin/meeting/waitingroom/get_user_list?access_token=%s" +) + +type ( + // WaitingRoomGetCurrentUserListRequest 获取实时等候室成员列表请求 + WaitingRoomGetCurrentUserListRequest struct { + MeetingID string `json:"meetingid"` + Limit uint32 `json:"limit,omitempty"` + Cursor string `json:"cursor,omitempty"` + } + + // WaitingRoomGetCurrentUserListResponse 获取实时等候室成员列表响应 + WaitingRoomGetCurrentUserListResponse struct { + util.CommonError + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + UserList []*WaitingRoomUser `json:"user_list"` + } + + // WaitingRoomGetUserListRequest 获取等候室成员记录请求 + WaitingRoomGetUserListRequest struct { + MeetingID string `json:"meetingid"` + Limit uint32 `json:"limit,omitempty"` + Cursor string `json:"cursor,omitempty"` + } + + // WaitingRoomGetUserListResponse 获取等候室成员记录响应 + WaitingRoomGetUserListResponse struct { + util.CommonError + HasMore bool `json:"has_more"` + NextCursor string `json:"next_cursor"` + UserList []*WaitingRoomRecord `json:"user_list"` + } + + // WaitingRoomUser 实时等候室成员 + WaitingRoomUser struct { + UserID string `json:"userid"` + InstanceID uint32 `json:"instance_id"` + CustomerData string `json:"customer_data"` + TmpOpenID string `json:"tmp_openid"` + } + + // WaitingRoomRecord 等候室成员记录 + WaitingRoomRecord struct { + UserID string `json:"userid"` + TmpOpenID string `json:"tmp_openid"` + InstanceID uint32 `json:"instance_id"` + JoinTime int64 `json:"join_time"` + QuitTime int64 `json:"quit_time"` + } +) + +// WaitingRoomGetCurrentUserList 获取实时等候室成员列表 +// see https://developer.work.weixin.qq.com/document/path/98163 +func (r *Client) WaitingRoomGetCurrentUserList(req *WaitingRoomGetCurrentUserListRequest) (*WaitingRoomGetCurrentUserListResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingWaitingRoomGetCurrentUserListURL, accessToken), req); err != nil { + return nil, err + } + result := &WaitingRoomGetCurrentUserListResponse{} + err = util.DecodeWithError(response, result, "WaitingRoomGetCurrentUserList") + return result, err +} + +// WaitingRoomGetUserList 获取等候室成员记录 +// see https://developer.work.weixin.qq.com/document/path/98164 +func (r *Client) WaitingRoomGetUserList(req *WaitingRoomGetUserListRequest) (*WaitingRoomGetUserListResponse, error) { + var ( + accessToken string + err error + ) + if accessToken, err = r.GetAccessToken(); err != nil { + return nil, err + } + var response []byte + if response, err = util.PostJSON(fmt.Sprintf(meetingWaitingRoomGetUserListURL, accessToken), req); err != nil { + return nil, err + } + result := &WaitingRoomGetUserListResponse{} + err = util.DecodeWithError(response, result, "WaitingRoomGetUserList") + return result, err +} diff --git a/work/work.go b/work/work.go index fc7352adb..65f2ee6f7 100644 --- a/work/work.go +++ b/work/work.go @@ -12,6 +12,7 @@ import ( "github.com/silenceper/wechat/v2/work/jsapi" "github.com/silenceper/wechat/v2/work/kf" "github.com/silenceper/wechat/v2/work/material" + "github.com/silenceper/wechat/v2/work/meeting" "github.com/silenceper/wechat/v2/work/message" "github.com/silenceper/wechat/v2/work/msgaudit" "github.com/silenceper/wechat/v2/work/oauth" @@ -97,3 +98,8 @@ func (wk *Work) GetInvoice() *invoice.Client { func (wk *Work) GetCheckin() *checkin.Client { return checkin.NewClient(wk.ctx) } + +// GetMeeting 获取会议接口实例 +func (wk *Work) GetMeeting() *meeting.Client { + return meeting.NewClient(wk.ctx) +} From 9f0087d893e87ab711e29f800b80d2f191f51d3f Mon Sep 17 00:00:00 2001 From: ssfyn Date: Mon, 17 Aug 2026 12:02:47 +0800 Subject: [PATCH 2/3] golint rename --- work/README.md | 6 +++--- work/meeting/meeting.go | 42 ++++++++++++++++++++--------------------- work/meeting/types.go | 6 +++--- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/work/README.md b/work/README.md index a21ea7422..cc9c457f6 100644 --- a/work/README.md +++ b/work/README.md @@ -21,7 +21,7 @@ wc := work.NewWork(&config.Config{ meetingClient := wc.GetMeeting() //创建预约会议 -resp, err := meetingClient.MeetingCreate(&meeting.MeetingCreateRequest{ +resp, err := meetingClient.MeetingCreate(&meeting.CreateRequest{ AdminUserID: "zhangsan", Title: "新建会议", MeetingStart: 1600000000, @@ -40,12 +40,12 @@ resp, err := meetingClient.MeetingCreate(&meeting.MeetingCreateRequest{ }) //获取会议详情 -info, err := meetingClient.MeetingGetInfo(&meeting.MeetingGetInfoRequest{ +info, err := meetingClient.MeetingGetInfo(&meeting.GetInfoRequest{ MeetingID: "XXXXXXXXX", }) //取消预约会议 -err = meetingClient.MeetingCancel(&meeting.MeetingCancelRequest{ +err = meetingClient.MeetingCancel(&meeting.CancelRequest{ MeetingID: "XXXXXXXXX", }) ``` diff --git a/work/meeting/meeting.go b/work/meeting/meeting.go index 755d8d54d..2a7acc8ee 100644 --- a/work/meeting/meeting.go +++ b/work/meeting/meeting.go @@ -20,8 +20,8 @@ const ( ) type ( - // MeetingCreateRequest 创建预约会议请求 - MeetingCreateRequest struct { + // CreateRequest 创建预约会议请求 + CreateRequest struct { AdminUserID string `json:"admin_userid"` Title string `json:"title"` MeetingStart uint32 `json:"meeting_start,omitempty"` @@ -36,8 +36,8 @@ type ( Reminders *Reminders `json:"reminders,omitempty"` } - // MeetingCreateResponse 创建预约会议响应 - MeetingCreateResponse struct { + // CreateResponse 创建预约会议响应 + CreateResponse struct { util.CommonError MeetingID string `json:"meetingid"` ExcessUsers []string `json:"excess_users"` @@ -45,8 +45,8 @@ type ( MeetingLink string `json:"meeting_link"` } - // MeetingUpdateRequest 修改预约会议请求 - MeetingUpdateRequest struct { + // UpdateRequest 修改预约会议请求 + UpdateRequest struct { MeetingID string `json:"meetingid"` Title string `json:"title,omitempty"` MeetingStart uint32 `json:"meeting_start,omitempty"` @@ -59,27 +59,27 @@ type ( Reminders *Reminders `json:"reminders,omitempty"` } - // MeetingUpdateResponse 修改预约会议响应 - MeetingUpdateResponse struct { + // UpdateResponse 修改预约会议响应 + UpdateResponse struct { util.CommonError ExcessUsers []string `json:"excess_users"` } - // MeetingCancelRequest 取消预约会议请求 - MeetingCancelRequest struct { + // CancelRequest 取消预约会议请求 + CancelRequest struct { MeetingID string `json:"meetingid"` SubMeetingID string `json:"sub_meetingid,omitempty"` } - // MeetingGetInfoRequest 获取会议详情请求 - MeetingGetInfoRequest struct { + // GetInfoRequest 获取会议详情请求 + GetInfoRequest struct { MeetingID string `json:"meetingid,omitempty"` MeetingCode string `json:"meeting_code,omitempty"` SubMeetingID string `json:"sub_meetingid,omitempty"` } - // MeetingGetInfoResponse 获取会议详情响应 - MeetingGetInfoResponse struct { + // GetInfoResponse 获取会议详情响应 + GetInfoResponse struct { util.CommonError AdminUserID string `json:"admin_userid"` Title string `json:"title"` @@ -124,7 +124,7 @@ type ( // MeetingCreate 创建预约会议 // see https://developer.work.weixin.qq.com/document/path/98148 -func (r *Client) MeetingCreate(req *MeetingCreateRequest) (*MeetingCreateResponse, error) { +func (r *Client) MeetingCreate(req *CreateRequest) (*CreateResponse, error) { var ( accessToken string err error @@ -136,14 +136,14 @@ func (r *Client) MeetingCreate(req *MeetingCreateRequest) (*MeetingCreateRespons if response, err = util.PostJSON(fmt.Sprintf(meetingCreateURL, accessToken), req); err != nil { return nil, err } - result := &MeetingCreateResponse{} + result := &CreateResponse{} err = util.DecodeWithError(response, result, "MeetingCreate") return result, err } // MeetingUpdate 修改预约会议 // see https://developer.work.weixin.qq.com/document/path/98154 -func (r *Client) MeetingUpdate(req *MeetingUpdateRequest) (*MeetingUpdateResponse, error) { +func (r *Client) MeetingUpdate(req *UpdateRequest) (*UpdateResponse, error) { var ( accessToken string err error @@ -155,14 +155,14 @@ func (r *Client) MeetingUpdate(req *MeetingUpdateRequest) (*MeetingUpdateRespons if response, err = util.PostJSON(fmt.Sprintf(meetingUpdateURL, accessToken), req); err != nil { return nil, err } - result := &MeetingUpdateResponse{} + result := &UpdateResponse{} err = util.DecodeWithError(response, result, "MeetingUpdate") return result, err } // MeetingCancel 取消预约会议 // see https://developer.work.weixin.qq.com/document/path/98153 -func (r *Client) MeetingCancel(req *MeetingCancelRequest) error { +func (r *Client) MeetingCancel(req *CancelRequest) error { var ( accessToken string err error @@ -179,7 +179,7 @@ func (r *Client) MeetingCancel(req *MeetingCancelRequest) error { // MeetingGetInfo 获取会议详情 // see https://developer.work.weixin.qq.com/document/path/98149 -func (r *Client) MeetingGetInfo(req *MeetingGetInfoRequest) (*MeetingGetInfoResponse, error) { +func (r *Client) MeetingGetInfo(req *GetInfoRequest) (*GetInfoResponse, error) { var ( accessToken string err error @@ -191,7 +191,7 @@ func (r *Client) MeetingGetInfo(req *MeetingGetInfoRequest) (*MeetingGetInfoResp if response, err = util.PostJSON(fmt.Sprintf(meetingGetInfoURL, accessToken), req); err != nil { return nil, err } - result := &MeetingGetInfoResponse{} + result := &GetInfoResponse{} err = util.DecodeWithError(response, result, "MeetingGetInfo") return result, err } diff --git a/work/meeting/types.go b/work/meeting/types.go index 14808b231..476139914 100644 --- a/work/meeting/types.go +++ b/work/meeting/types.go @@ -67,12 +67,12 @@ type Reminders struct { // Attendees 会议成员 type Attendees struct { - Member []*MeetingMember `json:"member"` + Member []*Member `json:"member"` TmpExternalUser []*TmpExternalUser `json:"tmp_external_user"` } -// MeetingMember 企业内部成员 -type MeetingMember struct { +// Member 企业内部成员 +type Member struct { UserID string `json:"userid"` Status uint32 `json:"status"` FirstJoinTime uint32 `json:"first_join_time"` From ea081a4650b637929e3bf670a0de998f49570385 Mon Sep 17 00:00:00 2001 From: ssfyn Date: Mon, 17 Aug 2026 14:03:31 +0800 Subject: [PATCH 3/3] fix omitempty --- work/meeting/enroll.go | 6 +++--- work/meeting/meeting.go | 4 ++-- work/meeting/types.go | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/work/meeting/enroll.go b/work/meeting/enroll.go index 2e7e919d9..2ea6d0df2 100644 --- a/work/meeting/enroll.go +++ b/work/meeting/enroll.go @@ -27,9 +27,9 @@ type ( // EnrollSetConfigRequest 修改会议报名配置请求 EnrollSetConfigRequest struct { MeetingID string `json:"meetingid"` - ApproveType int32 `json:"approve_type,omitempty"` - IsCollectQuestion int32 `json:"is_collect_question,omitempty"` - QuestionList []*EnrollQuestion `json:"question_list,omitempty"` + ApproveType int32 `json:"approve_type"` + IsCollectQuestion int32 `json:"is_collect_question"` + QuestionList []*EnrollQuestion `json:"question_list"` NoRegistrationNeededForStaff *bool `json:"no_registration_needed_for_staff,omitempty"` } diff --git a/work/meeting/meeting.go b/work/meeting/meeting.go index 2a7acc8ee..e2e6c6f27 100644 --- a/work/meeting/meeting.go +++ b/work/meeting/meeting.go @@ -26,8 +26,8 @@ type ( Title string `json:"title"` MeetingStart uint32 `json:"meeting_start,omitempty"` MeetingDuration uint32 `json:"meeting_duration,omitempty"` - Description string `json:"description,omitempty"` - Location string `json:"location,omitempty"` + Description string `json:"description"` + Location string `json:"location"` AgentID uint32 `json:"agentid,omitempty"` Invitees *Invitees `json:"invitees,omitempty"` Guests []*Guest `json:"guests,omitempty"` diff --git a/work/meeting/types.go b/work/meeting/types.go index 476139914..296b38721 100644 --- a/work/meeting/types.go +++ b/work/meeting/types.go @@ -24,10 +24,10 @@ type RingUsers struct { // Settings 会议配置 type Settings struct { - Password string `json:"password,omitempty"` - EnableWaitingRoom *bool `json:"enable_waiting_room,omitempty"` - AllowEnterBeforeHost *bool `json:"allow_enter_before_host,omitempty"` - EnableEnterMute uint32 `json:"enable_enter_mute,omitempty"` + Password string `json:"password"` + EnableWaitingRoom *bool `json:"enable_waiting_room"` + AllowEnterBeforeHost *bool `json:"allow_enter_before_host"` + EnableEnterMute uint32 `json:"enable_enter_mute"` AllowUnmuteSelf *bool `json:"allow_unmute_self,omitempty"` MuteAll *bool `json:"mute_all,omitempty"` AllowExternalUser *bool `json:"allow_external_user,omitempty"`