f
This commit is contained in:
32
app/main/api/desc/front/toolbox.api
Normal file
32
app/main/api/desc/front/toolbox.api
Normal file
@@ -0,0 +1,32 @@
|
||||
syntax = "v1"
|
||||
|
||||
info (
|
||||
title: "工具箱服务"
|
||||
desc: "免费小工具:手机号归属地、VIN解析、车牌归属地等"
|
||||
version: "v1"
|
||||
)
|
||||
|
||||
// ==================== 通用请求/响应 ====================
|
||||
|
||||
type (
|
||||
ToolboxQueryReq {
|
||||
ToolKey string `json:"tool_key" validate:"required"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
}
|
||||
ToolboxQueryResp {
|
||||
ToolKey string `json:"tool_key"`
|
||||
Result map[string]interface{} `json:"result"`
|
||||
}
|
||||
)
|
||||
|
||||
// ==================== 免费接口(无需登录) ====================
|
||||
|
||||
@server (
|
||||
prefix: api/v1
|
||||
group: toolbox
|
||||
)
|
||||
service main {
|
||||
@doc "通用工具查询"
|
||||
@handler toolboxQuery
|
||||
post /toolbox/query (ToolboxQueryReq) returns (ToolboxQueryResp)
|
||||
}
|
||||
@@ -97,3 +97,9 @@ Upload:
|
||||
TempFileMaxAgeH: 24 # 临时文件保留时长(小时),超时自动删除,0 表示默认 24
|
||||
PublicBaseURL: "https://www.tianyuancha.cn"
|
||||
ExtensionTime: 24 # 佣金解冻延迟时间,单位:24小时
|
||||
|
||||
|
||||
tianxingjuhe:
|
||||
url: "https://apis.tianapi.com"
|
||||
key: "4ceffb1ffb95b83230b9a9c9df2467e1"
|
||||
timeout: 30
|
||||
@@ -103,6 +103,10 @@ Tianyuanapi:
|
||||
Key: "74902aff197d72d1caa5593560cb281e"
|
||||
BaseURL: "https://api.tianyuanapi.com"
|
||||
Timeout: 60
|
||||
tianxingjuhe:
|
||||
url: "https://apis.tianapi.com"
|
||||
key: "4ceffb1ffb95b83230b9a9c9df2467e1"
|
||||
timeout: 30
|
||||
Authorization:
|
||||
FileBaseURL: "https://www.tianyuancha.cn/api/v1/auth-docs" # 授权书文件访问基础URL
|
||||
Upload:
|
||||
|
||||
@@ -18,6 +18,7 @@ type Config struct {
|
||||
Applepay ApplepayConfig
|
||||
Ali AliConfig
|
||||
Tianyuanapi TianyuanapiConfig
|
||||
Tianxingjuhe TianxingjuheConfig
|
||||
SystemConfig SystemConfig
|
||||
WechatH5 WechatH5Config
|
||||
Authorization AuthorizationConfig // 授权书配置
|
||||
@@ -150,6 +151,13 @@ type AuthorizationConfig struct {
|
||||
|
||||
// UploadConfig 图片上传(行驶证等)配置,临时存储,按 hash 去重
|
||||
type UploadConfig struct {
|
||||
FileBaseURL string `json:",optional"` // 上传文件访问基础 URL,如 https://xxx/api/v1/upload/file
|
||||
TempFileMaxAgeH int `json:",optional"` // 临时文件保留时长(小时),超时删除,0 表示默认 24 小时
|
||||
FileBaseURL string `json:"fileBaseURL,omitempty"` // 上传文件访问基础 URL,如 https://xxx/api/v1/upload/file
|
||||
TempFileMaxAgeH int `json:"tempFileMaxAgeH,omitempty"` // 临时文件保留时长(小时),超时删除,0 表示默认 24 小时
|
||||
}
|
||||
|
||||
// TianxingjuheConfig 天行聚合API配置
|
||||
type TianxingjuheConfig struct {
|
||||
URL string // API基础URL
|
||||
Key string // API密钥
|
||||
Timeout int // 超时时间(秒),默认30秒
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
product "tyc-server/app/main/api/internal/handler/product"
|
||||
query "tyc-server/app/main/api/internal/handler/query"
|
||||
tianyuan "tyc-server/app/main/api/internal/handler/tianyuan"
|
||||
toolbox "tyc-server/app/main/api/internal/handler/toolbox"
|
||||
upload "tyc-server/app/main/api/internal/handler/upload"
|
||||
user "tyc-server/app/main/api/internal/handler/user"
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
@@ -1175,6 +1176,24 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
// 获取工具列表
|
||||
Method: http.MethodGet,
|
||||
Path: "/toolbox/list",
|
||||
Handler: toolbox.ToolboxListHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
// 通用工具查询
|
||||
Method: http.MethodPost,
|
||||
Path: "/toolbox/query",
|
||||
Handler: toolbox.ToolboxQueryHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
|
||||
17
app/main/api/internal/handler/toolbox/toolboxlisthandler.go
Normal file
17
app/main/api/internal/handler/toolbox/toolboxlisthandler.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"tyc-server/app/main/api/internal/logic/toolbox"
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/common/result"
|
||||
)
|
||||
|
||||
func ToolboxListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := toolbox.NewToolboxListLogic(r.Context(), svcCtx)
|
||||
resp, err := l.ToolboxList()
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
29
app/main/api/internal/handler/toolbox/toolboxqueryhandler.go
Normal file
29
app/main/api/internal/handler/toolbox/toolboxqueryhandler.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"tyc-server/app/main/api/internal/logic/toolbox"
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/app/main/api/internal/types"
|
||||
"tyc-server/common/result"
|
||||
"tyc-server/pkg/lzkit/validator"
|
||||
)
|
||||
|
||||
func ToolboxQueryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ToolboxQueryReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := toolbox.NewToolboxQueryLogic(r.Context(), svcCtx)
|
||||
resp, err := l.ToolboxQuery(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
43
app/main/api/internal/logic/toolbox/toolboxlistlogic.go
Normal file
43
app/main/api/internal/logic/toolbox/toolboxlistlogic.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ToolboxListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewToolboxListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToolboxListLogic {
|
||||
return &ToolboxListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ToolboxListLogic) ToolboxList() (resp *types.ToolboxListResp, err error) {
|
||||
// 调用toolboxService获取工具列表
|
||||
tools := l.svcCtx.ToolboxService.ListTools()
|
||||
|
||||
// 转换为响应格式
|
||||
var toolInfos []types.ToolInfo
|
||||
for _, tool := range tools {
|
||||
toolInfos = append(toolInfos, types.ToolInfo{
|
||||
Key: tool.Key,
|
||||
Name: tool.Name,
|
||||
Desc: tool.Desc,
|
||||
})
|
||||
}
|
||||
|
||||
return &types.ToolboxListResp{
|
||||
Tools: toolInfos,
|
||||
}, nil
|
||||
}
|
||||
37
app/main/api/internal/logic/toolbox/toolboxquerylogic.go
Normal file
37
app/main/api/internal/logic/toolbox/toolboxquerylogic.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ToolboxQueryLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewToolboxQueryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToolboxQueryLogic {
|
||||
return &ToolboxQueryLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ToolboxQueryLogic) ToolboxQuery(req *types.ToolboxQueryReq) (resp *types.ToolboxQueryResp, err error) {
|
||||
// 调用toolboxService执行工具查询
|
||||
result, err := l.svcCtx.ToolboxService.Query(l.ctx, req.ToolKey, req.Params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ToolboxQueryResp{
|
||||
ToolKey: req.ToolKey,
|
||||
Result: result,
|
||||
}, nil
|
||||
}
|
||||
150
app/main/api/internal/service/tianxingjuhe_sdk/client.go
Normal file
150
app/main/api/internal/service/tianxingjuhe_sdk/client.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package tianxingjuhe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client 天行聚合API客户端
|
||||
type Client struct {
|
||||
baseURL string
|
||||
key string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// Config 客户端配置
|
||||
type Config struct {
|
||||
BaseURL string // API基础URL
|
||||
Key string // API密钥
|
||||
Timeout int // 超时时间(秒)
|
||||
}
|
||||
|
||||
// Response 通用API响应结构
|
||||
type Response struct {
|
||||
Code int `json:"code"` // 状态码,200表示成功
|
||||
Msg string `json:"msg"` // 返回说明
|
||||
Result interface{} `json:"result"` // 返回结果集,具体内容根据接口而定
|
||||
}
|
||||
|
||||
// NewClient 创建新的客户端实例
|
||||
func NewClient(config Config) (*Client, error) {
|
||||
if config.BaseURL == "" {
|
||||
return nil, fmt.Errorf("baseURL不能为空")
|
||||
}
|
||||
if config.Key == "" {
|
||||
return nil, fmt.Errorf("key不能为空")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
baseURL: config.BaseURL,
|
||||
key: config.Key,
|
||||
client: &http.Client{
|
||||
Timeout: time.Duration(config.Timeout) * time.Second,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get 发送GET请求
|
||||
func (c *Client) Get(endpoint string, params map[string]interface{}) (*Response, error) {
|
||||
// 构建完整URL
|
||||
fullURL := fmt.Sprintf("%s/%s", c.baseURL, endpoint)
|
||||
|
||||
// 添加请求参数
|
||||
queryParams := url.Values{}
|
||||
for key, value := range params {
|
||||
queryParams.Set(key, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// 添加key参数
|
||||
queryParams.Set("key", c.key)
|
||||
|
||||
// 拼接查询参数
|
||||
if len(queryParams) > 0 {
|
||||
fullURL = fmt.Sprintf("%s?%s", fullURL, queryParams.Encode())
|
||||
}
|
||||
|
||||
// 创建HTTP请求
|
||||
req, err := http.NewRequest("GET", fullURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", "Tianxingjuhe-Go-SDK/1.0.0")
|
||||
|
||||
// 发送请求
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var apiResp Response
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// Post 发送POST请求
|
||||
func (c *Client) Post(endpoint string, params map[string]interface{}) (*Response, error) {
|
||||
// 构建完整URL
|
||||
fullURL := fmt.Sprintf("%s/%s", c.baseURL, endpoint)
|
||||
|
||||
// 添加key参数
|
||||
if params == nil {
|
||||
params = make(map[string]interface{})
|
||||
}
|
||||
params["key"] = c.key
|
||||
|
||||
// 序列化请求体
|
||||
requestBody, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("序列化请求体失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建HTTP请求
|
||||
req, err := http.NewRequest("POST", fullURL, bytes.NewBuffer(requestBody))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", "Tianxingjuhe-Go-SDK/1.0.0")
|
||||
|
||||
// 发送请求
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var apiResp Response
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
8071
app/main/api/internal/service/toolboxService.go
Normal file
8071
app/main/api/internal/service/toolboxService.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import (
|
||||
"tyc-server/app/main/api/internal/config"
|
||||
"tyc-server/app/main/api/internal/middleware"
|
||||
"tyc-server/app/main/api/internal/service"
|
||||
tianxingjuhe "tyc-server/app/main/api/internal/service/tianxingjuhe_sdk"
|
||||
tianyuanapi "tyc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||
"tyc-server/app/main/model"
|
||||
|
||||
@@ -101,6 +102,8 @@ type ServiceContext struct {
|
||||
AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService
|
||||
ImageService *service.ImageService
|
||||
AuthorizationService *service.AuthorizationService
|
||||
ToolboxService *service.ToolboxService
|
||||
TianxingjuheService *tianxingjuhe.Client
|
||||
}
|
||||
|
||||
// NewServiceContext 创建服务上下文
|
||||
@@ -188,6 +191,16 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
logx.Errorf("初始化天远API失败: %+v", err)
|
||||
}
|
||||
|
||||
// 初始化天行聚合API客户端
|
||||
tianxingjuhe, err := tianxingjuhe.NewClient(tianxingjuhe.Config{
|
||||
BaseURL: c.Tianxingjuhe.URL,
|
||||
Key: c.Tianxingjuhe.Key,
|
||||
Timeout: c.Tianxingjuhe.Timeout,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("初始化天行聚合API失败: %+v", err)
|
||||
}
|
||||
|
||||
// ============================== 业务服务初始化 ==============================
|
||||
alipayService := service.NewAliPayService(c)
|
||||
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
|
||||
@@ -206,6 +219,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
adminPromotionLinkStatsTotalModel, adminPromotionLinkStatsHistoryModel)
|
||||
imageService := service.NewImageService()
|
||||
authorizationService := service.NewAuthorizationService(c, authorizationDocumentModel)
|
||||
toolboxService := service.NewToolboxService(tianxingjuhe)
|
||||
tianxingjuheService := tianxingjuhe
|
||||
|
||||
// ============================== 异步任务服务 ==============================
|
||||
asynqServer := asynq.NewServer(
|
||||
@@ -304,6 +319,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
AdminPromotionLinkStatsService: adminPromotionLinkStatsService,
|
||||
ImageService: imageService,
|
||||
AuthorizationService: authorizationService,
|
||||
ToolboxService: toolboxService,
|
||||
TianxingjuheService: tianxingjuheService,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2134,6 +2134,26 @@ type TimeRangeReport struct {
|
||||
Report int `json:"report"` // 报告量
|
||||
}
|
||||
|
||||
type ToolboxQueryReq struct {
|
||||
ToolKey string `json:"tool_key" validate:"required"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
}
|
||||
|
||||
type ToolboxQueryResp struct {
|
||||
ToolKey string `json:"tool_key"`
|
||||
Result map[string]interface{} `json:"result"`
|
||||
}
|
||||
|
||||
type ToolInfo struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
type ToolboxListResp struct {
|
||||
Tools []ToolInfo `json:"tools"`
|
||||
}
|
||||
|
||||
type UpdateMenuReq struct {
|
||||
Id int64 `path:"id"` // 菜单ID
|
||||
Pid int64 `json:"pid,optional"` // 父菜单ID
|
||||
|
||||
Reference in New Issue
Block a user