桌面应用图标替换为 B-brackets 设计(深藏青 + 白/蓝花括号)
- icon.svg 取自 opsx-icon-options/api/B-brackets.svg,全套光栅重生成: icon.icns(iconutil)、icon.ico(PNG-in-ICO 6 尺寸)、16-1024 PNG、Windows Square*/StoreLogo - 替换 Tauri 脚手架默认五角星图标;GUI 重启实测 Dock 图标已生效 - 服务全量重启:server 8787(官网/文档 200)+ web 5173 + 桌面 GUI
This commit is contained in:
1 parent
71a6d986a4
commit
39f4d5addc
161 files changed
+3289
-515
No files matched your search
@@ -2,6 +2,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -43,6 +44,9 @@ func (a *API) Register(r *gin.Engine) {
|
||||
g.GET("/workspaces/:id", a.auth(a.handleGetWorkspace))
|
||||
g.PUT("/workspaces/:id", a.auth(a.handlePutWorkspace))
|
||||
g.PUT("/workspaces/:id/mock", a.auth(a.handlePublishMock))
|
||||
g.PUT("/mock/local", a.handlePublishLocalMock)
|
||||
g.DELETE("/mock/local", a.handleRevokeLocalMock)
|
||||
g.DELETE("/workspaces/:id/mock", a.auth(a.handleRevokeMock))
|
||||
}
|
||||
|
||||
/* ---------------- 中间件 ---------------- */
|
||||
@@ -312,7 +316,8 @@ func (a *API) handlePublishMock(c *gin.Context, user *store.User) {
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
Endpoints []mocksrv.Endpoint `json:"endpoints" binding:"required"`
|
||||
Endpoints []mocksrv.Endpoint `json:"endpoints" binding:"required"`
|
||||
TTLSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "缺少 endpoints"})
|
||||
@@ -322,15 +327,39 @@ func (a *API) handlePublishMock(c *gin.Context, user *store.User) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "单空间最多发布 200 个 Mock 接口"})
|
||||
return
|
||||
}
|
||||
if req.TTLSeconds < 0 || req.TTLSeconds > 30*24*3600 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ttlSeconds 需在 0~2592000(30 天)之间"})
|
||||
return
|
||||
}
|
||||
if err := a.store.ReplaceMockEndpoints(ws.ID, req.Endpoints); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "发布失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
var expiresAt int64
|
||||
if req.TTLSeconds > 0 {
|
||||
expiresAt = time.Now().Unix() + req.TTLSeconds
|
||||
}
|
||||
if err := a.store.SetMockExpiry(ws.ID, expiresAt); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "设置 TTL 失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
base := ws.MockToken
|
||||
if base == "" {
|
||||
base = strconv.FormatInt(ws.ID, 10) // 兜底(不应出现)
|
||||
base = strconv.FormatInt(ws.ID, 10)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "count": len(req.Endpoints), "base": "/mock/" + base})
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "count": len(req.Endpoints), "base": "/mock/" + base, "expiresAt": expiresAt})
|
||||
}
|
||||
|
||||
func (a *API) handleRevokeMock(c *gin.Context, user *store.User) {
|
||||
ws := a.workspaceOf(c, user)
|
||||
if ws == nil {
|
||||
return
|
||||
}
|
||||
if _, err := a.store.RevokeMock(ws.ID); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "作废失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
/* ---------------- 工作区同步 ---------------- */
|
||||
@@ -385,3 +414,76 @@ func (a *API) handlePutWorkspace(c *gin.Context, user *store.User) {
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"updatedAt": now})
|
||||
}
|
||||
|
||||
/* ---------------- 本机联调 Mock(不绑账号) ---------------- */
|
||||
|
||||
func (a *API) handlePublishLocalMock(c *gin.Context) {
|
||||
if !isLoopbackRequest(c) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "本机联调发布仅允许从 127.0.0.1 / ::1 调用"})
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
Endpoints []mocksrv.Endpoint `json:"endpoints" binding:"required"`
|
||||
TTLSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "缺少 endpoints"})
|
||||
return
|
||||
}
|
||||
if len(req.Endpoints) > 200 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "单空间最多发布 200 个 Mock 接口"})
|
||||
return
|
||||
}
|
||||
if req.TTLSeconds < 0 || req.TTLSeconds > 30*24*3600 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ttlSeconds 需在 0~2592000(30 天)之间"})
|
||||
return
|
||||
}
|
||||
wsID, token, err := a.store.EnsureLocalMockWorkspace()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "本地 Mock 空间初始化失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
if err := a.store.ReplaceMockEndpoints(wsID, req.Endpoints); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "发布失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
var expiresAt int64
|
||||
if req.TTLSeconds > 0 {
|
||||
expiresAt = time.Now().Unix() + req.TTLSeconds
|
||||
}
|
||||
if err := a.store.SetMockExpiry(wsID, expiresAt); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "设置 TTL 失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "count": len(req.Endpoints), "base": "/mock/" + token, "token": token, "expiresAt": expiresAt})
|
||||
}
|
||||
|
||||
func (a *API) handleRevokeLocalMock(c *gin.Context) {
|
||||
if !isLoopbackRequest(c) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "本机联调作废仅允许从 127.0.0.1 / ::1 调用"})
|
||||
return
|
||||
}
|
||||
wsID, _, err := a.store.EnsureLocalMockWorkspace()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "本地 Mock 空间初始化失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
if _, err := a.store.RevokeMock(wsID); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "作废失败:" + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
func isLoopbackRequest(c *gin.Context) bool {
|
||||
ip := net.ParseIP(c.ClientIP())
|
||||
if ip != nil && ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
host, _, err := net.SplitHostPort(c.Request.RemoteAddr)
|
||||
if err != nil {
|
||||
host = c.Request.RemoteAddr
|
||||
}
|
||||
ip = net.ParseIP(host)
|
||||
return ip != nil && ip.IsLoopback()
|
||||
}
|
||||
Reference in new issue
Block a user