Compare commits

..
2 Commits
Author SHA1 Message Date
wwek 8409760713 feat(kf): 获取客户基础信息支持 need_enter_session_context 及进入会话上下文返回 (#894) 2026-11-04 22:22:31 +08:00
ccfish ad48392a5b feat(miniprogram): 添加学生身份核验和通用API调用功能 (#893)
* feat: 添加 微信物流服务 /微信物流服务(商家查看) /消息组件

* fix lint issues

* fix: 查询运单详情信息返回结果结构

* 追加官方文档地址

* feat: 追加接口【微信物流服务 /微信物流服务(商家查看) /查询组件】

* fix: comments

* fix: indents

* feat(miniprogram): 添加学生身份核验和通用API调用功能

- 新增学生身份核验模块,支持快速获取学生身份接口
- 添加通用API调用功能,用于访问SDK尚未封装的小程序接口
- 实现GET/POST请求及响应解码的通用方法
- 在文档中补充学生身份相关API说明
2026-09-29 16:25:30 +08:00
5 changed files with 242 additions and 0 deletions

No files matched your search

+9
View File
@@ -48,3 +48,12 @@ TODO
| :----------------: | -------- | :------------------- | ---------- | ------------------------------------------ |
| 获取用户的安全等级 | POST | /wxa/getuserriskrank | YES | (riskControl *RiskControl) GetUserRiskRank |
## 学生身份
[官方文档](https://developers.weixin.qq.com/miniprogram/dev/server/API/student/api_quickcheckstudentidentity.html)
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |
| :--------------: | -------- | :------------------------------ | ---------- | ----------------------------------------------- |
| 快速获取学生身份 | POST | /intp/quickcheckstudentidentity | YES | (student *Student) QuickCheckStudentIdentity |
+127
View File
@@ -0,0 +1,127 @@
package generic
import (
context2 "context"
"net/url"
"strings"
"github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/util"
)
// defaultBaseURL 微信 API 默认基础地址
const defaultBaseURL = "https://api.weixin.qq.com"
// Generic 通用 API 调用,用于访问 SDK 尚未封装的小程序接口。
// 支持自定义 path、query 参数、request body 以及 response 结构体。
type Generic struct {
*context.Context
}
// NewGeneric init
func NewGeneric(ctx *context.Context) *Generic {
return &Generic{ctx}
}
// BuildURL 构建完整请求 URL。
// path 支持相对路径(如 "/intp/xxx")或完整 URL(如 "https://api.weixin.qq.com/intp/xxx")。
// query 为额外的 URL 查询参数,可为 nil;access_token 会自动追加(若 query 中已包含则不重复追加)。
func (g *Generic) BuildURL(path string, query url.Values) (string, error) {
return g.BuildURLContext(context2.Background(), path, query)
}
// BuildURLContext 构建完整请求 URL(带 context)
func (g *Generic) BuildURLContext(ctx context2.Context, path string, query url.Values) (string, error) {
var baseURL string
switch {
case strings.HasPrefix(path, "http://"), strings.HasPrefix(path, "https://"):
baseURL = path
case strings.HasPrefix(path, "/"):
baseURL = defaultBaseURL + path
default:
baseURL = defaultBaseURL + "/" + path
}
// 克隆 query,避免修改调用方原始值
q := make(url.Values, len(query)+1)
for k, v := range query {
q[k] = v
}
// 自动追加 access_token
if q.Get("access_token") == "" {
accessToken, err := g.GetAccessTokenContext(ctx)
if err != nil {
return "", err
}
q.Set("access_token", accessToken)
}
sep := "?"
if strings.Contains(baseURL, "?") {
sep = "&"
}
return baseURL + sep + q.Encode(), nil
}
// Get 发送 GET 请求,返回原始响应字节。
// 使用 util.DecodeWithError 可将响应解码到自定义结构体。
func (g *Generic) Get(path string, query url.Values) (response []byte, err error) {
return g.GetContext(context2.Background(), path, query)
}
// GetContext 发送 GET 请求(带 context),返回原始响应字节
func (g *Generic) GetContext(ctx context2.Context, path string, query url.Values) (response []byte, err error) {
var uri string
if uri, err = g.BuildURLContext(ctx, path, query); err != nil {
return
}
return util.HTTPGetContext(ctx, uri)
}
// PostJSON 发送 POST 请求(JSON body),返回原始响应字节。
// body 可为 nil(无请求体);使用 util.DecodeWithError 可将响应解码到自定义结构体。
func (g *Generic) PostJSON(path string, query url.Values, body interface{}) (response []byte, err error) {
return g.PostJSONContext(context2.Background(), path, query, body)
}
// PostJSONContext 发送 POST 请求(JSON body,带 context),返回原始响应字节
func (g *Generic) PostJSONContext(ctx context2.Context, path string, query url.Values, body interface{}) (response []byte, err error) {
var uri string
if uri, err = g.BuildURLContext(ctx, path, query); err != nil {
return
}
return util.PostJSONContext(ctx, uri, body)
}
// GetDecode 发送 GET 请求并将响应解码到 resp。
// resp 应为指向结构体的指针,结构体中可嵌入 util.CommonError 以自动校验错误码。
// apiName 用于错误信息标识。
func (g *Generic) GetDecode(path string, query url.Values, resp interface{}, apiName string) (err error) {
return g.GetDecodeContext(context2.Background(), path, query, resp, apiName)
}
// GetDecodeContext 发送 GET 请求并将响应解码到 resp(带 context)
func (g *Generic) GetDecodeContext(ctx context2.Context, path string, query url.Values, resp interface{}, apiName string) (err error) {
var response []byte
if response, err = g.GetContext(ctx, path, query); err != nil {
return
}
return util.DecodeWithError(response, resp, apiName)
}
// PostJSONDecode 发送 POST 请求(JSON body)并将响应解码到 resp。
// resp 应为指向结构体的指针,结构体中可嵌入 util.CommonError 以自动校验错误码。
// apiName 用于错误信息标识。
func (g *Generic) PostJSONDecode(path string, query url.Values, body, resp interface{}, apiName string) (err error) {
return g.PostJSONDecodeContext(context2.Background(), path, query, body, resp, apiName)
}
// PostJSONDecodeContext 发送 POST 请求(JSON body)并将响应解码到 resp(带 context)
func (g *Generic) PostJSONDecodeContext(ctx context2.Context, path string, query url.Values, body, resp interface{}, apiName string) (err error) {
var response []byte
if response, err = g.PostJSONContext(ctx, path, query, body); err != nil {
return
}
return util.DecodeWithError(response, resp, apiName)
}
+12
View File
@@ -11,6 +11,7 @@ import (
"github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/miniprogram/encryptor"
"github.com/silenceper/wechat/v2/miniprogram/express"
"github.com/silenceper/wechat/v2/miniprogram/generic"
"github.com/silenceper/wechat/v2/miniprogram/message"
"github.com/silenceper/wechat/v2/miniprogram/minidrama"
"github.com/silenceper/wechat/v2/miniprogram/ocr"
@@ -22,6 +23,7 @@ import (
"github.com/silenceper/wechat/v2/miniprogram/riskcontrol"
"github.com/silenceper/wechat/v2/miniprogram/security"
"github.com/silenceper/wechat/v2/miniprogram/shortlink"
"github.com/silenceper/wechat/v2/miniprogram/student"
"github.com/silenceper/wechat/v2/miniprogram/subscribe"
"github.com/silenceper/wechat/v2/miniprogram/tcb"
"github.com/silenceper/wechat/v2/miniprogram/urllink"
@@ -202,3 +204,13 @@ func (miniProgram *MiniProgram) GetOCR() *ocr.OCR {
func (miniProgram *MiniProgram) GetIntracity() *express.Express {
return express.NewExpress(miniProgram.ctx)
}
// GetStudent 学生身份核验接口
func (miniProgram *MiniProgram) GetStudent() *student.Student {
return student.NewStudent(miniProgram.ctx)
}
// GetGeneric 通用 API 调用,用于访问 SDK 尚未封装的接口
func (miniProgram *MiniProgram) GetGeneric() *generic.Generic {
return generic.NewGeneric(miniProgram.ctx)
}
+73
View File
@@ -0,0 +1,73 @@
package student
import (
context2 "context"
"fmt"
"github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/util"
)
const (
// quickCheckStudentIdentityURL 快速获取学生身份
quickCheckStudentIdentityURL = "https://api.weixin.qq.com/intp/quickcheckstudentidentity?access_token=%s"
)
// Student 学生身份核验
type Student struct {
*context.Context
}
// NewStudent init
func NewStudent(ctx *context.Context) *Student {
return &Student{ctx}
}
// BindStatus 学生身份绑定状态
type BindStatus int
const (
// BindStatusUnbound 未绑定
BindStatusUnbound BindStatus = 1
// BindStatusAuditing 审核中
BindStatusAuditing BindStatus = 2
// BindStatusBound 已绑定
BindStatusBound BindStatus = 3
)
// QuickCheckStudentIdentityRequest 快速获取学生身份请求参数
type QuickCheckStudentIdentityRequest struct {
OpenID string `json:"openid"` // 用户在业务方下的openid,需为已开通接口权限小程序对应的用户openid
WxStudentCheckCode string `json:"wx_studentcheck_code"` // 用户授权查询code,由授权插件返回,code有效期两小时
}
// QuickCheckStudentIdentityResponse 快速获取学生身份返回参数
type QuickCheckStudentIdentityResponse struct {
util.CommonError
BindStatus BindStatus `json:"bind_status"` // 绑定状态:1-未绑定,2-审核中,3-已绑定
IsStudent bool `json:"is_student"` // 用户学生身份绑定状态说明,true-是学生,false-不是学生
}
// QuickCheckStudentIdentity 快速获取学生身份
// see https://developers.weixin.qq.com/miniprogram/dev/server/API/student/api_quickcheckstudentidentity.html
func (student *Student) QuickCheckStudentIdentity(in *QuickCheckStudentIdentityRequest) (out QuickCheckStudentIdentityResponse, err error) {
return student.QuickCheckStudentIdentityContext(context2.Background(), in)
}
// QuickCheckStudentIdentityContext 快速获取学生身份
func (student *Student) QuickCheckStudentIdentityContext(ctx context2.Context, in *QuickCheckStudentIdentityRequest) (out QuickCheckStudentIdentityResponse, err error) {
var accessToken string
if accessToken, err = student.GetAccessTokenContext(ctx); err != nil {
return
}
uri := fmt.Sprintf(quickCheckStudentIdentityURL, accessToken)
var response []byte
if response, err = util.PostJSONContext(ctx, uri, in); err != nil {
return
}
// 使用通用方法返回错误
err = util.DecodeWithError(response, &out, "student.QuickCheckStudentIdentity")
return
}
+21
View File
@@ -14,6 +14,24 @@ const (
// CustomerBatchGetOptions 客户基本信息获取请求参数
type CustomerBatchGetOptions struct {
ExternalUserIDList []string `json:"external_userid_list"` // external_userid列表
// NeedEnterSessionContext 是否需要返回客户48小时内最后一次进入会话的上下文信息
// 0-不返回 1-返回。默认不返回
NeedEnterSessionContext int `json:"need_enter_session_context"`
}
// CustomerWechatChannelsSchema 进入会话的视频号信息,从视频号进入会话才有值
type CustomerWechatChannelsSchema struct {
Nickname string `json:"nickname"` // 视频号名称,视频号场景值为1、2、3时返回此项
ShopNickname string `json:"shop_nickname"` // 视频号小店名称,视频号场景值为4、5时返回此项
Scene uint32 `json:"scene"` // 视频号场景值。1:视频号主页,2:视频号直播间商品列表页,3:视频号商品橱窗页,4:视频号小店商品详情页,5:视频号小店订单页
}
// CustomerEnterSessionContextSchema 48小时内最后一次进入会话的上下文信息
// 请求的need_enter_session_context参数设置为1才返回
type CustomerEnterSessionContextSchema struct {
Scene string `json:"scene"` // 进入会话的场景值,获取客服账号链接开发者自定义的场景值
SceneParam string `json:"scene_param"` // 进入会话的自定义参数,获取客服账号链接返回的url,开发者按规范拼接的scene_param参数
WechatChannels CustomerWechatChannelsSchema `json:"wechat_channels"` // 进入会话的视频号信息,从视频号进入会话才有值
}
// CustomerSchema 微信客户基本资料
@@ -23,6 +41,9 @@ type CustomerSchema struct {
Avatar string `json:"avatar"` // 微信头像。第三方不可获取
Gender int `json:"gender"` // 性别
UnionID string `json:"unionid"` // unionid,需要绑定微信开发者帐号才能获取到,查看绑定方法: https://open.work.weixin.qq.com/kf/doc/92512/93143/94769#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1%E5%AE%A2%E6%88%B7%E7%9A%84unionid
// EnterSessionContext 48小时内最后一次进入会话的上下文信息
// 请求的need_enter_session_context参数设置为1才返回
EnterSessionContext CustomerEnterSessionContextSchema `json:"enter_session_context"`
}
// CustomerBatchGetSchema 获取客户基本信息响应内容