add qygl23t7

This commit is contained in:
2025-07-30 00:51:22 +08:00
parent 83530c0f9b
commit 723c418a1b
38 changed files with 999 additions and 785 deletions

View File

@@ -0,0 +1,147 @@
package tianyancha
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
var (
ErrDatasource = errors.New("数据源异常")
ErrNotFound = errors.New("查询为空")
ErrSystem = errors.New("系统异常")
ErrInvalidParam = errors.New("参数错误")
)
// APIEndpoints 天眼查 API 端点映射
var APIEndpoints = map[string]string{
"VerifyThreeElements": "/open/ic/verify/2.0", // 企业三要素验证
}
// TianYanChaConfig 天眼查配置
type TianYanChaConfig struct {
BaseURL string
Token string
Timeout time.Duration
}
// TianYanChaService 天眼查服务
type TianYanChaService struct {
config TianYanChaConfig
}
// APIResponse 标准API响应结构
type APIResponse struct {
Success bool `json:"success"`
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// TianYanChaResponse 天眼查原始响应结构
type TianYanChaResponse struct {
ErrorCode int `json:"error_code"`
Reason string `json:"reason"`
Result interface{} `json:"result"`
}
// NewTianYanChaService 创建天眼查服务实例
func NewTianYanChaService(baseURL, token string, timeout time.Duration) *TianYanChaService {
if timeout == 0 {
timeout = 30 * time.Second
}
return &TianYanChaService{
config: TianYanChaConfig{
BaseURL: baseURL,
Token: token,
Timeout: timeout,
},
}
}
// CallAPI 调用天眼查API - 通用方法,由外部处理器传入具体参数
func (t *TianYanChaService) CallAPI(ctx context.Context, apiCode string, params map[string]string) (*APIResponse, error) {
// 从映射中获取 API 端点
endpoint, exists := APIEndpoints[apiCode]
if !exists {
return nil, fmt.Errorf("%w: 未找到 API 代码对应的端点: %s", ErrInvalidParam, apiCode)
}
// 构建完整 URL
fullURL := strings.TrimRight(t.config.BaseURL, "/") + "/" + strings.TrimLeft(endpoint, "/")
// 检查 Token 是否配置
if t.config.Token == "" {
return nil, fmt.Errorf("%w: 天眼查 API Token 未配置", ErrSystem)
}
// 构建查询参数
queryParams := url.Values{}
for key, value := range params {
queryParams.Set(key, value)
}
// 构建完整URL
requestURL := fullURL
if len(queryParams) > 0 {
requestURL += "?" + queryParams.Encode()
}
// 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", requestURL, nil)
if err != nil {
return nil, fmt.Errorf("%w: 创建请求失败: %v", ErrSystem, err)
}
// 设置请求头
req.Header.Set("Authorization", t.config.Token)
// 发送请求
client := &http.Client{Timeout: t.config.Timeout}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("%w: API 请求异常: %v", ErrDatasource, err)
}
defer resp.Body.Close()
// 检查 HTTP 状态码
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%w: API 请求失败,状态码: %d", ErrDatasource, resp.StatusCode)
}
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("%w: 读取响应体失败: %v", ErrSystem, err)
}
// 解析 JSON 响应
var tianYanChaResp TianYanChaResponse
if err := json.Unmarshal(body, &tianYanChaResp); err != nil {
return nil, fmt.Errorf("%w: 解析响应 JSON 失败: %v", ErrSystem, err)
}
// 检查天眼查业务状态码
if tianYanChaResp.ErrorCode != 0 {
return &APIResponse{
Success: false,
Code: tianYanChaResp.ErrorCode,
Message: tianYanChaResp.Reason,
Data: tianYanChaResp.Result,
}, nil
}
// 成功情况
return &APIResponse{
Success: true,
Code: 0,
Message: tianYanChaResp.Reason,
Data: tianYanChaResp.Result,
}, nil
}

View File

@@ -258,7 +258,7 @@ func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
// ListProducts 获取产品列表(管理员)
// @Summary 获取产品列表
// @Description 管理员获取产品列表,支持筛选和分页
// @Description 管理员获取产品列表,支持筛选和分页,包含所有产品(包括隐藏的)
// @Tags 产品管理
// @Accept json
// @Produce json
@@ -272,7 +272,7 @@ func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
// @Param is_package query bool false "是否组合包"
// @Param sort_by query string false "排序字段"
// @Param sort_order query string false "排序方向" Enums(asc, desc)
// @Success 200 {object} responses.ProductListResponse "获取产品列表成功"
// @Success 200 {object} responses.ProductAdminListResponse "获取产品列表成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
@@ -336,7 +336,8 @@ func (h *ProductAdminHandler) ListProducts(c *gin.Context) {
Order: sortOrder,
}
result, err := h.productAppService.ListProducts(c.Request.Context(), filters, options)
// 使用管理员专用的产品列表方法
result, err := h.productAppService.ListProductsForAdmin(c.Request.Context(), filters, options)
if err != nil {
h.logger.Error("获取产品列表失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取产品列表失败")
@@ -358,13 +359,13 @@ func (h *ProductAdminHandler) getIntQuery(c *gin.Context, key string, defaultVal
// GetProductDetail 获取产品详情(管理员)
// @Summary 获取产品详情
// @Description 管理员获取产品详细信息
// @Description 管理员获取产品详细信息,包含可见状态
// @Tags 产品管理
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path string true "产品ID"
// @Success 200 {object} responses.ProductInfoResponse "获取产品详情成功"
// @Success 200 {object} responses.ProductAdminInfoResponse "获取产品详情成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 404 {object} map[string]interface{} "产品不存在"
@@ -379,7 +380,8 @@ func (h *ProductAdminHandler) GetProductDetail(c *gin.Context) {
return
}
result, err := h.productAppService.GetProductByID(c.Request.Context(), &query)
// 使用管理员专用的产品详情获取方法
result, err := h.productAppService.GetProductByIDForAdmin(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取产品详情失败", zap.Error(err), zap.String("product_id", query.ID))
h.responseBuilder.NotFound(c, "产品不存在")

View File

@@ -45,7 +45,7 @@ func NewProductHandler(
// ListProducts 获取产品列表(数据大厅)
// @Summary 获取产品列表
// @Description 分页获取可用的产品列表,支持筛选
// @Description 分页获取可用的产品列表,支持筛选,默认只返回可见的产品
// @Tags 数据大厅
// @Accept json
// @Produce json
@@ -91,11 +91,14 @@ func (h *ProductHandler) ListProducts(c *gin.Context) {
}
}
// 可见状态筛选
// 可见状态筛选 - 用户端默认只显示可见的产品
if isVisible := c.Query("is_visible"); isVisible != "" {
if visible, err := strconv.ParseBool(isVisible); err == nil {
filters["is_visible"] = visible
}
} else {
// 如果没有指定可见状态,默认只显示可见的产品
filters["is_visible"] = true
}
// 产品类型筛选
@@ -168,7 +171,7 @@ func (h *ProductHandler) getCurrentUserID(c *gin.Context) string {
// GetProductDetail 获取产品详情
// @Summary 获取产品详情
// @Description 根据产品ID获取产品详细信息
// @Description 根据产品ID获取产品详细信息,只能获取可见的产品
// @Tags 数据大厅
// @Accept json
// @Produce json
@@ -187,7 +190,8 @@ func (h *ProductHandler) GetProductDetail(c *gin.Context) {
return
}
result, err := h.appService.GetProductByID(c.Request.Context(), &query)
// 使用用户端专用的产品详情获取方法
result, err := h.appService.GetProductByIDForUser(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取产品详情失败", zap.Error(err), zap.String("product_id", query.ID))
h.responseBuilder.NotFound(c, "产品不存在")