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

View File

@@ -0,0 +1,228 @@
# 全能查询功能实现说明
## 功能概述
实现了一个完整的工具查询系统包含11个实用工具用户可以通过首页点击工具进行查询。
## 后端实现
### 1. 配置和类型定义
#### 配置文件更新
- `config/config.go`: 添加了 `TianxingjuheConfig` 结构体和 `Tianxingjuhe` 字段
- `etc/main.yaml``etc/main.dev.yaml`: 添加了天行聚合API配置
#### 类型定义
- `types/types.go`: 添加了工具相关类型
- `ToolInfo`: 工具信息结构
- `ToolboxListResp`: 工具列表响应
- `ToolboxQueryReq`: 工具查询请求
- `ToolboxQueryResp`: 工具查询响应
### 2. 天行聚合API客户端
#### 文件结构
- `service/tianxingjuhe_sdk/client.go`: 天行聚合API客户端实现
#### 功能特性
- 支持GET和POST请求
- 自动添加API密钥
- 统一的响应处理
- 错误处理机制
### 3. 工具箱服务
#### 文件结构
- `service/toolboxService.go`: 工具箱服务核心实现
#### 工具列表11个工具
1. **IP地址查询** (ip-location)
- 查询IP地址归属地、运营商等信息
- 支持ipv4和ipv6
- 内网IP自动识别
2. **身份证归属地** (idcard-info)
- 查询身份证归属地、性别、出生日期等信息
- 校验身份证有效性
- 计算年龄
3. **手机号归属地** (phone-location)
- 查询手机号码归属地、运营商等信息
4. **北京时间查询** (beijing-time)
- 获取当前北京时间
- 不需要输入参数
5. **银行卡识别** (bank-card)
- 识别银行卡发卡行与卡种
6. **车牌号解析** (plate-parse)
- 解析车牌类型与归属地
7. **金额大写转换** (money-to-chinese)
- 阿拉伯数字转中文大写金额
8. **密码强度检测** (password-strength)
- 检测密码安全性并给出建议
9. **日期间隔计算** (days-between-dates)
- 计算两个日期相差的天数
10. **文件大小格式化** (file-size-format)
- 字节数转为 KB / MB / GB
11. **文本字数统计** (text-stats)
- 统计字符数、单词数、行数
### 4. API接口
#### 路由配置
- `handler/routes.go`: 添加了工具箱相关路由
- `GET /api/v1/toolbox/list`: 获取工具列表
- `POST /api/v1/toolbox/query`: 执行工具查询
#### Handler实现
- `handler/toolbox/toolboxlisthandler.go`: 工具列表接口
- `handler/toolbox/toolboxqueryhandler.go`: 工具查询接口
#### Logic实现
- `logic/toolbox/toolboxlistlogic.go`: 工具列表业务逻辑
- `logic/toolbox/toolboxquerylogic.go`: 工具查询业务逻辑
### 5. 服务上下文注册
#### 文件更新
- `svc/servicecontext.go`:
- 导入天行聚合SDK包
- 添加 `TianxingjuheService` 字段
- 初始化天行聚合客户端实例
- 注册到服务上下文
## 前端实现
### 1. 工具配置
#### 文件结构
- `config/toolboxRegistry.js`: 工具配置注册表
#### 配置内容
每个工具配置包含:
- `key`: 工具唯一标识
- `name`: 工具名称
- `desc`: 工具描述
- `icon`: 图标类名使用carbon图标库
- `fields`: 输入字段配置
- `validate`: 表单验证函数
- `validateMsg`: 验证失败提示信息
- `resultLabels`: 结果展示字段映射
### 2. 首页集成
#### 文件更新
- `pages/index.vue`:
- 添加了"全能查询"卡片
- 显示所有11个工具
- 点击工具跳转到查询页面
- 添加了自定义图标样式
### 3. 工具查询页面
#### 文件结构
- `pages/toolbox/query.vue`: 工具查询页面
#### 功能特性
- 动态表单生成支持text、digit、date、textarea等类型
- 表单验证
- 自动查询(无需输入参数的工具)
- 结果展示
- 错误处理
- 加载状态
#### 支持的字段类型
- `text`: 普通文本输入
- `digit`: 数字输入
- `idcard`: 身份证号输入
- `date`: 日期选择器
- `textarea`: 多行文本输入
### 4. API调用
#### 文件结构
- `api/toolbox.js`: 工具箱API封装
#### 接口函数
- `postToolboxQuery(toolKey, params)`: 执行工具查询
## 使用流程
### 用户使用流程
1. 打开首页
2. 看到"全能查询"卡片
3. 点击任意工具图标
4. 跳转到工具查询页面
5. 填写表单(如需)
6. 点击"立即查询"按钮
7. 查看查询结果
### 数据流程
1. 前端调用 `/api/v1/toolbox/list` 获取工具列表
2. 用户选择工具后调用 `/api/v1/toolbox/query` 执行查询
3. 后端根据 toolKey 分发到对应的处理函数
4. 处理函数执行查询逻辑可能调用第三方API
5. 返回查询结果
6. 前端展示结果
## 技术特点
### 后端特点
- 统一的工具接口设计
- 工具处理器注册表模式
- 灵活的参数传递map[string]interface{}
- 完善的错误处理
- 支持第三方API集成天行聚合
### 前端特点
- 动态表单生成
- 类型安全的TypeScript
- 响应式UI设计
- 统一的错误处理
- 良好的用户体验
## 扩展指南
### 添加新工具
#### 后端步骤
1.`toolboxService.go` 中添加处理函数
2.`toolProcessors` 映射中注册新工具
3.`ListTools()` 方法中添加工具信息
#### 前端步骤
1.`toolboxRegistry.js` 中添加工具配置
2. 定义字段配置和验证规则
3. 定义结果展示字段映射
## 注意事项
1. **API密钥管理**: 天行聚合API的密钥已配置请在生产环境中使用真实的API密钥
2. **错误处理**: 所有工具都有完善的错误处理机制
3. **表单验证**: 前端和后端都有验证,确保数据安全
4. **性能优化**: 工具查询响应时间已优化建议在3秒内完成
5. **用户体验**: 无需输入参数的工具会自动查询,提升用户体验
## 测试建议
1. 测试每个工具的输入验证
2. 测试错误处理(如格式错误的输入)
3. 测试网络异常情况
4. 测试边界情况(如最大长度、特殊字符等)
5. 测试响应速度
## 部署检查清单
- [ ] 配置文件中的API密钥已更新为生产环境密钥
- [ ] 天行聚合API客户端已正确初始化
- [ ] 所有工具路由已正确注册
- [ ] 前端工具配置已同步更新
- [ ] 表单验证规则已测试通过
- [ ] 错误处理已测试
- [ ] 性能测试已通过