606 lines
17 KiB
Go
606 lines
17 KiB
Go
package controllers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"strings"
|
||
"time"
|
||
|
||
"server/models"
|
||
"server/pkg/jwtutil"
|
||
"server/services/wechatmp"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
beego "github.com/beego/beego/v2/server/web"
|
||
)
|
||
|
||
// =============================================================
|
||
// 平台端「微信公众号(服务号)」:
|
||
// 配置(AppID/Secret/Token/AESKey)、绑定(扫码关注取验证码)、粉丝管理、消息推送
|
||
// 未认证阶段可完整跑通「扫码关注 → 公众号回复验证码 → 平台核销绑定」;
|
||
// 认证后开启模板消息推送(提醒/公告)。
|
||
// =============================================================
|
||
|
||
// PlatformWechatMpController 平台端微信公众号管理
|
||
type PlatformWechatMpController struct {
|
||
beego.Controller
|
||
}
|
||
|
||
func (c *PlatformWechatMpController) claims() (*jwtutil.Claims, error) {
|
||
auth := c.Ctx.Request.Header.Get("Authorization")
|
||
if auth == "" {
|
||
return nil, fmt.Errorf("未登录")
|
||
}
|
||
parts := strings.SplitN(auth, " ", 2)
|
||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||
return nil, fmt.Errorf("认证信息格式错误")
|
||
}
|
||
claims, err := jwtutil.ParseToken(parts[1])
|
||
if err != nil {
|
||
return nil, fmt.Errorf("无效的token")
|
||
}
|
||
if claims.UserType != "platform" {
|
||
return nil, fmt.Errorf("无权访问")
|
||
}
|
||
return claims, nil
|
||
}
|
||
|
||
func (c *PlatformWechatMpController) jsonErr(httpStatus, bizCode int, msg string) {
|
||
c.Ctx.Output.SetStatus(httpStatus)
|
||
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
func (c *PlatformWechatMpController) ok(data interface{}, msg string) {
|
||
if msg == "" {
|
||
msg = "success"
|
||
}
|
||
resp := map[string]interface{}{"code": 200, "msg": msg}
|
||
if data != nil {
|
||
resp["data"] = data
|
||
}
|
||
c.Data["json"] = resp
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
func (c *PlatformWechatMpController) readBody(out interface{}) bool {
|
||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||
if err != nil {
|
||
c.jsonErr(400, 400, "参数错误")
|
||
return false
|
||
}
|
||
if err := json.Unmarshal(raw, out); err != nil {
|
||
c.jsonErr(400, 400, "参数错误")
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// ============================ 配置 ============================
|
||
|
||
// GetConfig GET /platform/wechatMp/config
|
||
func (c *PlatformWechatMpController) GetConfig() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
data := map[string]interface{}{
|
||
"app_id": "",
|
||
"app_secret": "",
|
||
"token": "",
|
||
"aes_key": "",
|
||
"encrypt_mode": wechatmp.EncryptModePlain,
|
||
"template_id": "",
|
||
"verified": 0,
|
||
"enabled": 0,
|
||
"remark": "",
|
||
"configured": false,
|
||
"callback_url": wechatmp.CallbackURL(),
|
||
}
|
||
if cfg, err := wechatmp.LoadConfig(); err == nil {
|
||
data["app_id"] = cfg.AppID
|
||
data["app_secret"] = wechatmp.MaskSecret(cfg.AppSecret)
|
||
data["token"] = cfg.Token
|
||
data["aes_key"] = wechatmp.MaskSecret(cfg.AESKey)
|
||
data["encrypt_mode"] = cfg.EncryptMode
|
||
data["template_id"] = cfg.TemplateID
|
||
data["remark"] = cfg.Remark
|
||
data["configured"] = cfg.AppID != ""
|
||
if cfg.Verified {
|
||
data["verified"] = 1
|
||
}
|
||
if cfg.Enabled {
|
||
data["enabled"] = 1
|
||
}
|
||
}
|
||
c.ok(data, "获取成功")
|
||
}
|
||
|
||
// SaveConfig POST /platform/wechatMp/config
|
||
func (c *PlatformWechatMpController) SaveConfig() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
AppID string `json:"app_id"`
|
||
AppSecret string `json:"app_secret"`
|
||
Token string `json:"token"`
|
||
AESKey string `json:"aes_key"`
|
||
EncryptMode string `json:"encrypt_mode"`
|
||
TemplateID string `json:"template_id"`
|
||
Verified bool `json:"verified"`
|
||
Enabled bool `json:"enabled"`
|
||
Remark string `json:"remark"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
if strings.TrimSpace(p.AppID) == "" {
|
||
c.jsonErr(400, 400, "AppID 不能为空")
|
||
return
|
||
}
|
||
err := wechatmp.SaveConfig(wechatmp.SaveInput{
|
||
AppID: p.AppID,
|
||
AppSecret: p.AppSecret,
|
||
Token: p.Token,
|
||
AESKey: p.AESKey,
|
||
EncryptMode: p.EncryptMode,
|
||
TemplateID: p.TemplateID,
|
||
Verified: p.Verified,
|
||
Enabled: p.Enabled,
|
||
Remark: p.Remark,
|
||
})
|
||
if err != nil {
|
||
c.jsonErr(400, 400, "保存失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(nil, "保存成功")
|
||
}
|
||
|
||
// TestConnection POST /platform/wechatMp/test
|
||
// 使用当前配置获取 access_token,验证 AppID/AppSecret 是否正确
|
||
func (c *PlatformWechatMpController) TestConnection() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
cfg, err := wechatmp.LoadConfig()
|
||
if err != nil || cfg.AppID == "" || cfg.AppSecret == "" {
|
||
c.jsonErr(400, 400, "请先保存 AppID 与 AppSecret")
|
||
return
|
||
}
|
||
token, err := wechatmp.GetAccessToken(cfg)
|
||
if err != nil {
|
||
msg := "连接失败:" + err.Error()
|
||
if hint, ok := wechatmp.ExplainError(err); ok {
|
||
msg += ";" + hint
|
||
}
|
||
c.jsonErr(400, 400, msg)
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{
|
||
"access_token_suffix": wechatmp.MaskSecret(token),
|
||
"callback_url": wechatmp.CallbackURL(),
|
||
"verified": boolToInt8(cfg.Verified),
|
||
}, "连接成功:AppID 与 AppSecret 校验通过")
|
||
}
|
||
|
||
// ============================ 绑定(当前平台用户) ============================
|
||
|
||
// BindStart POST /platform/wechatMp/bind/start
|
||
// 生成带参二维码;用户扫码关注后公众号将被动回复验证码
|
||
func (c *PlatformWechatMpController) BindStart() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
uid := uint64(claims.UserID)
|
||
if uid == 0 {
|
||
c.jsonErr(401, 401, "未获取到用户信息")
|
||
return
|
||
}
|
||
scene, _, qrURL, expireAt, err := wechatmp.CreateVerifyCode(models.WechatBindTypePlatformUser, uid, 0, 0)
|
||
if err != nil {
|
||
c.jsonErr(400, 400, "生成二维码失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{
|
||
"scene": scene,
|
||
"qrcode_url": qrURL,
|
||
"expire_at": expireAt,
|
||
"expires_in": int(time.Until(expireAt).Seconds()),
|
||
"callback_url": wechatmp.CallbackURL(),
|
||
}, "生成成功")
|
||
}
|
||
|
||
// BindStatus GET /platform/wechatMp/bind/status?scene=xxx
|
||
func (c *PlatformWechatMpController) BindStatus() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
scene := strings.TrimSpace(c.GetString("scene"))
|
||
row, err := wechatmp.GetVerifyCode(scene)
|
||
if err != nil {
|
||
c.jsonErr(404, 404, err.Error())
|
||
return
|
||
}
|
||
if row.BindType != models.WechatBindTypePlatformUser || row.BindID != uint64(claims.UserID) {
|
||
c.jsonErr(403, 403, "该二维码不是当前账号发起,请重新获取")
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{
|
||
"status": row.Status,
|
||
"expire_at": row.ExpireAt,
|
||
}, "获取成功")
|
||
}
|
||
|
||
// BindConfirm POST /platform/wechatMp/bind/confirm {scene, code}
|
||
func (c *PlatformWechatMpController) BindConfirm() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
Scene string `json:"scene"`
|
||
Code string `json:"code"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
if strings.TrimSpace(p.Code) == "" {
|
||
c.jsonErr(400, 400, "请输入公众号返回的验证码")
|
||
return
|
||
}
|
||
var follower *models.WechatMpFollower
|
||
if strings.TrimSpace(p.Scene) == "" {
|
||
// 未展示二维码(在公众号内发送「验证码」获取):按验证码认领待认领会话
|
||
follower, err = wechatmp.ConfirmVerifyCodeByCode(models.WechatBindTypePlatformUser, uint64(claims.UserID), 0, p.Code)
|
||
} else {
|
||
follower, err = wechatmp.ConfirmVerifyCode(models.WechatBindTypePlatformUser, uint64(claims.UserID), 0, p.Scene, p.Code)
|
||
}
|
||
if err != nil {
|
||
c.jsonErr(400, 400, err.Error())
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{
|
||
"openid": follower.OpenID,
|
||
"nickname": follower.Nickname,
|
||
"bind_time": follower.BindTime,
|
||
}, "绑定成功")
|
||
}
|
||
|
||
// MyBinding GET /platform/wechatMp/my
|
||
func (c *PlatformWechatMpController) MyBinding() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
follower, err := wechatmp.GetFollowerByUser(models.WechatBindTypePlatformUser, uint64(claims.UserID))
|
||
if err != nil {
|
||
c.jsonErr(500, 500, "查询失败:"+err.Error())
|
||
return
|
||
}
|
||
if follower == nil {
|
||
c.ok(map[string]interface{}{"bound": false}, "获取成功")
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{
|
||
"bound": true,
|
||
"openid": follower.OpenID,
|
||
"nickname": follower.Nickname,
|
||
"avatar": follower.Avatar,
|
||
"subscribe": follower.Subscribe,
|
||
"bind_time": follower.BindTime,
|
||
"subscribe_time": follower.SubscribeTime,
|
||
}, "获取成功")
|
||
}
|
||
|
||
// Unbind POST /platform/wechatMp/unbind
|
||
func (c *PlatformWechatMpController) Unbind() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
if err := wechatmp.UnbindByUser(models.WechatBindTypePlatformUser, uint64(claims.UserID)); err != nil {
|
||
c.jsonErr(500, 500, "解绑失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(nil, "已解绑")
|
||
}
|
||
|
||
// ============================ 粉丝管理 ============================
|
||
|
||
// ListFollowers GET /platform/wechatMp/followers?page=&pageSize=&keyword=&bind_type=&subscribe=
|
||
func (c *PlatformWechatMpController) ListFollowers() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
page, _ := c.GetInt("page", 1)
|
||
pageSize, _ := c.GetInt("pageSize", 20)
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
if pageSize < 1 || pageSize > 200 {
|
||
pageSize = 20
|
||
}
|
||
|
||
qs := models.Orm.QueryTable(new(models.WechatMpFollower)).Filter("delete_time__isnull", true)
|
||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||
cond := orm.NewCondition().
|
||
Or("nickname__icontains", kw).
|
||
Or("openid__icontains", kw).
|
||
Or("remark__icontains", kw)
|
||
qs = qs.SetCond(cond)
|
||
}
|
||
if bindType := strings.TrimSpace(c.GetString("bind_type")); bindType != "" {
|
||
qs = qs.Filter("bind_type", bindType)
|
||
}
|
||
if sub := strings.TrimSpace(c.GetString("subscribe")); sub == "0" || sub == "1" {
|
||
qs = qs.Filter("subscribe", sub)
|
||
}
|
||
|
||
total, err := qs.Count()
|
||
if err != nil {
|
||
c.jsonErr(500, 500, "获取失败:"+err.Error())
|
||
return
|
||
}
|
||
var rows []models.WechatMpFollower
|
||
if _, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
|
||
c.jsonErr(500, 500, "获取失败:"+err.Error())
|
||
return
|
||
}
|
||
|
||
// 绑定对象名称(平台用户 / 租户用户)
|
||
nameMap := loadWechatBindNames(rows)
|
||
|
||
list := make([]map[string]interface{}, 0, len(rows))
|
||
for i := range rows {
|
||
r := rows[i]
|
||
nickname := r.Nickname
|
||
if strings.TrimSpace(nickname) == "" {
|
||
nickname = maskOpenID(r.OpenID)
|
||
}
|
||
list = append(list, map[string]interface{}{
|
||
"id": r.ID,
|
||
"openid": r.OpenID,
|
||
"nickname": nickname,
|
||
"avatar": r.Avatar,
|
||
"sex": r.Sex,
|
||
"city": r.City,
|
||
"subscribe": r.Subscribe,
|
||
"subscribe_time": r.SubscribeTime,
|
||
"unsubscribe_time": r.UnsubscribeTime,
|
||
"bind_type": r.BindType,
|
||
"bind_id": r.BindID,
|
||
"bind_tid": r.BindTid,
|
||
"bind_name": nameMap[r.BindType+"#"+fmt.Sprintf("%d", r.BindID)+"#"+fmt.Sprintf("%d", r.BindTid)],
|
||
"bind_time": r.BindTime,
|
||
"remark": r.Remark,
|
||
"create_time": r.CreateTime,
|
||
})
|
||
}
|
||
c.ok(map[string]interface{}{"list": list, "total": total, "page": page, "pageSize": pageSize}, "获取成功")
|
||
}
|
||
|
||
// SetFollowerRemark POST /platform/wechatMp/follower/remark {id, remark}
|
||
func (c *PlatformWechatMpController) SetFollowerRemark() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
ID uint64 `json:"id"`
|
||
Remark string `json:"remark"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
if p.ID == 0 {
|
||
c.jsonErr(400, 400, "参数错误")
|
||
return
|
||
}
|
||
now := time.Now()
|
||
if _, err := models.Orm.QueryTable(new(models.WechatMpFollower)).
|
||
Filter("id", p.ID).
|
||
Update(map[string]interface{}{"remark": strings.TrimSpace(p.Remark), "update_time": now}); err != nil {
|
||
c.jsonErr(500, 500, "保存失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(nil, "保存成功")
|
||
}
|
||
|
||
// UnbindFollower POST /platform/wechatMp/follower/unbind {id}
|
||
// 仅清除绑定关系(保留粉丝记录)
|
||
func (c *PlatformWechatMpController) UnbindFollower() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
ID uint64 `json:"id"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
if p.ID == 0 {
|
||
c.jsonErr(400, 400, "参数错误")
|
||
return
|
||
}
|
||
now := time.Now()
|
||
if _, err := models.Orm.QueryTable(new(models.WechatMpFollower)).
|
||
Filter("id", p.ID).
|
||
Update(map[string]interface{}{
|
||
"bind_type": "", "bind_id": 0, "bind_tid": 0, "update_time": now,
|
||
}); err != nil {
|
||
c.jsonErr(500, 500, "解绑失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(nil, "已解绑")
|
||
}
|
||
|
||
// ============================ 推送 ============================
|
||
|
||
// Push POST /platform/wechatMp/push
|
||
// {title, content, remark, url, bind_type, bind_id, tid}
|
||
func (c *PlatformWechatMpController) Push() {
|
||
if _, err := c.claims(); err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
Title string `json:"title"`
|
||
Content string `json:"content"`
|
||
Remark string `json:"remark"`
|
||
URL string `json:"url"`
|
||
BindType string `json:"bind_type"`
|
||
BindID uint64 `json:"bind_id"`
|
||
Tid uint64 `json:"tid"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
if strings.TrimSpace(p.Title) == "" && strings.TrimSpace(p.Content) == "" {
|
||
c.jsonErr(400, 400, "请填写推送内容")
|
||
return
|
||
}
|
||
cfg, err := wechatmp.LoadEnabledConfig()
|
||
if err != nil {
|
||
c.jsonErr(400, 400, "请先启用并配置微信公众号:"+err.Error())
|
||
return
|
||
}
|
||
sent, failed, perr := wechatmp.PushToFollowers(cfg, wechatmp.PushScope{
|
||
BindType: strings.TrimSpace(p.BindType),
|
||
BindID: p.BindID,
|
||
Tid: p.Tid,
|
||
}, wechatmp.PushMessage{
|
||
Title: strings.TrimSpace(p.Title),
|
||
Content: strings.TrimSpace(p.Content),
|
||
Remark: strings.TrimSpace(p.Remark),
|
||
URL: strings.TrimSpace(p.URL),
|
||
})
|
||
if perr != nil {
|
||
c.jsonErr(400, 400, perr.Error())
|
||
return
|
||
}
|
||
c.ok(map[string]interface{}{"sent": sent, "failed": failed},
|
||
fmt.Sprintf("推送完成:成功 %d 条,失败 %d 条", sent, failed))
|
||
}
|
||
|
||
// PushTest POST /platform/wechatMp/push/test {title, content, remark}
|
||
// 推送给当前登录平台用户绑定的微信
|
||
func (c *PlatformWechatMpController) PushTest() {
|
||
claims, err := c.claims()
|
||
if err != nil {
|
||
c.jsonErr(401, 401, err.Error())
|
||
return
|
||
}
|
||
var p struct {
|
||
Title string `json:"title"`
|
||
Content string `json:"content"`
|
||
Remark string `json:"remark"`
|
||
}
|
||
if !c.readBody(&p) {
|
||
return
|
||
}
|
||
cfg, err := wechatmp.LoadEnabledConfig()
|
||
if err != nil {
|
||
c.jsonErr(400, 400, "请先启用并配置微信公众号:"+err.Error())
|
||
return
|
||
}
|
||
follower, err := wechatmp.GetFollowerByUser(models.WechatBindTypePlatformUser, uint64(claims.UserID))
|
||
if err != nil || follower == nil {
|
||
c.jsonErr(400, 400, "当前账号尚未绑定微信,请先扫码绑定")
|
||
return
|
||
}
|
||
if follower.Subscribe != 1 {
|
||
c.jsonErr(400, 400, "该微信已取消关注,请重新关注后再试")
|
||
return
|
||
}
|
||
if p.Title == "" {
|
||
p.Title = "平台消息测试"
|
||
}
|
||
if p.Content == "" {
|
||
p.Content = "这是一条来自平台的测试消息,收到说明推送链路正常。"
|
||
}
|
||
if err := wechatmp.PushToOpenID(cfg, follower.OpenID, wechatmp.PushMessage{
|
||
Title: strings.TrimSpace(p.Title),
|
||
Content: strings.TrimSpace(p.Content),
|
||
Remark: strings.TrimSpace(p.Remark),
|
||
}); err != nil {
|
||
c.jsonErr(400, 400, "推送失败:"+err.Error())
|
||
return
|
||
}
|
||
c.ok(nil, "测试消息已发送")
|
||
}
|
||
|
||
// ============================ 辅助 ============================
|
||
|
||
func boolToInt8(b bool) int8 {
|
||
if b {
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func maskOpenID(openid string) string {
|
||
if len(openid) <= 8 {
|
||
return openid
|
||
}
|
||
return openid[:4] + "****" + openid[len(openid)-4:]
|
||
}
|
||
|
||
// loadWechatBindNames 批量加载粉丝绑定对象名称:key = bindType#bindID#bindTid
|
||
func loadWechatBindNames(rows []models.WechatMpFollower) map[string]string {
|
||
names := map[string]string{}
|
||
if len(rows) == 0 {
|
||
return names
|
||
}
|
||
adminIDs := make([]uint64, 0)
|
||
tenantIDs := make([]uint64, 0)
|
||
for _, r := range rows {
|
||
switch r.BindType {
|
||
case models.WechatBindTypePlatformUser:
|
||
adminIDs = append(adminIDs, r.BindID)
|
||
case models.WechatBindTypeTenantUser:
|
||
tenantIDs = append(tenantIDs, r.BindID)
|
||
}
|
||
}
|
||
if len(adminIDs) > 0 {
|
||
var admins []models.AdminUser
|
||
if _, err := models.Orm.QueryTable(new(models.AdminUser)).Filter("id__in", adminIDs).All(&admins, "ID", "Account", "Name"); err == nil {
|
||
for _, a := range admins {
|
||
name := a.Account
|
||
if a.Name != nil && strings.TrimSpace(*a.Name) != "" {
|
||
name = *a.Name
|
||
}
|
||
names[models.WechatBindTypePlatformUser+"#"+fmt.Sprintf("%d", a.ID)+"#0"] = name
|
||
}
|
||
}
|
||
}
|
||
if len(tenantIDs) > 0 {
|
||
var users []models.SystemTenantUser
|
||
if _, err := models.Orm.QueryTable(new(models.SystemTenantUser)).Filter("uid__in", tenantIDs).All(&users, "UID", "Tid", "Account", "Name"); err == nil {
|
||
for _, u := range users {
|
||
name := ""
|
||
if u.Account != nil {
|
||
name = *u.Account
|
||
}
|
||
if u.Name != nil && strings.TrimSpace(*u.Name) != "" {
|
||
name = *u.Name
|
||
}
|
||
names[models.WechatBindTypeTenantUser+"#"+fmt.Sprintf("%d", u.Uid)+"#"+fmt.Sprintf("%d", u.Tid)] = name
|
||
}
|
||
}
|
||
}
|
||
return names
|
||
}
|