feat: 用户个人页面展示当前 VPN 连接信息
- handler/vpn.go: 新增 GetMyVpnConnections,返回当前用户的在线 VPN 连接列表(IP/连接时间)及 max_conns_per_user 上限 - router.go: 注册 GET /api/me/vpn/connections(普通用户可访问) - ProfileView.vue: 新增"我的 VPN 连接"区块,含 n/max 徽章、 IPv4/IPv6/连接时间表格,底部提示异常连接请修改密码 - zh.ts/en.ts: 新增 myVpnConnections/noConnections/ abnormalConnectionHint 国际化
This commit is contained in:
@@ -208,6 +208,42 @@ func UpdateVpnSettings(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "设置已更新"})
|
||||
}
|
||||
|
||||
type myVpnConnection struct {
|
||||
IP string `json:"ip"`
|
||||
IP6 string `json:"ip6,omitempty"`
|
||||
ConnectedAt string `json:"connected_at"`
|
||||
}
|
||||
|
||||
func GetMyVpnConnections(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
maxConns := 30
|
||||
if vpn.VPN != nil {
|
||||
s := vpn.VPN.Settings()
|
||||
if s.MaxConnsPerUser > 0 {
|
||||
maxConns = s.MaxConnsPerUser
|
||||
}
|
||||
}
|
||||
|
||||
connections := make([]myVpnConnection, 0)
|
||||
if vpn.VPN != nil && vpn.VPN.Running() {
|
||||
for _, ci := range vpn.VPN.ClientList() {
|
||||
if ci.UserID == userID.(uint) {
|
||||
connections = append(connections, myVpnConnection{
|
||||
IP: ci.IP,
|
||||
IP6: ci.IP6,
|
||||
ConnectedAt: ci.ConnectedAt,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"max_conns_per_user": maxConns,
|
||||
"connections": connections,
|
||||
})
|
||||
}
|
||||
|
||||
type vpnStatusResponse struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Online int `json:"online"`
|
||||
|
||||
@@ -26,6 +26,7 @@ func Setup(r *gin.Engine) {
|
||||
auth.PUT("/me/password", handler.ChangePassword)
|
||||
auth.GET("/me/sessions", handler.ListMySessions)
|
||||
auth.DELETE("/me/sessions/:sessionId", handler.RevokeMySession)
|
||||
auth.GET("/me/vpn/connections", handler.GetMyVpnConnections)
|
||||
}
|
||||
|
||||
admin := r.Group("/api/admin")
|
||||
|
||||
Reference in New Issue
Block a user