This commit is contained in:
Mrx
2026-05-16 15:45:05 +08:00
parent 867a1022dd
commit a81f5198e3
14 changed files with 8683 additions and 2 deletions

View 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)
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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秒
}

View File

@@ -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{
{

View 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)
}
}

View 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)
}
}

View 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
}

View 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
}

View 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
}

File diff suppressed because it is too large Load Diff

View File

@@ -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,
}
}

View File

@@ -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