diff --git a/web/controller/inbound.go b/web/controller/inbound.go index 8317de31..b012ec95 100644 --- a/web/controller/inbound.go +++ b/web/controller/inbound.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "strconv" + "time" "github.com/mhsanaei/3x-ui/v2/database/model" "github.com/mhsanaei/3x-ui/v2/web/service" @@ -193,6 +194,37 @@ func (a *InboundController) getClientIps(c *gin.Context) { return } + // Prefer returning a normalized string list for consistent UI rendering + type ipWithTimestamp struct { + IP string `json:"ip"` + Timestamp int64 `json:"timestamp"` + } + + var ipsWithTime []ipWithTimestamp + if err := json.Unmarshal([]byte(ips), &ipsWithTime); err == nil && len(ipsWithTime) > 0 { + formatted := make([]string, 0, len(ipsWithTime)) + for _, item := range ipsWithTime { + if item.IP == "" { + continue + } + if item.Timestamp > 0 { + ts := time.Unix(item.Timestamp, 0).Local().Format("2006-01-02 15:04:05") + formatted = append(formatted, fmt.Sprintf("%s (%s)", item.IP, ts)) + continue + } + formatted = append(formatted, item.IP) + } + jsonObj(c, formatted, nil) + return + } + + var oldIps []string + if err := json.Unmarshal([]byte(ips), &oldIps); err == nil && len(oldIps) > 0 { + jsonObj(c, oldIps, nil) + return + } + + // If parsing fails, return as string jsonObj(c, ips, nil) } diff --git a/web/html/modals/inbound_info_modal.html b/web/html/modals/inbound_info_modal.html index 1ab187ee..37f8248a 100644 --- a/web/html/modals/inbound_info_modal.html +++ b/web/html/modals/inbound_info_modal.html @@ -260,15 +260,31 @@ v-if="app.ipLimitEnable && infoModal.clientSettings.limitIp > 0">