Files
2026-07-31 12:57:17 +08:00

193 lines
4.2 KiB
Go

package response
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"strings"
"time"
"affiliate_dash/internal/pkg/timeutil"
"github.com/gin-gonic/gin"
)
var (
timeType = reflect.TypeOf(time.Time{})
rawMessageType = reflect.TypeOf(json.RawMessage{})
)
type Body struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func OK(c *gin.Context, data interface{}) {
WithStatus(c, http.StatusOK, data)
}
func WithStatus(c *gin.Context, httpStatus int, data interface{}) {
c.JSON(httpStatus, Body{Code: 0, Message: "ok", Data: NormalizeTime(data)})
}
func Fail(c *gin.Context, httpStatus int, code int, message string) {
c.JSON(httpStatus, Body{Code: code, Message: message})
}
func BadRequest(c *gin.Context, message string) {
Fail(c, http.StatusBadRequest, 400, message)
}
func Unauthorized(c *gin.Context, message string) {
Fail(c, http.StatusUnauthorized, 401, message)
}
func Forbidden(c *gin.Context, message string) {
Fail(c, http.StatusForbidden, 403, message)
}
func NotFound(c *gin.Context, message string) {
Fail(c, http.StatusNotFound, 404, message)
}
func ServerError(c *gin.Context, message string) {
Fail(c, http.StatusInternalServerError, 500, message)
}
type PageData struct {
List interface{} `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
func Page(c *gin.Context, list interface{}, total int64, page, size int) {
OK(c, PageData{List: list, Total: total, Page: page, Size: size})
}
func FormatTime(value time.Time) string {
return timeutil.FormatAPITime(value)
}
func NormalizeTime(value interface{}) interface{} {
return normalizeTimeValue(reflect.ValueOf(value))
}
func normalizeTimeValue(value reflect.Value) interface{} {
if !value.IsValid() {
return nil
}
if value.Kind() == reflect.Interface {
if value.IsNil() {
return nil
}
return normalizeTimeValue(value.Elem())
}
if value.Type() == rawMessageType {
return value.Interface()
}
if value.Type() == timeType {
if !value.CanInterface() {
return nil
}
return FormatTime(value.Interface().(time.Time))
}
switch value.Kind() {
case reflect.Pointer:
if value.IsNil() {
return nil
}
if value.Type().Elem() == timeType {
return FormatTime(value.Elem().Interface().(time.Time))
}
return normalizeTimeValue(value.Elem())
case reflect.Slice, reflect.Array:
if value.Kind() == reflect.Slice && value.IsNil() {
return nil
}
if value.Type().Elem().Kind() == reflect.Uint8 {
return value.Interface()
}
out := make([]interface{}, 0, value.Len())
for i := 0; i < value.Len(); i++ {
out = append(out, normalizeTimeValue(value.Index(i)))
}
return out
case reflect.Map:
if value.IsNil() {
return nil
}
out := make(map[string]interface{}, value.Len())
iter := value.MapRange()
for iter.Next() {
out[mapKeyString(iter.Key())] = normalizeTimeValue(iter.Value())
}
return out
case reflect.Struct:
return normalizeTimeStruct(value)
default:
if value.CanInterface() {
return value.Interface()
}
return nil
}
}
func normalizeTimeStruct(value reflect.Value) map[string]interface{} {
out := make(map[string]interface{}, value.NumField())
valueType := value.Type()
for i := 0; i < value.NumField(); i++ {
field := valueType.Field(i)
if field.PkgPath != "" {
continue
}
name, skip, omitEmpty := jsonFieldName(field)
if skip {
continue
}
fieldValue := value.Field(i)
if omitEmpty && fieldValue.IsZero() {
continue
}
out[name] = normalizeTimeValue(fieldValue)
}
return out
}
func jsonFieldName(field reflect.StructField) (string, bool, bool) {
tag := field.Tag.Get("json")
if tag == "-" {
return "", true, false
}
if tag == "" {
return field.Name, false, false
}
parts := strings.Split(tag, ",")
name := parts[0]
if name == "" {
name = field.Name
}
return name, false, hasTagOption(parts[1:], "omitempty")
}
func hasTagOption(options []string, target string) bool {
for _, option := range options {
if option == target {
return true
}
}
return false
}
func mapKeyString(value reflect.Value) string {
if value.Kind() == reflect.String {
return value.String()
}
if value.CanInterface() {
return fmt.Sprint(value.Interface())
}
return ""
}