Skip to content

Commit d0ef568

Browse files
committed
Update.
1 parent cfea733 commit d0ef568

File tree

3 files changed

+70
-119
lines changed

3 files changed

+70
-119
lines changed

cmd/dashboard/controller/member_api.go

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -807,12 +807,13 @@ type monitorForm struct {
807807
func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
808808
var mf monitorForm
809809
var m model.Monitor
810-
err := c.ShouldBindJSON(&mf)
811-
if err != nil {
812-
// 回退到表单绑定,兼容 application/x-www-form-urlencoded
813-
if ferr := c.ShouldBind(&mf); ferr == nil {
814-
err = nil
815-
}
810+
var err error
811+
ctype := c.GetHeader("Content-Type")
812+
if strings.HasPrefix(ctype, "application/json") {
813+
err = c.ShouldBindJSON(&mf)
814+
} else {
815+
// 表单方式
816+
err = c.ShouldBind(&mf)
816817
}
817818
if err == nil {
818819
log.Printf("[Monitor] 收到提交: ID=%d Name=%s Type=%d Cover=%d Duration=%d SkipServersRaw=%s FailTasks=%s RecoverTasks=%s",
@@ -834,19 +835,36 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
834835
m.RecoverTriggerTasksRaw = mf.RecoverTriggerTasksRaw
835836
m.FailTriggerTasksRaw = mf.FailTriggerTasksRaw
836837

837-
// 兼容旧前端取值:3 代表 TCP-Ping,0 视为默认 ICMP-Ping
838-
if m.Type == 3 {
839-
m.Type = model.TaskTypeTCPPing
840-
}
841-
if m.Type == 0 {
838+
// 兼容历史与新值:
839+
// 历史:2=ICMP, 3=TCP;新值:1=ICMP, 2=TCP;0 视为 ICMP
840+
switch m.Type {
841+
case 0:
842+
m.Type = model.TaskTypeICMPPing
843+
case 1:
842844
m.Type = model.TaskTypeICMPPing
845+
case 2:
846+
// 模糊:根据 Target 是否含端口推断
847+
if strings.Contains(m.Target, ":") {
848+
m.Type = model.TaskTypeTCPPing
849+
} else {
850+
m.Type = model.TaskTypeICMPPing
851+
}
852+
case 3:
853+
m.Type = model.TaskTypeTCPPing
843854
}
844855

845856
// 处理 SkipServersRaw,确保它是有效的JSON数组
846857
if mf.SkipServersRaw == "" {
847858
mf.SkipServersRaw = "[]"
848859
m.SkipServersRaw = "[]"
849860
}
861+
// 处理 触发任务 Raw 字段,空字符串时置为 []
862+
if m.FailTriggerTasksRaw == "" {
863+
m.FailTriggerTasksRaw = "[]"
864+
}
865+
if m.RecoverTriggerTasksRaw == "" {
866+
m.RecoverTriggerTasksRaw = "[]"
867+
}
850868

851869
// 尝试初始化跳过服务器列表,如果失败则设置为空数组
852870
err = m.InitSkipServers()
@@ -862,10 +880,23 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
862880
if m.NotificationTag == "" {
863881
m.NotificationTag = "default"
864882
}
865-
err = utils.Json.Unmarshal([]byte(mf.FailTriggerTasksRaw), &m.FailTriggerTasks)
883+
// 容错解析触发任务列表
884+
if strings.TrimSpace(m.FailTriggerTasksRaw) == "" {
885+
m.FailTriggerTasks = []uint64{}
886+
} else if uerr := utils.Json.Unmarshal([]byte(m.FailTriggerTasksRaw), &m.FailTriggerTasks); uerr != nil {
887+
log.Printf("解析FailTriggerTasksRaw失败(%s),重置为空数组: %v", m.FailTriggerTasksRaw, uerr)
888+
m.FailTriggerTasks = []uint64{}
889+
m.FailTriggerTasksRaw = "[]"
890+
}
866891
}
867892
if err == nil {
868-
err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks)
893+
if strings.TrimSpace(m.RecoverTriggerTasksRaw) == "" {
894+
m.RecoverTriggerTasks = []uint64{}
895+
} else if uerr := utils.Json.Unmarshal([]byte(m.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks); uerr != nil {
896+
log.Printf("解析RecoverTriggerTasksRaw失败(%s),重置为空数组: %v", m.RecoverTriggerTasksRaw, uerr)
897+
m.RecoverTriggerTasks = []uint64{}
898+
m.RecoverTriggerTasksRaw = "[]"
899+
}
869900
}
870901
if err == nil {
871902
if m.ID == 0 {

model/monitor.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package model
33
import (
44
"fmt"
55
"log"
6+
"strings"
67

78
"github.com/robfig/cron/v3"
89
"github.com/xos/serverstatus/pkg/utils"
@@ -118,6 +119,17 @@ func (m *Monitor) AfterFind(tx *gorm.DB) error {
118119
log.Printf("修正Monitor %s(Type=3)为TCP失败: %v", m.Name, err)
119120
}
120121
}
122+
} else if m.Type == 2 {
123+
// 兼容历史:早期 2 代表 ICMP。若目标不含端口,视为 ICMP 并静默纠正;
124+
// 若目标包含端口,保持为 TCP。
125+
if !strings.Contains(m.Target, ":") {
126+
m.Type = TaskTypeICMPPing
127+
if tx != nil {
128+
if err := tx.Model(m).Update("type", TaskTypeICMPPing).Error; err != nil {
129+
log.Printf("修正Monitor %s(Type=2无端口)为ICMP失败: %v", m.Name, err)
130+
}
131+
}
132+
}
121133
}
122134

123135
m.SkipServers = make(map[uint64]bool)

resource/static/main.js

Lines changed: 14 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -87,111 +87,19 @@ function showFormModal(modelSelector, formID, URL, getData) {
8787
}
8888
form.children(".message").remove();
8989
btn.toggleClass("loading");
90-
const data = getData
91-
? getData()
92-
: $(formID)
93-
.serializeArray()
94-
.reduce(function (obj, item) {
95-
// ID 类的数据
96-
if (
97-
item.name.endsWith("_id") ||
98-
item.name === "id" ||
99-
item.name === "ID" ||
100-
item.name === "ServerID" ||
101-
item.name === "RequestType" ||
102-
item.name === "RequestMethod" ||
103-
item.name === "TriggerMode" ||
104-
item.name === "TaskType" ||
105-
item.name === "DisplayIndex" ||
106-
item.name === "Type" ||
107-
item.name === "Cover" ||
108-
item.name === "Duration" ||
109-
item.name === "MaxRetries" ||
110-
item.name === "Provider" ||
111-
item.name === "WebhookMethod" ||
112-
item.name === "WebhookRequestType"
113-
) {
114-
obj[item.name] = parseInt(item.value);
115-
} else if (item.name.endsWith("Latency")) {
116-
obj[item.name] = parseFloat(item.value);
117-
} else {
118-
obj[item.name] = item.value;
119-
}
120-
121-
if (item.name.endsWith("ServersRaw")) {
122-
// 直接使用隐藏input的值,它已经是正确的JSON格式
123-
if (item.value && item.value.length > 2) {
124-
try {
125-
// 验证是否为有效的JSON数组
126-
var parsedValue = JSON.parse(item.value);
127-
if (Array.isArray(parsedValue)) {
128-
obj[item.name] = item.value;
129-
} else {
130-
obj[item.name] = "[]";
131-
}
132-
} catch (e) {
133-
// 如果不是有效JSON,尝试从字符串中提取数字
134-
obj[item.name] = JSON.stringify(
135-
[...item.value.matchAll(/\d+/gm)].map((k) =>
136-
parseInt(k[0])
137-
)
138-
);
139-
}
140-
} else {
141-
obj[item.name] = "[]";
142-
}
143-
}
144-
145-
if (item.name.endsWith("TasksRaw")) {
146-
// 直接使用隐藏input的值,它已经是正确的JSON格式
147-
if (item.value && item.value.length > 2) {
148-
try {
149-
// 验证是否为有效的JSON数组
150-
var parsedValue = JSON.parse(item.value);
151-
if (Array.isArray(parsedValue)) {
152-
obj[item.name] = item.value;
153-
} else {
154-
obj[item.name] = "[]";
155-
}
156-
} catch (e) {
157-
// 如果不是有效JSON,尝试从字符串中提取数字
158-
obj[item.name] = JSON.stringify(
159-
[...item.value.matchAll(/\d+/gm)].map((k) =>
160-
parseInt(k[0])
161-
)
162-
);
163-
}
164-
} else {
165-
obj[item.name] = "[]";
166-
}
167-
}
168-
169-
if (item.name.endsWith("DDNSProfilesRaw")) {
170-
// 直接使用隐藏input的值,它已经是正确的JSON格式
171-
if (item.value && item.value.length > 2) {
172-
try {
173-
// 验证是否为有效的JSON数组
174-
var parsedValue = JSON.parse(item.value);
175-
if (Array.isArray(parsedValue)) {
176-
obj[item.name] = item.value;
177-
} else {
178-
obj[item.name] = "[]";
179-
}
180-
} catch (e) {
181-
// 如果不是有效JSON,尝试从字符串中提取数字
182-
obj[item.name] = JSON.stringify(
183-
[...item.value.matchAll(/\d+/gm)].map((k) =>
184-
parseInt(k[0])
185-
)
186-
);
187-
}
188-
} else {
189-
obj[item.name] = "[]";
190-
}
191-
}
90+
// 1) 用 Dropdown API 写回隐藏 input 的实时值
91+
$(formID).find('.ui.multiple.dropdown').each(function() {
92+
const $dropdown = $(this);
93+
const $hidden = $dropdown.find('input[type="hidden"]');
94+
const name = $hidden.attr('name');
95+
if (!name || !name.endsWith('Raw')) return;
96+
let values = $dropdown.dropdown('get values') || [];
97+
values = values.map(v => { const n = parseInt(v); return isNaN(n) ? v : n; });
98+
$hidden.val(JSON.stringify(values));
99+
});
192100

193-
return obj;
194-
}, {});
101+
// 2) serialize 生成标准 x-www-form-urlencoded 字符串
102+
const serialized = $(formID).serialize();
195103

196104
// 特殊处理checkbox字段,确保未选中的checkbox也被包含在数据中
197105
// 检查所有checkbox,如果没有在数据中,则设置为空字符串(表示未选中)
@@ -214,8 +122,8 @@ function showFormModal(modelSelector, formID, URL, getData) {
214122
data[name] = JSON.stringify(values);
215123
});
216124

217-
// 使用表单方式提交(application/x-www-form-urlencoded),与历史行为一致
218-
$.post(URL, data)
125+
// 按标准表单方式提交
126+
$.post(URL, serialized)
219127
.done(function (resp) {
220128
if (resp.code == 200) {
221129
window.location.reload()

0 commit comments

Comments
 (0)