feat: many

This commit is contained in:
wangfuduo 2026-07-08 17:13:18 +08:00
parent ca93be0371
commit 7463e2dacd
10 changed files with 144 additions and 66 deletions

View File

@ -24,7 +24,7 @@ type PkgDelete struct {
} }
type PkgCreate struct { type PkgCreate struct {
Name string `json:"package_name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
Expire string `json:"expire"` Expire string `json:"expire"`
Link string `json:"link"` Link string `json:"link"`

View File

@ -3,7 +3,6 @@ package response
import ( import (
"fmt" "fmt"
"time" "time"
"twin-api/base/config"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -12,6 +11,7 @@ type Button struct {
Color string `json:"-"` Color string `json:"-"`
Text string `json:"text"` Text string `json:"text"`
Url string `json:"url"` Url string `json:"url"`
Type string `json:"type"`
} }
type Window struct { type Window struct {
@ -20,8 +20,8 @@ type Window struct {
} }
type Data struct { type Data struct {
Buttons []Button `json:"buttons"` Buttons []*Button `json:"buttons"`
Window Window `json:"window"` Window Window `json:"window"`
} }
type Response struct { type Response struct {
@ -45,20 +45,20 @@ func New(ctx *gin.Context, code int, message string) *Response {
response.Code = code response.Code = code
response.Msg = message response.Msg = message
response.Trace = trace response.Trace = trace
response.Data.Buttons = make([]Button, 0) response.Data.Buttons = make([]*Button, 0)
response.Data.Window = Window{Title: "温馨提示", Close: true} response.Data.Window = Window{Title: "温馨提示", Close: true}
return response return response
} }
func (r *Response) Success(ctx *gin.Context) *Response { func (r *Response) Button(b ...*Button) *Response {
resp := New(ctx, config.Success, "success") if len(b) > 1 {
resp.Window(&Window{Title: "", Close: true}) r.Data.Buttons = append(r.Data.Buttons[:0], b...)
resp.Data.Buttons = make([]Button, 0) }
return resp
} if len(b) == 1 {
r.Data.Buttons = append(r.Data.Buttons, b...)
}
func (r *Response) Botton(b *Button) *Response {
r.Data.Buttons = append(r.Data.Buttons, *b)
return r return r
} }
@ -70,3 +70,8 @@ func (r *Response) Window(win *Window) *Response {
r.Data.Window.Close = win.Close r.Data.Window.Close = win.Close
return r return r
} }
func (r *Response) Message(message string) *Response {
r.Msg = message
return r
}

41
app/api/service/button.go Normal file
View File

@ -0,0 +1,41 @@
package service
import (
"twin-api/app/api/response"
"twin-api/base/config"
)
type Button struct {
param map[string]any
}
func New(param map[string]any) *Button {
b := new(Button)
b.param = param
return b
}
func (b *Button) CouponButton() []*response.Button {
button := new(response.Button)
button.Url = b.param[config.ServiceVipExpireUrl].(string)
button.Type = config.ButtonInput
submitBtn := new(response.Button)
submitBtn.Text = "提交"
submitBtn.Type = config.ButtonClick
customBtn := new(response.Button)
customBtn.Text = b.param[config.ButtonTxtContractCustomer].(string)
customBtn.Type = config.ButtonClick
return []*response.Button{button, submitBtn, customBtn}
}
func (b *Button) PayButton() []*response.Button {
button := new(response.Button)
button.Text = b.param[config.ServiceVipExpireButton].(string)
button.Url = b.param[config.ServiceVipExpireUrl].(string)
button.Type = config.ButtonInput
return []*response.Button{button}
}

View File

@ -49,12 +49,14 @@ func NewUser(ctx *gin.Context) *User {
// 判断包是否提示强制更新 // 判断包是否提示强制更新
// 判断包是否提示更新 // 判断包是否提示更新
func (u *User) Verify() *response.Response { func (u *User) success() *response.Response {
// 检查免费使用时间 resp := response.New(u.ctx, config.Success, "success")
if resp := u.FreeCheck(); resp != nil { resp.Window(&response.Window{Title: "", Close: true})
return resp resp.Data.Buttons = make([]*response.Button, 0)
} return resp
}
func (u *User) Verify() *response.Response {
// 检查会员状况 // 检查会员状况
if resp := u.VipCheck(); resp != nil { if resp := u.VipCheck(); resp != nil {
return resp return resp
@ -64,30 +66,7 @@ func (u *User) Verify() *response.Response {
return resp return resp
} }
resp := response.New(u.ctx, config.Success, "success") return u.success()
resp.Window(&response.Window{Title: "", Close: true})
resp.Data.Buttons = make([]response.Button, 0)
return resp
}
func (u *User) FreeCheck() *response.Response {
var resp *response.Response
free := time.Unix(u.sess.GetUserInfo().ActiveTime, 0).AddDate(0, 0, cast.ToInt(u.params[config.ServiceFreeDay]))
if free.Unix() >= time.Now().Unix() {
// 提示需要充值
resp = response.New(u.ctx, config.VipExpire, u.params[config.ServiceVipExpireNotice].(string))
button := &response.Button{
Text: u.params[config.ServiceVipExpireButton].(string),
Url: u.params[config.ServiceVipExpireUrl].(string),
}
window := &response.Window{Close: false}
resp.Botton(button)
resp.Window(window)
return resp
}
return resp
} }
func (u *User) VipCheck() *response.Response { func (u *User) VipCheck() *response.Response {
@ -97,15 +76,35 @@ func (u *User) VipCheck() *response.Response {
return nil return nil
} }
free := time.Unix(u.sess.GetUserInfo().ActiveTime, 0).AddDate(0, 0, cast.ToInt(u.params[config.ServiceFreeDay])).Unix()
if free-u.sess.GetUserInfo().ActiveTime > 0 {
return nil
}
//
if expire < time.Now().Unix() { if expire < time.Now().Unix() {
resp = response.New(u.ctx, config.VipExpire, u.params[config.ServiceVipExpireNotice].(string)) resp = response.New(u.ctx, config.VipExpire, u.params[config.ServiceVipExpireNotice].(string))
button := &response.Button{
Text: u.params[config.ServiceVipExpireButton].(string),
Url: u.params[config.ServiceVipExpireUrl].(string),
}
window := &response.Window{Close: false} window := &response.Window{Close: false}
resp.Botton(button)
resp.Window(window) resp.Window(window)
buttons := make([]*response.Button, 0)
// 首次支付按钮
if u.sess.GetUserInfo().VipCreateTime == 0 {
if u.params[config.ServiceFirstPayWay] == config.FirstRechargeByCoupon {
resp.Message(u.params[config.ServerCouponNotice].(string))
buttons = append(buttons, New(u.params).CouponButton()...)
} else {
buttons = append(buttons, New(u.params).PayButton()...)
}
} else {
if u.params[config.ServicePayWay] == config.FirstRechargeByCoupon {
resp.Message(u.params[config.ServerCouponNotice].(string))
buttons = append(buttons, New(u.params).CouponButton()...)
} else {
buttons = append(buttons, New(u.params).PayButton()...)
}
}
resp.Button(buttons...)
} }
return resp return resp
@ -134,9 +133,10 @@ func (u *User) PkgCheck() *response.Response {
button := &response.Button{ button := &response.Button{
Text: u.params[config.ServicePackageLackButton].(string), Text: u.params[config.ServicePackageLackButton].(string),
Url: u.params[config.ServicePackageLackUrl].(string), Url: u.params[config.ServicePackageLackUrl].(string),
Type: config.ButtonClick,
} }
window := &response.Window{Close: false} window := &response.Window{Close: false}
resp.Botton(button) resp.Button(button)
resp.Window(window) resp.Window(window)
return resp return resp
@ -196,9 +196,10 @@ func (u *User) expireCheck(userPkg *model.UserPkgInfo, day int) *response.Respon
button := &response.Button{ button := &response.Button{
Text: u.params[config.ServiceInstallButton].(string), Text: u.params[config.ServiceInstallButton].(string),
Url: pkg.Link, Url: pkg.Link,
Type: config.ButtonClick,
} }
window := &response.Window{Close: false} window := &response.Window{Close: false}
resp.Botton(button) resp.Button(button)
resp.Window(window) resp.Window(window)
} }

View File

@ -13,6 +13,7 @@ import (
) )
func UserPkg(ctx *gin.Context) { func UserPkg(ctx *gin.Context) {
ctx.Keys[config.TraceId] = fmt.Sprintf("trace_id:%d", time.Now().UnixNano())
sess, ok := ctx.Keys[session.ContextSession].(*session.ApiSession) sess, ok := ctx.Keys[session.ContextSession].(*session.ApiSession)
if !ok { if !ok {
panic(config.ErrInternal.New().Append("user_pkg: error user")) panic(config.ErrInternal.New().Append("user_pkg: error user"))
@ -41,6 +42,10 @@ func UserPkg(ctx *gin.Context) {
panic(config.ErrParam.New().Append(fmt.Sprintf("user_pkg: error pkg: %s version %s", header.Package, header.Version))) panic(config.ErrParam.New().Append(fmt.Sprintf("user_pkg: error pkg: %s version %s", header.Package, header.Version)))
} }
if pkg.ExpireTime < time.Now().Unix() {
panic(config.ErrPkgExpire.New())
}
userPkg := &model.UserPkg{} userPkg := &model.UserPkg{}
userPkg.UserId = sess.GetUserId() userPkg.UserId = sess.GetUserId()
userPkg.PackageId = pkg.Id userPkg.PackageId = pkg.Id

View File

@ -32,8 +32,8 @@ func (p *Pkg) Format() map[string]any {
res["link"] = p.Link res["link"] = p.Link
res["status"] = p.Status res["status"] = p.Status
res["expire"] = gsUtils.TimeToDateTime(p.ExpireTime) res["expire"] = gsUtils.TimeToDateTime(p.ExpireTime)
res["create_date"] = gsUtils.TimeToDateTime(p.CreateTime) res["create_time"] = gsUtils.TimeToDateTime(p.CreateTime)
res["update_date"] = gsUtils.TimeToDateTime(p.UpdateTime) res["update_time"] = gsUtils.TimeToDateTime(p.UpdateTime)
return res return res
} }

View File

@ -23,7 +23,7 @@ func InitRouter(engine *gin.Engine) {
// 客户端接口路由 // 客户端接口路由
func initApiRouter(engine *gin.Engine) { func initApiRouter(engine *gin.Engine) {
base := new(gsApiController.BaseController) base := new(gsApiController.BaseController)
userGroup := engine.Group("/api/user").Use(base.Recovery).Use(base.Before).Use(base.Token).Use(base.IpLimit).Use(base.Response).Use(middle.UserPkg) userGroup := engine.Group("/api").Use(base.Recovery).Use(base.Before).Use(base.Token).Use(base.IpLimit).Use(base.Response).Use(middle.UserPkg)
userApi := new(controller.User) userApi := new(controller.User)
userGroup.GET("/verify", userApi.Verify) userGroup.GET("/verify", userApi.Verify)

View File

@ -7,3 +7,16 @@ const (
NoPkg = 30002 NoPkg = 30002
NeedUpgrade = 30003 NeedUpgrade = 30003
) )
const (
TraceId = "trace_id"
)
const (
FirstRechargeByCoupon = "coupon"
)
const (
ButtonClick = "click"
ButtonInput = "input"
)

View File

@ -16,4 +16,6 @@ var (
ErrParam = errors.T(11000, "参数错误") ErrParam = errors.T(11000, "参数错误")
ErrNoData = errors.T(11001, "数据不存在") ErrNoData = errors.T(11001, "数据不存在")
ErrExist = errors.T(11002, "数据已存在") ErrExist = errors.T(11002, "数据已存在")
ErrPkgExpire = errors.T(30004, "包已过期")
) )

View File

@ -20,21 +20,32 @@ const (
ServiceContactCustomer = "service.contact.customer" // 联系客服提示语 ServiceContactCustomer = "service.contact.customer" // 联系客服提示语
ServiceInstallButton = "service.install.button" // 安装按钮提示 ServiceInstallButton = "service.install.button" // 安装按钮提示
ServiceFirstPayWay = "service.first.pay.way" // 首次激活的支付方式
ServicePayWay = "service.pay.way" // 后续的支付方式
ServerCouponNotice = "service.coupon.notice" // 激活码兑换
)
const (
ButtonTxtContractCustomer = "service.button.contract.customer" // 联系客服按钮文字
) )
var KeysDefault = map[string]any{ var KeysDefault = map[string]any{
ServiceFreeDay: "1", ServiceFreeDay: "1",
ServiceUpdateBeforeDay: "30", ServiceUpdateBeforeDay: "30",
ServiceForceUpdateDay: "7", ServiceForceUpdateDay: "7",
ServiceVipExpireNotice: "您的会员已过期,请联系客服充值", ServiceVipExpireNotice: "您的会员已过期,请联系客服充值",
ServiceUpdateNotice: "您的包将于%s到期请你前往AppStore更新应用", ServiceUpdateNotice: "您的包将于%s到期请你前往AppStore更新应用",
ServiceUpdateOtherNotice: "您需要下载新的应用,请注意备份聊天记录", ServiceUpdateOtherNotice: "您需要下载新的应用,请注意备份聊天记录",
ServiceForceUpdateNotice: "请您先备份好聊天记录再前往AppStore更新应用。否则数据会丢失", ServiceForceUpdateNotice: "请您先备份好聊天记录再前往AppStore更新应用。否则数据会丢失",
ServiceVipExpireButton: "充值", ServiceVipExpireButton: "充值",
ServiceVipExpireUrl: "", ServiceVipExpireUrl: "",
ServiceUserPackageLack: "请您重新安装", ServiceUserPackageLack: "请您重新安装",
ServicePackageLackButton: "安装", ServicePackageLackButton: "安装",
ServicePackageLackUrl: "", ServicePackageLackUrl: "",
ServiceContactCustomer: "安装包缺失请联系客服解决all@batiao8.com", ServiceContactCustomer: "安装包缺失请联系客服解决all@batiao8.com",
ServiceInstallButton: "安装", ServiceInstallButton: "安装",
ServiceFirstPayWay: "coupon", // coupon | recharge
ServicePayWay: "coupon",
ServerCouponNotice: "请输入兑换码",
ButtonTxtContractCustomer: "联系客服",
} }