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"`