feat: rbac迁移完成,并已部署至dev服务器

This commit is contained in:
Blizzard
2026-05-01 01:19:50 +08:00
parent f80a3dc064
commit 8b11068fef
250 changed files with 6314 additions and 13072 deletions
+9
View File
@@ -0,0 +1,9 @@
.git
.gitignore
.idea
.vscode
deploy
docs
*.md
*.yaml
*.yml
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoImports">
<option name="excludedPackages">
<array>
<option value="golang.org/x/net/context" />
</array>
</option>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sundynix-micro-go.iml" filepath="$PROJECT_DIR$/.idea/sundynix-micro-go.iml" />
</modules>
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="auth-api" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/auth/api" />
<parameters value="-f etc/auth-api.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/auth/api/auth.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="file-api" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/file/api" />
<parameters value="-f etc/file-api.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/file/api/file.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="file-rpc" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/file/rpc" />
<parameters value="-f etc/file.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/file/rpc/file.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="gateway" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/gateway" />
<parameters value="-f etc/gateway.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/gateway/gateway.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="plant-api" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/plant/api" />
<parameters value="-f etc/plant-api.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/plant/api/plant.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="plant-rpc" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/plant/rpc" />
<parameters value="-f etc/plant.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/plant/rpc/plant.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="system-api" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/system/api" />
<parameters value="-f etc/system-api.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/system/api/system.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="system-rpc" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/system/rpc" />
<parameters value="-f etc/system.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/system/rpc/system.go" />
<method v="2" />
</configuration>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="zero-gateway" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="sundynix-micro-go" />
<working_directory value="$PROJECT_DIR$/app/zero-gateway" />
<parameters value="-f etc/zero-gateway.yaml" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/app/zero-gateway/zero-gateway.go" />
<method v="2" />
</configuration>
</component>
+18 -15
View File
@@ -23,6 +23,13 @@ type (
LoginReq {
Account string `json:"account"`
Password string `json:"password"`
CaptchaId string `json:"captchaId"`
Captcha string `json:"captcha"`
}
// 验证码响应
CaptchaResp {
CaptchaId string `json:"captchaId"`
CaptchaImg string `json:"captchaImg"`
}
// 登录响应
LoginResp {
@@ -70,10 +77,10 @@ type (
// ========== 无需鉴权的接口 ==========
@server (
prefix: /api/user
prefix: /api/auth
group: auth
)
service user-api {
service auth-api {
@doc "微信小程序登录"
@handler MiniLogin
post /miniLogin (MiniLoginReq) returns (LoginResp)
@@ -85,34 +92,30 @@ service user-api {
@doc "账号密码登录"
@handler Login
post /login (LoginReq) returns (LoginResp)
@doc "获取图形验证码"
@handler GetCaptcha
get /captcha returns (CaptchaResp)
}
// ========== 需要鉴权的接口 ==========
@server (
prefix: /api/user
prefix: /api/auth
group: user
jwt: Auth
)
service user-api {
service auth-api {
@doc "获取当前用户信息"
@handler GetUserInfo
get /info returns (LoginResp)
@doc "更新用户信息"
@doc "更新个人信息"
@handler UpdateUser
put /update (UpdateUserReq)
post /update (UpdateUserReq)
@doc "修改密码"
@handler ChangePassword
put /changePassword (ChangePasswordReq)
@doc "用户列表"
@handler GetUserList
post /list (UserListReq)
@doc "删除用户"
@handler DeleteUser
delete /delete (IdsReq)
post /changePassword (ChangePasswordReq)
@doc "获取位置信息"
@handler GetLocation
@@ -7,18 +7,20 @@ import (
"flag"
"fmt"
"sundynix-micro-go/app/user/api/internal/config"
"sundynix-micro-go/app/user/api/internal/handler"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/config"
"sundynix-micro-go/app/auth/api/internal/handler"
"sundynix-micro-go/app/auth/api/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/user-api.yaml", "the config file")
var configFile = flag.String("f", "etc/auth-api.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog() //去掉state日志
var c config.Config
conf.MustLoad(*configFile, &c)
+23
View File
@@ -0,0 +1,23 @@
Name: auth-api
Log:
Encoding: plain
Host: 0.0.0.0
Port: 9001
Auth:
AccessSecret: 9149f2eb-d517-4a50-a03a-231dbcf0d872
AccessExpire: 7200
# system-rpc(统一管理用户/角色/菜单/客户端等)
SystemRpc:
Etcd:
Hosts:
- 192.168.100.127:2379
Key: system.rpc
# Redis(验证码存储,DB2
Redis:
Host: 192.168.100.127:6379
Pass: sundynix
DB: 2
@@ -1,6 +1,3 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package config
import (
@@ -14,5 +11,10 @@ type Config struct {
AccessSecret string
AccessExpire int64
}
UserRpc zrpc.RpcClientConf
SystemRpc zrpc.RpcClientConf
Redis struct {
Host string
Pass string
DB int `json:",optional"`
}
}
@@ -0,0 +1,22 @@
package auth
import (
"net/http"
"sundynix-micro-go/app/auth/api/internal/logic/auth"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/common/response"
)
// 获取图形验证码
func GetCaptchaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := auth.NewGetCaptchaLogic(r.Context(), svcCtx)
resp, err := l.GetCaptcha()
if err != nil {
response.Fail(w, err.Error())
} else {
response.OkWithData(w, resp)
}
}
}
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/auth"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/auth"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -1,15 +1,12 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/auth"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/auth"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -23,6 +20,7 @@ func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
}
l := auth.NewLoginLogic(r.Context(), svcCtx)
l.SetRequest(r) // 注入 http.Request 以便取 X-Client-Id 请求头
resp, err := l.Login(&req)
if err != nil {
response.Fail(w, err.Error())
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/auth"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/auth"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -6,9 +6,9 @@ package handler
import (
"net/http"
auth "sundynix-micro-go/app/user/api/internal/handler/auth"
user "sundynix-micro-go/app/user/api/internal/handler/user"
"sundynix-micro-go/app/user/api/internal/svc"
auth "sundynix-micro-go/app/auth/api/internal/handler/auth"
user "sundynix-micro-go/app/auth/api/internal/handler/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
@@ -16,6 +16,12 @@ import (
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// 获取图形验证码
Method: http.MethodGet,
Path: "/captcha",
Handler: auth.GetCaptchaHandler(serverCtx),
},
{
// 账号密码登录
Method: http.MethodPost,
@@ -35,35 +41,23 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Handler: auth.MiniLoginHandler(serverCtx),
},
},
rest.WithPrefix("/api/user"),
rest.WithPrefix("/api/auth"),
)
server.AddRoutes(
[]rest.Route{
{
// 修改密码
Method: http.MethodPut,
Method: http.MethodPost,
Path: "/changePassword",
Handler: user.ChangePasswordHandler(serverCtx),
},
{
// 删除用户
Method: http.MethodDelete,
Path: "/delete",
Handler: user.DeleteUserHandler(serverCtx),
},
{
// 获取当前用户信息
Method: http.MethodGet,
Path: "/info",
Handler: user.GetUserInfoHandler(serverCtx),
},
{
// 用户列表
Method: http.MethodPost,
Path: "/list",
Handler: user.GetUserListHandler(serverCtx),
},
{
// 获取位置信息
Method: http.MethodGet,
@@ -71,8 +65,8 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Handler: user.GetLocationHandler(serverCtx),
},
{
// 更新用户信息
Method: http.MethodPut,
// 更新个人信息
Method: http.MethodPost,
Path: "/update",
Handler: user.UpdateUserHandler(serverCtx),
},
@@ -84,6 +78,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/user"),
rest.WithPrefix("/api/auth"),
)
}
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/user"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/user"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -6,8 +6,8 @@ package user
import (
"net/http"
"sundynix-micro-go/app/user/api/internal/logic/user"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/logic/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/common/response"
)
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/user"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -7,9 +7,9 @@ import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/user/api/internal/logic/user"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/logic/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/response"
)
@@ -0,0 +1,33 @@
package auth
import (
"context"
"fmt"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"sundynix-micro-go/common/utils/captcha"
"github.com/zeromicro/go-zero/core/logx"
)
type GetCaptchaLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCaptchaLogic {
return &GetCaptchaLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
}
func (l *GetCaptchaLogic) GetCaptcha() (resp *types.CaptchaResp, err error) {
id, b64s, err := captcha.Generate()
if err != nil {
return nil, fmt.Errorf("生成验证码失败")
}
return &types.CaptchaResp{
CaptchaId: id,
CaptchaImg: b64s,
}, nil
}
@@ -10,14 +10,11 @@ import (
"io"
"net/http"
"net/url"
"time"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/user/rpc/user"
jwtUtil "sundynix-micro-go/common/utils/jwt"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
sysPb "sundynix-micro-go/app/system/rpc/system"
jwtv5 "github.com/golang-jwt/jwt/v5"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -58,7 +55,7 @@ func (l *LoginByPhoneLogic) LoginByPhone(req *types.LoginByPhoneReq) (resp *type
_ = url.Values{}
// 2. 通过 user-rpc 查询用户
userResp, err := l.svcCtx.UserRpc.GetUserByOpenId(l.ctx, &user.GetUserByOpenIdReq{
userResp, err := l.svcCtx.SystemRpc.GetUserByOpenId(l.ctx, &sysPb.GetUserByOpenIdReq{
OpenId: req.OpenId,
})
if err != nil {
@@ -70,7 +67,7 @@ func (l *LoginByPhoneLogic) LoginByPhone(req *types.LoginByPhoneReq) (resp *type
if ok {
phoneNumber, _ := phoneInfo["phoneNumber"].(string)
if phoneNumber != "" && userResp.User.Phone == "" {
_, _ = l.svcCtx.UserRpc.UpdateUser(l.ctx, &user.UpdateUserReq{
_, _ = l.svcCtx.SystemRpc.UpdateUser(l.ctx, &sysPb.UpdateUserReq{
Id: userResp.User.Id,
Phone: phoneNumber,
})
@@ -78,20 +75,11 @@ func (l *LoginByPhoneLogic) LoginByPhone(req *types.LoginByPhoneReq) (resp *type
}
}
// 4. 生成Token
j := jwtUtil.NewJWT(l.svcCtx.Config.Auth.AccessSecret)
claims := jwtUtil.CustomClaims{
BaseClaims: jwtUtil.BaseClaims{
ID: userResp.User.Id,
Account: userResp.User.Account,
},
BufferTime: 3600,
RegisteredClaims: jwtv5.RegisteredClaims{
ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(time.Duration(l.svcCtx.Config.Auth.AccessExpire) * time.Second)),
Issuer: "sundynix",
},
// 4. 生成Token(复用统一的 generateToken 函数)
token, err := generateToken(l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire, userResp.User)
if err != nil {
return nil, fmt.Errorf("生成Token失败")
}
token, _ := j.CreateToken(claims)
return &types.LoginResp{
Token: token,
@@ -0,0 +1,115 @@
package auth
import (
"context"
"fmt"
"net/http"
"time"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
sysPb "sundynix-micro-go/app/system/rpc/system"
"sundynix-micro-go/common/utils/captcha"
jwtUtil "sundynix-micro-go/common/utils/jwt"
jwtv5 "github.com/golang-jwt/jwt/v5"
"github.com/zeromicro/go-zero/core/logx"
)
type LoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
r *http.Request
}
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
return &LoginLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
}
// SetRequest 注入 http.Request 以便从请求头取 clientId
func (l *LoginLogic) SetRequest(r *http.Request) {
l.r = r
}
func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) {
// 1. 校验验证码
if !captcha.Verify(req.CaptchaId, req.Captcha) {
return nil, fmt.Errorf("验证码错误")
}
// 2. 从请求头获取 clientId
clientId := ""
if l.r != nil {
clientId = l.r.Header.Get("X-Client-Id")
}
if clientId == "" {
return nil, fmt.Errorf("缺少客户端标识")
}
// 3. 查询 Client 信息,获取 token 过期时间
clientResp, err := l.svcCtx.SystemRpc.GetClientById(l.ctx, &sysPb.GetClientByIdReq{ClientId: clientId})
if err != nil {
l.Errorf("[Login] ❌ 查询客户端失败 | clientId=%s | err=%v", clientId, err)
return nil, fmt.Errorf("无效的客户端标识,请确认 X-Client-Id 请求头是否正确")
}
activeTimeout := clientResp.Client.ActiveTimeout
if activeTimeout <= 0 {
activeTimeout = 7200
}
// 4. 调用 system-rpc 验证账号密码
rpcResp, err := l.svcCtx.SystemRpc.LoginByAccount(l.ctx, &sysPb.LoginByAccountReq{
Account: req.Account,
Password: req.Password,
})
if err != nil {
l.Errorf("[Login] ❌ 账号验证失败 | account=%s | err=%v", req.Account, err)
return nil, err
}
// 5. 签发 JWT Token
token, err := generateToken(l.svcCtx.Config.Auth.AccessSecret, activeTimeout, rpcResp.User)
if err != nil {
l.Errorf("[Login] ❌ 生成 Token 失败 | userId=%s | err=%v", rpcResp.User.Id, err)
return nil, err
}
l.Infof("[Login] ✅ 登录成功 | account=%s | userId=%s | clientId=%s | tokenExpire=%ds",
req.Account, rpcResp.User.Id, clientId, activeTimeout)
return &types.LoginResp{
Token: token,
UserInfo: map[string]interface{}{
"id": rpcResp.User.Id,
"name": rpcResp.User.Name,
"account": rpcResp.User.Account,
"nickName": rpcResp.User.NickName,
"phone": rpcResp.User.Phone,
"avatarId": rpcResp.User.AvatarId,
"gender": rpcResp.User.Gender,
},
}, nil
}
func generateToken(accessSecret string, activeTimeout int64, userInfo *sysPb.UserInfo) (string, error) {
j := jwtUtil.NewJWT(accessSecret)
claims := jwtUtil.CustomClaims{
BaseClaims: jwtUtil.BaseClaims{
ID: userInfo.Id,
Account: userInfo.Account,
},
BufferTime: 3600,
RegisteredClaims: jwtv5.RegisteredClaims{
Audience: jwtv5.ClaimStrings{"sundynix"},
NotBefore: jwtv5.NewNumericDate(time.Now().Add(-1000)),
ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(time.Duration(activeTimeout) * time.Second)),
Issuer: "sundynix",
},
}
token, err := j.CreateToken(claims)
if err != nil {
return "", fmt.Errorf("生成Token失败: %w", err)
}
return token, nil
}
@@ -10,14 +10,11 @@ import (
"io"
"net/http"
"net/url"
"time"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/user/rpc/user"
jwtUtil "sundynix-micro-go/common/utils/jwt"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
sysPb "sundynix-micro-go/app/system/rpc/system"
jwtv5 "github.com/golang-jwt/jwt/v5"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -87,7 +84,7 @@ func (l *MiniLoginLogic) MiniLogin(req *types.MiniLoginReq) (resp *types.LoginRe
}
// 2. 通过 user-rpc 创建或获取用户
createResp, err := l.svcCtx.UserRpc.CreateUser(l.ctx, &user.CreateUserReq{
createResp, err := l.svcCtx.SystemRpc.CreateUser(l.ctx, &sysPb.CreateUserReq{
Name: "",
OpenId: wxResp.Openid,
SessionKey: wxResp.SessionKey,
@@ -98,22 +95,8 @@ func (l *MiniLoginLogic) MiniLogin(req *types.MiniLoginReq) (resp *types.LoginRe
return nil, fmt.Errorf("登录失败")
}
// 3. 生成JWT Token
j := jwtUtil.NewJWT(l.svcCtx.Config.Auth.AccessSecret)
claims := jwtUtil.CustomClaims{
BaseClaims: jwtUtil.BaseClaims{
ID: createResp.User.Id,
Account: createResp.User.Account,
},
BufferTime: 3600,
RegisteredClaims: jwtv5.RegisteredClaims{
Audience: jwtv5.ClaimStrings{"sundynix"},
NotBefore: jwtv5.NewNumericDate(time.Now().Add(-1000)),
ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(time.Duration(l.svcCtx.Config.Auth.AccessExpire) * time.Second)),
Issuer: "sundynix",
},
}
token, err := j.CreateToken(claims)
// 3. 生成JWT Token(复用统一的 generateToken 函数)
token, err := generateToken(l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire, createResp.User)
if err != nil {
l.Errorf("生成Token失败: %v", err)
return nil, fmt.Errorf("登录失败")
@@ -6,8 +6,8 @@ package user
import (
"context"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -6,8 +6,8 @@ package user
import (
"context"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -0,0 +1,114 @@
package user
import (
"context"
"fmt"
"sort"
"sundynix-micro-go/app/auth/api/internal/svc"
sysPb "sundynix-micro-go/app/system/rpc/system"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserInfoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserInfoLogic {
return &GetUserInfoLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
}
func (l *GetUserInfoLogic) GetUserInfo() (resp interface{}, err error) {
// 1. 从 JWT claims 中获取 userId
userId := fmt.Sprintf("%v", l.ctx.Value("userId"))
if userId == "" || userId == "<nil>" {
return nil, fmt.Errorf("用户未登录")
}
// 2. 调用 system-rpc 获取用户基础信息
userResp, err := l.svcCtx.SystemRpc.GetUserById(l.ctx, &sysPb.GetUserByIdReq{Id: userId})
if err != nil {
l.Errorf("[GetUserInfo] ❌ 获取用户信息失败 | userId=%s | err=%v", userId, err)
return nil, fmt.Errorf("获取用户信息失败")
}
// 3. 获取用户角色列表
rolesResp, err := l.svcCtx.SystemRpc.GetRolesByUserId(l.ctx, &sysPb.GetRolesByUserIdReq{UserId: userId})
if err != nil {
l.Errorf("[GetUserInfo] ⚠️ 获取用户角色失败(已降级返回空角色) | userId=%s | err=%v", userId, err)
rolesResp = &sysPb.GetRolesByUserIdResp{Roles: []*sysPb.RoleInfo{}}
}
// 4. 根据角色获取菜单权限(合并所有角色的菜单)
menuMap := make(map[string]interface{})
var allMenus []interface{}
var roleCodes []string
for _, role := range rolesResp.Roles {
roleCodes = append(roleCodes, role.Code)
menusResp, err := l.svcCtx.SystemRpc.GetMenusByRoleId(l.ctx, &sysPb.GetMenusByRoleIdReq{RoleId: role.Id})
if err != nil {
l.Errorf("获取角色[%s]菜单失败: %v", role.Name, err)
continue
}
for _, m := range menusResp.Menus {
if _, exists := menuMap[m.Id]; !exists {
menuMap[m.Id] = true
allMenus = append(allMenus, convertMenuInfo(m))
}
}
}
// 5. 对顶层菜单进行重新排序,防止不同角色的合并打乱顺序
sort.Slice(allMenus, func(i, j int) bool {
m1 := allMenus[i].(map[string]interface{})
m2 := allMenus[j].(map[string]interface{})
s1 := m1["sort"].(int32)
s2 := m2["sort"].(int32)
return s1 < s2
})
// 5. 组装完整的用户信息返回
u := userResp.User
return map[string]interface{}{
"id": u.Id,
"name": u.Name,
"account": u.Account,
"nickName": u.NickName,
"phone": u.Phone,
"avatarId": u.AvatarId,
"gender": u.Gender,
"roles": roleCodes,
"menus": allMenus,
"createdAt": u.CreatedAt,
}, nil
}
// convertMenuInfo 将proto MenuInfo转为map
func convertMenuInfo(m *sysPb.MenuInfo) map[string]interface{} {
menu := map[string]interface{}{
"id": m.Id,
"parentId": m.ParentId,
"category": m.Category,
"name": m.Name,
"title": m.Title,
"code": m.Code,
"path": m.Path,
"permission": m.Permission,
"locale": m.Locale,
"icon": m.Icon,
"sort": m.Sort,
}
if len(m.Children) > 0 {
var children []map[string]interface{}
for _, child := range m.Children {
children = append(children, convertMenuInfo(child))
}
menu["children"] = children
}
return menu
}
@@ -6,8 +6,8 @@ package user
import (
"context"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -7,9 +7,9 @@ import (
"context"
"fmt"
"sundynix-micro-go/app/user/api/internal/svc"
"sundynix-micro-go/app/user/api/internal/types"
pb "sundynix-micro-go/app/user/rpc/user"
"sundynix-micro-go/app/auth/api/internal/svc"
"sundynix-micro-go/app/auth/api/internal/types"
sysPb "sundynix-micro-go/app/system/rpc/system"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -34,7 +34,7 @@ func (l *UpdateUserLogic) UpdateUser(req *types.UpdateUserReq) error {
return fmt.Errorf("用户未登录")
}
_, err := l.svcCtx.UserRpc.UpdateUser(l.ctx, &pb.UpdateUserReq{
_, err := l.svcCtx.SystemRpc.UpdateUser(l.ctx, &sysPb.UpdateUserReq{
Id: userId,
Name: req.Name,
Account: req.Account,
@@ -0,0 +1,32 @@
package svc
import (
"sundynix-micro-go/app/auth/api/internal/config"
"sundynix-micro-go/app/system/rpc/systemservice"
"sundynix-micro-go/common/utils/captcha"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
SystemRpc systemservice.SystemService
}
func NewServiceContext(c config.Config) *ServiceContext {
// 初始化 Redis 并注入验证码存储
rdb := redis.NewClient(&redis.Options{
Addr: c.Redis.Host,
Password: c.Redis.Pass,
DB: c.Redis.DB,
})
captcha.InitWithRedis(rdb)
logx.Infof("验证码存储已切换至 Redis (DB%d)", c.Redis.DB)
return &ServiceContext{
Config: c,
SystemRpc: systemservice.NewSystemService(zrpc.MustNewClient(c.SystemRpc)),
}
}
@@ -3,6 +3,11 @@
package types
type CaptchaResp struct {
CaptchaId string `json:"captchaId"`
CaptchaImg string `json:"captchaImg"`
}
type ChangePasswordReq struct {
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
@@ -30,6 +35,8 @@ type LoginByPhoneReq struct {
type LoginReq struct {
Account string `json:"account"`
Password string `json:"password"`
CaptchaId string `json:"captchaId"`
Captcha string `json:"captcha"`
}
type LoginResp struct {
+1 -1
View File
@@ -47,7 +47,7 @@ service file-api {
@doc "删除文件"
@handler DeleteFile
delete /delete (IdsReq)
post /delete (IdsReq)
@doc "文件列表"
@handler GetFileList
+2
View File
@@ -12,6 +12,7 @@ import (
"sundynix-micro-go/app/file/api/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/rest"
)
@@ -19,6 +20,7 @@ var configFile = flag.String("f", "etc/file-api.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog()
var c config.Config
conf.MustLoad(*configFile, &c)
+2
View File
@@ -11,6 +11,7 @@ import (
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/service"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
@@ -20,6 +21,7 @@ var configFile = flag.String("f", "etc/file.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog()
var c config.Config
conf.MustLoad(*configFile, &c)
+24 -7
View File
@@ -21,16 +21,33 @@ Cors:
- Content-Type
- Authorization
- X-Requested-With
- X-Client-Id
# system-rpc 连接(用于写入操作日志)
SystemRpc:
Etcd:
Hosts:
- 192.168.100.127:2379
Key: system.rpc
# JWT 密钥(与 user-api 的 Auth.AccessSecret 一致,用于解析 token 获取 userId
JwtSecret: "9149f2eb-d517-4a50-a03a-231dbcf0d872"
# 鉴权白名单(无需 Token 的路径,精确匹配或 /* 前缀通配)
AuthWhitelist:
- /api/auth/login
- /api/auth/loginByPhone
- /api/auth/miniLogin
- /api/auth/captcha
- /api/plant/callback/wechatpay
# 上游服务路由表
Upstreams:
- Prefix: /api/user
Target: http://127.0.0.1:9001
- Prefix: /api/auth
Target: http://192.168.100.2:9001
- Prefix: /api/file
Target: http://127.0.0.1:9002
Target: http://192.168.100.2:9002
- Prefix: /api/sys
Target: http://127.0.0.1:9003
Target: http://192.168.100.2:9003
- Prefix: /api/plant
Target: http://127.0.0.1:9004
- Prefix: /api/radio
Target: http://127.0.0.1:9005
Target: http://192.168.100.2:9004
+22 -1
View File
@@ -8,23 +8,34 @@ import (
"sundynix-micro-go/app/gateway/internal/config"
"sundynix-micro-go/app/gateway/internal/handler"
"sundynix-micro-go/app/gateway/internal/middleware"
"sundynix-micro-go/app/system/rpc/systemservice"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/zrpc"
)
var configFile = flag.String("f", "etc/gateway.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog()
var c config.Config
conf.MustLoad(*configFile, &c)
// 手动初始化日志(自定义 gateway 没用 rest.MustNewServer,需要显式设置)
logx.MustSetup(c.Log)
// 初始化 system-rpc 客户端(用于写操作日志)
systemRpc := systemservice.NewSystemService(zrpc.MustNewClient(c.SystemRpc))
// 构建反向代理路由器
proxyRouter := handler.NewProxyRouter(c.Upstreams)
// 构建请求处理链
// 构建中间件链(执行顺序:操作日志 → 鉴权 → CORS → 代理)
// 注意:由于是外层包内层,实际请求流程是:OpLog → Auth → CORS → Proxy → CORS → Auth → OpLog
var finalHandler http.Handler = proxyRouter
// 注入 CORS 中间件
@@ -35,6 +46,14 @@ func main() {
}))
}
// 注入 JWT 鉴权中间件(含滑动窗口续期)
authMiddleware := middleware.NewAuthMiddleware(c.JwtSecret, c.AuthWhitelist)
finalHandler = authMiddleware.Handle(finalHandler)
// 注入操作日志中间件(在最外层,记录完整的请求-响应周期,含鉴权状态)
opLogMiddleware := middleware.NewOperationLogMiddleware(systemRpc, c.JwtSecret)
finalHandler = opLogMiddleware.Handle(finalHandler)
// 健康检查
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
@@ -50,6 +69,8 @@ func main() {
for _, u := range c.Upstreams {
logx.Infof(" %s -> %s", u.Prefix, u.Target)
}
logx.Infof("中间件: CORS | JWT鉴权(滑动续期) | 操作日志→system-rpc")
logx.Infof("鉴权白名单: %d 条", len(c.AuthWhitelist))
logx.Infof("================================")
if err := http.ListenAndServe(addr, mux); err != nil {
+13 -1
View File
@@ -1,6 +1,9 @@
package config
import "github.com/zeromicro/go-zero/rest"
import (
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
rest.RestConf
@@ -13,6 +16,15 @@ type Config struct {
}
Upstreams []Upstream
// system-rpc 连接(用于写入操作日志)
SystemRpc zrpc.RpcClientConf
// JWT 密钥(用于解析 Token 获取 userId,与 user-api 的 Auth.AccessSecret 保持一致)
JwtSecret string `json:",optional"`
// 无需鉴权的路径白名单
AuthWhitelist []string `json:",optional"`
}
type Upstream struct {
+26 -4
View File
@@ -1,7 +1,9 @@
package handler
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
@@ -52,16 +54,35 @@ func NewProxyRouter(upstreams []config.Upstream) *ProxyRouter {
MaxIdleConns: 100,
MaxIdleConnsPerHost: 20,
IdleConnTimeout: 90 * time.Second,
ResponseHeaderTimeout: 30 * time.Second, // 上游响应头超时,超出则触发 ErrorHandler
}
// 错误处理
prefix := u.Prefix
targetAddr := u.Target
// ErrorHandler:处理网络层错误(连接失败、超时等)
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
logx.Errorf("代理请求失败 [%s%s -> %s]: %v", prefix, r.URL.Path, targetAddr, err)
logx.Errorf("[Gateway] ❌ 上游连接失败 | %s %s -> %s | 错误: %v",
r.Method, r.URL.Path, targetAddr, err)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusBadGateway)
fmt.Fprintf(w, `{"code":502,"msg":"上游服务不可用: %s"}`, prefix)
fmt.Fprintf(w, `{"code":502,"msg":"上游服务不可用,请检查 %s 是否正常运行"}`, prefix)
}
// ModifyResponse:捕获上游返回的 4xx/5xx 并记录日志(网络层正常但业务异常)
proxy.ModifyResponse = func(resp *http.Response) error {
if resp.StatusCode >= 500 {
// 读取响应体用于日志(最多 1KB,读完后要写回)
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
resp.Body = io.NopCloser(bytes.NewBuffer(body))
logx.Errorf("[Gateway] ⚠️ 上游服务异常 | %s %s -> %s | 状态码: %d | 响应: %s",
resp.Request.Method, resp.Request.URL.Path, targetAddr,
resp.StatusCode, string(body))
} else if resp.StatusCode >= 400 {
logx.Infof("[Gateway] ️ 上游返回客户端错误 | %s %s | 状态码: %d",
resp.Request.Method, resp.Request.URL.Path, resp.StatusCode)
}
return nil
}
router.routes = append(router.routes, &route{
@@ -82,13 +103,14 @@ func (pr *ProxyRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, rt := range pr.routes {
if strings.HasPrefix(path, rt.prefix) {
logx.Infof("[Gateway] %s %s -> %s", r.Method, path, rt.target)
logx.Infof("[Gateway] %s %s -> %s", r.Method, path, rt.target)
rt.proxy.ServeHTTP(w, r)
return
}
}
// 没有匹配的路由
logx.Errorf("[Gateway] ❌ 路由未找到: %s %s", r.Method, path)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, `{"code":404,"msg":"路由未找到: %s"}`, path)
+140
View File
@@ -0,0 +1,140 @@
package middleware
import (
"encoding/json"
"net/http"
"strings"
"time"
jwtUtil "sundynix-micro-go/common/utils/jwt"
jwtv5 "github.com/golang-jwt/jwt/v5"
"github.com/zeromicro/go-zero/core/logx"
)
// RefreshTokenHeader 续期后新 Token 放在此响应头里,前端读取后静默替换
const RefreshTokenHeader = "X-Refresh-Token"
// AuthMiddleware 网关鉴权 + 自动续期中间件
type AuthMiddleware struct {
jwtSecret string
whitelist map[string]bool
}
func NewAuthMiddleware(jwtSecret string, whitelist []string) *AuthMiddleware {
wl := make(map[string]bool, len(whitelist))
for _, p := range whitelist {
wl[p] = true
}
return &AuthMiddleware{
jwtSecret: jwtSecret,
whitelist: wl,
}
}
// Handle 适配 http.Handler 链(自定义 gateway 使用 http.Handler 链式调用)
func (m *AuthMiddleware) Handle(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// OPTIONS 预检直接放行
if r.Method == http.MethodOptions {
next.ServeHTTP(w, r)
return
}
// 白名单路径放行(支持精确匹配和 /* 前缀通配)
if m.isWhitelisted(r.URL.Path) {
next.ServeHTTP(w, r)
return
}
// 解析 Authorization 头
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
writeUnauthorized(w, "缺少 Authorization 请求头")
return
}
tokenStr := jwtUtil.GetTokenFromHeader(authHeader)
if tokenStr == "" {
writeUnauthorized(w, "Token 格式错误")
return
}
j := jwtUtil.NewJWT(m.jwtSecret)
claims, err := j.ParseToken(tokenStr)
if err != nil {
logx.Infof("[gateway] JWT 解析失败: %v, path: %s", err, r.URL.Path)
writeUnauthorized(w, err.Error())
return
}
// 将用户信息透传到上游,避免上游重复解析 JWT
r.Header.Set("X-User-Id", claims.BaseClaims.ID)
r.Header.Set("X-User-Account", claims.BaseClaims.Account)
// ---- 滑动窗口续期 ----
if newToken, ok := m.tryRefresh(j, claims); ok {
w.Header().Set(RefreshTokenHeader, newToken)
logx.Infof("[gateway] Token 已续期, userId: %s", claims.BaseClaims.ID)
}
next.ServeHTTP(w, r)
})
}
// tryRefresh 判断是否需要续期,需要则签发新 Token 并返回
// 续期规则:剩余有效时间 < BufferTime → 以原始有效时长(ExpiresAt - NotBefore)重新签发
func (m *AuthMiddleware) tryRefresh(j *jwtUtil.JWT, claims *jwtUtil.CustomClaims) (string, bool) {
bufferTime := time.Duration(claims.BufferTime) * time.Second
expiresAt := claims.RegisteredClaims.ExpiresAt.Time
remaining := time.Until(expiresAt)
// 未进入缓冲窗口,无需续期
if remaining >= bufferTime {
return "", false
}
// 计算原始有效时长:ExpiresAt - NotBefore ≈ 当初登录时配置的 activeTimeout
notBefore := claims.RegisteredClaims.NotBefore.Time
originalDuration := expiresAt.Sub(notBefore)
newClaims := jwtUtil.CustomClaims{
BaseClaims: claims.BaseClaims,
BufferTime: claims.BufferTime,
RegisteredClaims: jwtv5.RegisteredClaims{
Audience: claims.RegisteredClaims.Audience,
Issuer: claims.RegisteredClaims.Issuer,
NotBefore: jwtv5.NewNumericDate(time.Now()),
ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(originalDuration)),
},
}
newToken, err := j.CreateToken(newClaims)
if err != nil {
logx.Errorf("[gateway] Token 续期失败: %v", err)
return "", false
}
return newToken, true
}
// isWhitelisted 支持精确匹配和 /* 前缀通配
func (m *AuthMiddleware) isWhitelisted(path string) bool {
if m.whitelist[path] {
return true
}
for p := range m.whitelist {
if strings.HasSuffix(p, "/*") && strings.HasPrefix(path, strings.TrimSuffix(p, "*")) {
return true
}
}
return false
}
// writeUnauthorized 返回统一的 401 响应
func writeUnauthorized(w http.ResponseWriter, msg string) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusUnauthorized)
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"code": 401,
"msg": msg,
})
}
+2
View File
@@ -42,6 +42,8 @@ func (m *CorsMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
w.Header().Set("Access-Control-Allow-Headers", strings.Join(m.allowHeaders, ", "))
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Max-Age", "3600")
// 允许前端 JS 读取自定义响应头(用于 Token 自动续期)
w.Header().Set("Access-Control-Expose-Headers", "X-Refresh-Token")
}
// 预检请求直接返回
@@ -0,0 +1,172 @@
package middleware
import (
"bytes"
"context"
"io"
"net/http"
"strings"
"time"
"sundynix-micro-go/app/system/rpc/system"
"sundynix-micro-go/app/system/rpc/systemservice"
jwtUtil "sundynix-micro-go/common/utils/jwt"
"github.com/zeromicro/go-zero/core/logx"
)
// OperationLogMiddleware 操作日志中间件
type OperationLogMiddleware struct {
systemRpc systemservice.SystemService
jwtSecret string
logChan chan *system.CreateOperationRecordReq
}
// NewOperationLogMiddleware 创建操作日志中间件
func NewOperationLogMiddleware(systemRpc systemservice.SystemService, jwtSecret string) *OperationLogMiddleware {
m := &OperationLogMiddleware{
systemRpc: systemRpc,
jwtSecret: jwtSecret,
logChan: make(chan *system.CreateOperationRecordReq, 500),
}
// 启动异步消费者,避免阻塞请求
go m.consumer()
return m
}
// Handle 中间件处理函数
func (m *OperationLogMiddleware) Handle(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 跳过健康检查、OPTIONS 预检
if r.URL.Path == "/health" || r.Method == http.MethodOptions {
next.ServeHTTP(w, r)
return
}
startTime := time.Now()
// 读取请求体(限制大小,跳过文件上传)
var bodyStr string
if r.Body != nil && !strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
bodyBytes, _ := io.ReadAll(io.LimitReader(r.Body, 2048))
bodyStr = string(bodyBytes)
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
clientId := r.Header.Get("X-Client-Id")
userId := m.extractUserId(r)
clientIP := getClientIP(r)
// 包装 ResponseWriter 捕获响应
rw := &responseCapture{ResponseWriter: w, statusCode: http.StatusOK}
// 执行后续 handler
next.ServeHTTP(rw, r)
latency := time.Since(startTime)
// 构建日志请求
record := &system.CreateOperationRecordReq{
ClientId: clientId,
Ip: clientIP,
Method: r.Method,
Path: r.URL.Path,
Status: int32(rw.statusCode),
Latency: latency.Nanoseconds(),
Agent: truncate(r.UserAgent(), 500),
ErrorMessage: rw.errorMsg(),
Body: truncate(bodyStr, 2000),
Resp: truncate(rw.body.String(), 2000),
UserId: userId,
}
// 异步发送,不阻塞响应
select {
case m.logChan <- record:
default:
logx.Error("操作日志缓冲区满,丢弃日志")
}
})
}
// consumer 异步消费日志并通过 system-rpc 写入
func (m *OperationLogMiddleware) consumer() {
for record := range m.logChan {
_, err := m.systemRpc.CreateOperationRecord(context.Background(), record)
if err != nil {
logx.Errorf("写入操作日志失败: %v", err)
}
}
}
// extractUserId 从请求中获取 userId
// 优先从鉴权中间件注入的 X-User-Id 头获取(避免重复解析 JWT)
func (m *OperationLogMiddleware) extractUserId(r *http.Request) string {
if uid := r.Header.Get("X-User-Id"); uid != "" {
return uid
}
// fallback: 自己解析 JWT
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
return ""
}
tokenStr := jwtUtil.GetTokenFromHeader(authHeader)
if tokenStr == "" {
return ""
}
j := jwtUtil.NewJWT(m.jwtSecret)
claims, err := j.ParseToken(tokenStr)
if err != nil {
return ""
}
return claims.BaseClaims.ID
}
// responseCapture 捕获响应状态码和响应体
type responseCapture struct {
http.ResponseWriter
statusCode int
body bytes.Buffer
}
func (rc *responseCapture) WriteHeader(code int) {
rc.statusCode = code
rc.ResponseWriter.WriteHeader(code)
}
func (rc *responseCapture) Write(b []byte) (int, error) {
if rc.body.Len() < 2048 {
rc.body.Write(b)
}
return rc.ResponseWriter.Write(b)
}
func (rc *responseCapture) errorMsg() string {
if rc.statusCode >= 400 {
return rc.body.String()
}
return ""
}
// getClientIP 获取真实客户端 IP
func getClientIP(r *http.Request) string {
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
return strings.Split(ip, ",")[0]
}
if ip := r.Header.Get("X-Real-Ip"); ip != "" {
return ip
}
addr := r.RemoteAddr
if idx := strings.LastIndex(addr, ":"); idx != -1 {
return addr[:idx]
}
return addr
}
// truncate 截断字符串
func truncate(s string, maxLen int) string {
if len(s) > maxLen {
return s[:maxLen] + "..."
}
return s
}
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"sundynix-micro-go/app/file/rpc/fileservice"
"sundynix-micro-go/app/plant/api/internal/config"
"sundynix-micro-go/app/plant/rpc/plantservice"
"sundynix-micro-go/app/user/rpc/userservice"
"sundynix-micro-go/app/system/rpc/systemservice"
"github.com/zeromicro/go-zero/zrpc"
)
@@ -15,7 +15,7 @@ import (
type ServiceContext struct {
Config config.Config
PlantRpc plantservice.PlantService
UserRpc userservice.UserService
UserRpc systemservice.SystemService
FileRpc fileservice.FileService
}
@@ -23,7 +23,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
PlantRpc: plantservice.NewPlantService(zrpc.MustNewClient(c.PlantRpc)),
UserRpc: userservice.NewUserService(zrpc.MustNewClient(c.UserRpc)),
UserRpc: systemservice.NewSystemService(zrpc.MustNewClient(c.UserRpc)),
FileRpc: fileservice.NewFileService(zrpc.MustNewClient(c.FileRpc)),
}
}
+5 -5
View File
@@ -166,11 +166,11 @@ service plant-api {
@doc "更新植物"
@handler UpdatePlant
put /my/update (UpdatePlantReq)
post /my/update (UpdatePlantReq)
@doc "删除植物"
@handler DeletePlant
delete /my/delete (IdsReq)
post /my/delete (IdsReq)
@doc "我的植物列表"
@handler GetMyPlantList
@@ -240,7 +240,7 @@ service plant-api {
@doc "删除帖子"
@handler DeletePost
delete /post/delete (IdsReq)
post /post/delete (IdsReq)
@doc "评论帖子"
@handler CommentPost
@@ -267,7 +267,7 @@ service plant-api {
@doc "删除话题"
@handler DeleteTopic
delete /topic/delete (IdsReq)
post /topic/delete (IdsReq)
}
@server (
@@ -323,7 +323,7 @@ service plant-api {
@doc "更新用户资料"
@handler UpdateUserProfile
put /profile/update (UpdateProfileReq)
post /profile/update (UpdateProfileReq)
}
@server (
+2
View File
@@ -12,6 +12,7 @@ import (
"sundynix-micro-go/app/plant/api/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/rest"
)
@@ -19,6 +20,7 @@ var configFile = flag.String("f", "etc/plant-api.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog()
var c config.Config
conf.MustLoad(*configFile, &c)
+2
View File
@@ -11,6 +11,7 @@ import (
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/service"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/zrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
@@ -20,6 +21,7 @@ var configFile = flag.String("f", "etc/plant.yaml", "the config file")
func main() {
flag.Parse()
stat.DisableLog()
var c config.Config
conf.MustLoad(*configFile, &c)
-28
View File
@@ -1,28 +0,0 @@
Name: radio-api
Log:
Encoding: plain
Host: 0.0.0.0
Port: 9005
Auth:
AccessSecret: sundynix-jwt-secret-2024
AccessExpire: 604800
RadioRpc:
Etcd:
Hosts:
- 192.168.100.127:2379
Key: radio.rpc
UserRpc:
Etcd:
Hosts:
- 192.168.100.127:2379
Key: user.rpc
FileRpc:
Etcd:
Hosts:
- 192.168.100.127:2379
Key: file.rpc
-20
View File
@@ -1,20 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package config
import (
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
rest.RestConf
Auth struct {
AccessSecret string
AccessExpire int64
}
RadioRpc zrpc.RpcClientConf
UserRpc zrpc.RpcClientConf
FileRpc zrpc.RpcClientConf
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/analytics"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 数据概览
func GetAnalyticsOverviewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AnalyticsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := analytics.NewGetAnalyticsOverviewLogic(r.Context(), svcCtx)
err := l.GetAnalyticsOverview(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/analytics"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 频道数据
func GetChannelAnalyticsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AnalyticsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := analytics.NewGetChannelAnalyticsLogic(r.Context(), svcCtx)
err := l.GetChannelAnalytics(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/analytics"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 用户数据
func GetUserAnalyticsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AnalyticsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := analytics.NewGetUserAnalyticsLogic(r.Context(), svcCtx)
err := l.GetUserAnalytics(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,25 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package callback
import (
"net/http"
"sundynix-micro-go/app/radio/api/internal/logic/callback"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/common/response"
)
// 微信支付回调
func WechatPayCallbackHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := callback.NewWechatPayCallbackLogic(r.Context(), svcCtx)
err := l.WechatPayCallback()
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/category"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 创建分类
func CreateCategoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CategoryReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := category.NewCreateCategoryLogic(r.Context(), svcCtx)
err := l.CreateCategory(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/category"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 删除分类
func DeleteCategoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := category.NewDeleteCategoryLogic(r.Context(), svcCtx)
err := l.DeleteCategory(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/category"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 分类列表
func GetCategoryListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CategoryListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := category.NewGetCategoryListLogic(r.Context(), svcCtx)
err := l.GetCategoryList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/category"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 更新分类
func UpdateCategoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CategoryUpdateReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := category.NewUpdateCategoryLogic(r.Context(), svcCtx)
err := l.UpdateCategory(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/channel"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 创建频道
func CreateChannelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChannelReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := channel.NewCreateChannelLogic(r.Context(), svcCtx)
err := l.CreateChannel(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/channel"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 删除频道
func DeleteChannelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := channel.NewDeleteChannelLogic(r.Context(), svcCtx)
err := l.DeleteChannel(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/channel"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 频道详情
func GetChannelDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdPathReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := channel.NewGetChannelDetailLogic(r.Context(), svcCtx)
err := l.GetChannelDetail(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/channel"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 频道列表
func GetChannelListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChannelListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := channel.NewGetChannelListLogic(r.Context(), svcCtx)
err := l.GetChannelList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/channel"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 更新频道
func UpdateChannelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChannelUpdateReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := channel.NewUpdateChannelLogic(r.Context(), svcCtx)
err := l.UpdateChannel(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 评论节目
func CommentProgramHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CommentReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewCommentProgramLogic(r.Context(), svcCtx)
err := l.CommentProgram(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 我的收藏列表
func GetFavoriteListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.HistoryListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewGetFavoriteListLogic(r.Context(), svcCtx)
err := l.GetFavoriteList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 播放历史列表
func GetHistoryListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.HistoryListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewGetHistoryListLogic(r.Context(), svcCtx)
err := l.GetHistoryList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 记录播放历史
func RecordHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.HistoryReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewRecordHistoryLogic(r.Context(), svcCtx)
err := l.RecordHistory(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 收藏/取消收藏
func ToggleFavoriteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.FavoriteReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewToggleFavoriteLogic(r.Context(), svcCtx)
err := l.ToggleFavorite(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package interaction
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/interaction"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 点赞/取消点赞
func ToggleLikeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.LikeReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := interaction.NewToggleLikeLogic(r.Context(), svcCtx)
err := l.ToggleLike(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package pay
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/pay"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 创建支付订单
func CreatePayOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CreatePayOrderReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := pay.NewCreatePayOrderLogic(r.Context(), svcCtx)
err := l.CreatePayOrder(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 创建节目
func CreateProgramHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ProgramReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewCreateProgramLogic(r.Context(), svcCtx)
err := l.CreateProgram(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 删除节目
func DeleteProgramHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewDeleteProgramLogic(r.Context(), svcCtx)
err := l.DeleteProgram(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// TTS生成音频
func GenerateTtsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.TtsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewGenerateTtsLogic(r.Context(), svcCtx)
err := l.GenerateTts(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 节目详情
func GetProgramDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdPathReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewGetProgramDetailLogic(r.Context(), svcCtx)
err := l.GetProgramDetail(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 节目列表
func GetProgramListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ProgramListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewGetProgramListLogic(r.Context(), svcCtx)
err := l.GetProgramList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package program
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/program"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 更新节目
func UpdateProgramHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ProgramUpdateReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := program.NewUpdateProgramLogic(r.Context(), svcCtx)
err := l.UpdateProgram(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
-291
View File
@@ -1,291 +0,0 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.10.1
package handler
import (
"net/http"
analytics "sundynix-micro-go/app/radio/api/internal/handler/analytics"
callback "sundynix-micro-go/app/radio/api/internal/handler/callback"
category "sundynix-micro-go/app/radio/api/internal/handler/category"
channel "sundynix-micro-go/app/radio/api/internal/handler/channel"
interaction "sundynix-micro-go/app/radio/api/internal/handler/interaction"
pay "sundynix-micro-go/app/radio/api/internal/handler/pay"
program "sundynix-micro-go/app/radio/api/internal/handler/program"
subscription "sundynix-micro-go/app/radio/api/internal/handler/subscription"
vip "sundynix-micro-go/app/radio/api/internal/handler/vip"
voice "sundynix-micro-go/app/radio/api/internal/handler/voice"
"sundynix-micro-go/app/radio/api/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// 频道数据
Method: http.MethodPost,
Path: "/analytics/channel",
Handler: analytics.GetChannelAnalyticsHandler(serverCtx),
},
{
// 数据概览
Method: http.MethodPost,
Path: "/analytics/overview",
Handler: analytics.GetAnalyticsOverviewHandler(serverCtx),
},
{
// 用户数据
Method: http.MethodPost,
Path: "/analytics/user",
Handler: analytics.GetUserAnalyticsHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 微信支付回调
Method: http.MethodPost,
Path: "/callback/wechatpay",
Handler: callback.WechatPayCallbackHandler(serverCtx),
},
},
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 创建分类
Method: http.MethodPost,
Path: "/category/create",
Handler: category.CreateCategoryHandler(serverCtx),
},
{
// 删除分类
Method: http.MethodDelete,
Path: "/category/delete",
Handler: category.DeleteCategoryHandler(serverCtx),
},
{
// 分类列表
Method: http.MethodPost,
Path: "/category/list",
Handler: category.GetCategoryListHandler(serverCtx),
},
{
// 更新分类
Method: http.MethodPut,
Path: "/category/update",
Handler: category.UpdateCategoryHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 频道详情
Method: http.MethodGet,
Path: "/channel/:id",
Handler: channel.GetChannelDetailHandler(serverCtx),
},
{
// 创建频道
Method: http.MethodPost,
Path: "/channel/create",
Handler: channel.CreateChannelHandler(serverCtx),
},
{
// 删除频道
Method: http.MethodDelete,
Path: "/channel/delete",
Handler: channel.DeleteChannelHandler(serverCtx),
},
{
// 频道列表
Method: http.MethodPost,
Path: "/channel/list",
Handler: channel.GetChannelListHandler(serverCtx),
},
{
// 更新频道
Method: http.MethodPut,
Path: "/channel/update",
Handler: channel.UpdateChannelHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 评论节目
Method: http.MethodPost,
Path: "/interaction/comment",
Handler: interaction.CommentProgramHandler(serverCtx),
},
{
// 收藏/取消收藏
Method: http.MethodPost,
Path: "/interaction/favorite",
Handler: interaction.ToggleFavoriteHandler(serverCtx),
},
{
// 我的收藏列表
Method: http.MethodPost,
Path: "/interaction/favorite/list",
Handler: interaction.GetFavoriteListHandler(serverCtx),
},
{
// 记录播放历史
Method: http.MethodPost,
Path: "/interaction/history",
Handler: interaction.RecordHistoryHandler(serverCtx),
},
{
// 播放历史列表
Method: http.MethodPost,
Path: "/interaction/history/list",
Handler: interaction.GetHistoryListHandler(serverCtx),
},
{
// 点赞/取消点赞
Method: http.MethodPost,
Path: "/interaction/like",
Handler: interaction.ToggleLikeHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 创建支付订单
Method: http.MethodPost,
Path: "/pay/create",
Handler: pay.CreatePayOrderHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 节目详情
Method: http.MethodGet,
Path: "/program/:id",
Handler: program.GetProgramDetailHandler(serverCtx),
},
{
// 创建节目
Method: http.MethodPost,
Path: "/program/create",
Handler: program.CreateProgramHandler(serverCtx),
},
{
// 删除节目
Method: http.MethodDelete,
Path: "/program/delete",
Handler: program.DeleteProgramHandler(serverCtx),
},
{
// 节目列表
Method: http.MethodPost,
Path: "/program/list",
Handler: program.GetProgramListHandler(serverCtx),
},
{
// TTS生成音频
Method: http.MethodPost,
Path: "/program/tts",
Handler: program.GenerateTtsHandler(serverCtx),
},
{
// 更新节目
Method: http.MethodPut,
Path: "/program/update",
Handler: program.UpdateProgramHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 我的订阅列表
Method: http.MethodGet,
Path: "/subscription/list",
Handler: subscription.GetMySubscriptionsHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 我的VIP信息
Method: http.MethodGet,
Path: "/vip/info",
Handler: vip.GetMyVipInfoHandler(serverCtx),
},
{
// VIP配置列表
Method: http.MethodPost,
Path: "/vip/list",
Handler: vip.GetVipConfigListHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
server.AddRoutes(
[]rest.Route{
{
// 创建音色
Method: http.MethodPost,
Path: "/voice/create",
Handler: voice.CreateVoiceHandler(serverCtx),
},
{
// 删除音色
Method: http.MethodDelete,
Path: "/voice/delete",
Handler: voice.DeleteVoiceHandler(serverCtx),
},
{
// 音色列表
Method: http.MethodPost,
Path: "/voice/list",
Handler: voice.GetVoiceListHandler(serverCtx),
},
{
// 更新音色
Method: http.MethodPut,
Path: "/voice/update",
Handler: voice.UpdateVoiceHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
rest.WithPrefix("/api/radio"),
)
}
@@ -1,25 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package subscription
import (
"net/http"
"sundynix-micro-go/app/radio/api/internal/logic/subscription"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/common/response"
)
// 我的订阅列表
func GetMySubscriptionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := subscription.NewGetMySubscriptionsLogic(r.Context(), svcCtx)
err := l.GetMySubscriptions()
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,25 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package vip
import (
"net/http"
"sundynix-micro-go/app/radio/api/internal/logic/vip"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/common/response"
)
// 我的VIP信息
func GetMyVipInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := vip.NewGetMyVipInfoLogic(r.Context(), svcCtx)
err := l.GetMyVipInfo()
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package vip
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/vip"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// VIP配置列表
func GetVipConfigListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.VipConfigListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := vip.NewGetVipConfigListLogic(r.Context(), svcCtx)
err := l.GetVipConfigList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package voice
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/voice"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 创建音色
func CreateVoiceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.VoiceReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := voice.NewCreateVoiceLogic(r.Context(), svcCtx)
err := l.CreateVoice(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package voice
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/voice"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 删除音色
func DeleteVoiceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.IdsReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := voice.NewDeleteVoiceLogic(r.Context(), svcCtx)
err := l.DeleteVoice(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package voice
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/voice"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 音色列表
func GetVoiceListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.VoiceListReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := voice.NewGetVoiceListLogic(r.Context(), svcCtx)
err := l.GetVoiceList(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,33 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package voice
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"sundynix-micro-go/app/radio/api/internal/logic/voice"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"sundynix-micro-go/common/response"
)
// 更新音色
func UpdateVoiceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.VoiceUpdateReq
if err := httpx.Parse(r, &req); err != nil {
response.Fail(w, err.Error())
return
}
l := voice.NewUpdateVoiceLogic(r.Context(), svcCtx)
err := l.UpdateVoice(&req)
if err != nil {
response.Fail(w, err.Error())
} else {
response.Ok(w)
}
}
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetAnalyticsOverviewLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 数据概览
func NewGetAnalyticsOverviewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAnalyticsOverviewLogic {
return &GetAnalyticsOverviewLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetAnalyticsOverviewLogic) GetAnalyticsOverview(req *types.AnalyticsReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetChannelAnalyticsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 频道数据
func NewGetChannelAnalyticsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChannelAnalyticsLogic {
return &GetChannelAnalyticsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetChannelAnalyticsLogic) GetChannelAnalytics(req *types.AnalyticsReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package analytics
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserAnalyticsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 用户数据
func NewGetUserAnalyticsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserAnalyticsLogic {
return &GetUserAnalyticsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetUserAnalyticsLogic) GetUserAnalytics(req *types.AnalyticsReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,32 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package callback
import (
"context"
"github.com/zeromicro/go-zero/core/logx"
"sundynix-micro-go/app/radio/api/internal/svc"
)
type WechatPayCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 微信支付回调
func NewWechatPayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatPayCallbackLogic {
return &WechatPayCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WechatPayCallbackLogic) WechatPayCallback() error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CreateCategoryLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 创建分类
func NewCreateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateCategoryLogic {
return &CreateCategoryLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CreateCategoryLogic) CreateCategory(req *types.CategoryReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteCategoryLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 删除分类
func NewDeleteCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCategoryLogic {
return &DeleteCategoryLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *DeleteCategoryLogic) DeleteCategory(req *types.IdsReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetCategoryListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 分类列表
func NewGetCategoryListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCategoryListLogic {
return &GetCategoryListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetCategoryListLogic) GetCategoryList(req *types.CategoryListReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package category
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateCategoryLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 更新分类
func NewUpdateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateCategoryLogic {
return &UpdateCategoryLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UpdateCategoryLogic) UpdateCategory(req *types.CategoryUpdateReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CreateChannelLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 创建频道
func NewCreateChannelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateChannelLogic {
return &CreateChannelLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CreateChannelLogic) CreateChannel(req *types.ChannelReq) error {
// todo: add your logic here and delete this line
return nil
}
@@ -1,34 +0,0 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1
package channel
import (
"context"
"sundynix-micro-go/app/radio/api/internal/svc"
"sundynix-micro-go/app/radio/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteChannelLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 删除频道
func NewDeleteChannelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteChannelLogic {
return &DeleteChannelLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *DeleteChannelLogic) DeleteChannel(req *types.IdsReq) error {
// todo: add your logic here and delete this line
return nil
}

Some files were not shown because too many files have changed in this diff Show More