This commit is contained in:
Mrx
2026-02-09 18:10:23 +08:00
parent a8ec1a5aa1
commit c416c44c0c
9 changed files with 133 additions and 9 deletions

View File

@@ -121,6 +121,14 @@ type (
GetInviteLinkResp { GetInviteLinkResp {
InviteLink string `json:"invite_link"` // 邀请链接 InviteLink string `json:"invite_link"` // 邀请链接
} }
// 生成邀请海报(背景图+二维码,返回 base64
GetInvitePosterReq {
InviteLink string `form:"invite_link"` // 邀请链接(短链)
Format string `form:"format,optional"` // 返回格式base64默认
}
GetInvitePosterResp {
PosterBase64 string `json:"poster_base64"` // 海报图片 base64不含 data:image/png;base64, 前缀)
}
// 获取代理等级特权信息 // 获取代理等级特权信息
GetLevelPrivilegeResp { GetLevelPrivilegeResp {
Levels []LevelPrivilegeItem `json:"levels"` Levels []LevelPrivilegeItem `json:"levels"`
@@ -244,6 +252,10 @@ service main {
@handler GetInviteLink @handler GetInviteLink
get /invite_link (GetInviteLinkReq) returns (GetInviteLinkResp) get /invite_link (GetInviteLinkReq) returns (GetInviteLinkResp)
// 生成邀请海报(背景图+邀请链接二维码)
@handler GetInvitePoster
get /invite/poster (GetInvitePosterReq) returns (GetInvitePosterResp)
// 获取代理等级特权信息 // 获取代理等级特权信息
@handler GetLevelPrivilege @handler GetLevelPrivilege
get /level/privilege returns (GetLevelPrivilegeResp) get /level/privilege returns (GetLevelPrivilegeResp)

View File

@@ -58,8 +58,8 @@ WechatH5:
AppID: "wxb786749edb73eb04" AppID: "wxb786749edb73eb04"
AppSecret: "b2aad5ec8788eb1e74a3c385dd5aa282" AppSecret: "b2aad5ec8788eb1e74a3c385dd5aa282"
WechatMini: WechatMini:
AppID: "xxx" # 小程序的AppID AppID: "wxc17ebfe0d5b832b0" # 小程序的AppID
AppSecret: "xxxx" # 小程序的AppSecret AppSecret: "92100f1fbad05309635cea0671d37995" # 小程序的AppSecret
Query: Query:
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒 ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
AdminConfig: AdminConfig:

View File

@@ -55,8 +55,8 @@ WechatH5:
AppID: "wxb786749edb73eb04" AppID: "wxb786749edb73eb04"
AppSecret: "b2aad5ec8788eb1e74a3c385dd5aa282" AppSecret: "b2aad5ec8788eb1e74a3c385dd5aa282"
WechatMini: WechatMini:
AppID: "xxx" # 小程序的AppID AppID: "wxc17ebfe0d5b832b0" # 小程序的AppID
AppSecret: "xxxx" # 小程序的AppSecret AppSecret: "92100f1fbad05309635cea0671d37995" # 小程序的AppSecret
Query: Query:
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒 ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
AdminConfig: AdminConfig:

View File

@@ -0,0 +1,30 @@
package agent
import (
"net/http"
"bdqr-server/app/main/api/internal/logic/agent"
"bdqr-server/app/main/api/internal/svc"
"bdqr-server/app/main/api/internal/types"
"bdqr-server/common/result"
"bdqr-server/pkg/lzkit/validator"
"github.com/zeromicro/go-zero/rest/httpx"
)
func GetInvitePosterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetInvitePosterReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := agent.NewGetInvitePosterLogic(r.Context(), svcCtx)
resp, err := l.GetInvitePoster(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -661,6 +661,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/invite_link", Path: "/invite_link",
Handler: agent.GetInviteLinkHandler(serverCtx), Handler: agent.GetInviteLinkHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/invite/poster",
Handler: agent.GetInvitePosterHandler(serverCtx),
},
{ {
Method: http.MethodGet, Method: http.MethodGet,
Path: "/level/privilege", Path: "/level/privilege",

View File

@@ -0,0 +1,66 @@
package agent
import (
"context"
"encoding/base64"
"strings"
"bdqr-server/app/main/model"
"bdqr-server/common/ctxdata"
"bdqr-server/common/xerr"
"github.com/pkg/errors"
"bdqr-server/app/main/api/internal/svc"
"bdqr-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetInvitePosterLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetInvitePosterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInvitePosterLogic {
return &GetInvitePosterLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetInvitePosterLogic) GetInvitePoster(req *types.GetInvitePosterReq) (resp *types.GetInvitePosterResp, err error) {
// 1. 需登录且为代理
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
}
_, err = l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
}
// 2. 邀请链接不能为空
inviteLink := strings.TrimSpace(req.InviteLink)
if inviteLink == "" {
return nil, errors.Wrapf(xerr.NewErrMsg("邀请链接不能为空"), "")
}
// 3. 调用 ImageService 生成邀请海报(背景图 + 二维码)
imgData, _, err := l.svcCtx.ImageService.ProcessImageWithQRCode("invitation", inviteLink)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成海报失败: %v", err)
}
// 4. 返回 base64
posterBase64 := base64.StdEncoding.EncodeToString(imgData)
return &types.GetInvitePosterResp{
PosterBase64: posterBase64,
}, nil
}

View File

@@ -26,13 +26,13 @@ func NewImageService() *ImageService {
// ProcessImageWithQRCode 处理图片,在中间添加二维码 // ProcessImageWithQRCode 处理图片,在中间添加二维码
func (s *ImageService) ProcessImageWithQRCode(qrcodeType, qrcodeUrl string) ([]byte, string, error) { func (s *ImageService) ProcessImageWithQRCode(qrcodeType, qrcodeUrl string) ([]byte, string, error) {
// 1. 根据qrcodeType确定使用哪张背景图 // 1. 根据qrcodeType确定使用哪张背景图(与 uniapp_ycc/src/static/invitation 下海报一致,需复制到本目录 static/images
var backgroundImageName string var backgroundImageName string
switch qrcodeType { switch qrcodeType {
case "promote": case "promote":
backgroundImageName = "tg_qrcode_1.png" backgroundImageName = "tg_qrcode_1.png"
case "invitation": case "invitation":
backgroundImageName = "yq_qrcode_1.png" backgroundImageName = "invitation_01.png" // 与 uniapp static/invitation/invitation_01.png 同一张图,部署时拷贝到 static/images
default: default:
backgroundImageName = "tg_qrcode_1.png" // 默认使用第一张图片 backgroundImageName = "tg_qrcode_1.png" // 默认使用第一张图片
} }
@@ -79,10 +79,10 @@ func (s *ImageService) ProcessImageWithQRCode(qrcodeType, qrcodeUrl string) ([]b
case "invitation": case "invitation":
// invitation类型精确设置二维码尺寸 // invitation类型精确设置二维码尺寸
qrSize = 360 // 固定尺寸320px qrSize = 138 // 固定尺寸320px
// 中间偏上位置 // 中间偏上位置
qrX = (imgWidth - qrSize) / 2 // 水平居中 qrX = (imgWidth - qrSize) / 2 // 水平居中
qrY = 555 // 垂直位置200px qrY = 140 // 垂直位置200px
default: default:
// 默认promote样式 // 默认promote样式
@@ -162,7 +162,7 @@ func (s *ImageService) CheckImageExists(qrcodeType string) bool {
case "promote": case "promote":
backgroundImageName = "tg_qrcode_1.png" backgroundImageName = "tg_qrcode_1.png"
case "invitation": case "invitation":
backgroundImageName = "yq_qrcode_1.png" backgroundImageName = "invitation_01.png"
default: default:
backgroundImageName = "tg_qrcode_1.png" backgroundImageName = "tg_qrcode_1.png"
} }

View File

@@ -116,6 +116,17 @@ type GetInviteLinkResp struct {
InviteLink string `json:"invite_link"` // 邀请链接 InviteLink string `json:"invite_link"` // 邀请链接
} }
// GetInvitePosterReq 生成邀请海报请求(邀请链接 + 可选 format=base64
type GetInvitePosterReq struct {
InviteLink string `form:"invite_link"` // 邀请链接(短链)
Format string `form:"format,optional"` // 返回格式base64默认
}
// GetInvitePosterResp 生成邀请海报响应
type GetInvitePosterResp struct {
PosterBase64 string `json:"poster_base64"` // 海报图片 base64不含 data:image/png;base64, 前缀)
}
type GetLevelPrivilegeResp struct { type GetLevelPrivilegeResp struct {
Levels []LevelPrivilegeItem `json:"levels"` Levels []LevelPrivilegeItem `json:"levels"`
UpgradeToGoldFee float64 `json:"upgrade_to_gold_fee"` UpgradeToGoldFee float64 `json:"upgrade_to_gold_fee"`

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB