Skip to content

Commit 806d402

Browse files
committed
Update.
1 parent d0ef568 commit 806d402

2 files changed

Lines changed: 125 additions & 46 deletions

File tree

cmd/dashboard/controller/member_api.go

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,14 @@ type TokenForm struct {
105105
func (ma *memberAPI) issueNewToken(c *gin.Context) {
106106
u := c.MustGet(model.CtxKeyAuthorizedUser).(*model.User)
107107
tf := &TokenForm{}
108-
err := c.ShouldBindJSON(tf)
108+
// 兼容 JSON 与表单
109+
ct := c.GetHeader("Content-Type")
110+
var err error
111+
if strings.HasPrefix(ct, "application/json") {
112+
err = c.ShouldBindJSON(tf)
113+
} else {
114+
err = c.ShouldBind(tf)
115+
}
109116
if err != nil {
110117
WriteJSON(c, http.StatusOK, model.Response{
111118
Code: http.StatusBadRequest,
@@ -617,7 +624,14 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
617624
var sf serverForm
618625
var s model.Server
619626
var isEdit bool
620-
err := c.ShouldBindJSON(&sf)
627+
// 兼容 JSON 与表单
628+
ct := c.GetHeader("Content-Type")
629+
var err error
630+
if strings.HasPrefix(ct, "application/json") {
631+
err = c.ShouldBindJSON(&sf)
632+
} else {
633+
err = c.ShouldBind(&sf)
634+
}
621635
if err == nil {
622636
s.Name = sf.Name
623637
s.Secret = sf.Secret
@@ -626,8 +640,9 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
626640
s.Tag = sf.Tag
627641
s.Note = sf.Note
628642
s.PublicNote = sf.PublicNote
629-
s.HideForGuest = sf.HideForGuest == "on"
630-
s.EnableDDNS = sf.EnableDDNS == "on"
643+
// 兼容表单与JSON布尔值
644+
s.HideForGuest = sf.HideForGuest == "on" || sf.HideForGuest == "true" || sf.HideForGuest == "1"
645+
s.EnableDDNS = sf.EnableDDNS == "on" || sf.EnableDDNS == "true" || sf.EnableDDNS == "1"
631646

632647
// 处理DDNSProfilesRaw,确保它是有效的JSON数组
633648
if sf.DDNSProfilesRaw == "" {
@@ -969,14 +984,22 @@ type cronForm struct {
969984
func (ma *memberAPI) addOrEditCron(c *gin.Context) {
970985
var cf cronForm
971986
var cr model.Cron
972-
err := c.ShouldBindJSON(&cf)
987+
// 兼容 JSON 与 x-www-form-urlencoded 提交
988+
ct := c.GetHeader("Content-Type")
989+
var err error
990+
if strings.HasPrefix(ct, "application/json") {
991+
err = c.ShouldBindJSON(&cf)
992+
} else {
993+
err = c.ShouldBind(&cf)
994+
}
973995
if err == nil {
974996
cr.TaskType = cf.TaskType
975997
cr.Name = cf.Name
976998
cr.Scheduler = cf.Scheduler
977999
cr.Command = cf.Command
9781000
cr.ServersRaw = cf.ServersRaw
979-
cr.PushSuccessful = cf.PushSuccessful == "on"
1001+
// 兼容多种布尔表示:表单“on”、JSON "true"/"1"
1002+
cr.PushSuccessful = cf.PushSuccessful == "on" || cf.PushSuccessful == "true" || cf.PushSuccessful == "1"
9801003
cr.NotificationTag = cf.NotificationTag
9811004
cr.ID = cf.ID
9821005
cr.Cover = cf.Cover
@@ -1314,7 +1337,14 @@ type notificationForm struct {
13141337
func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
13151338
var nf notificationForm
13161339
var n model.Notification
1317-
err := c.ShouldBindJSON(&nf)
1340+
// 兼容 JSON 与表单
1341+
ct := c.GetHeader("Content-Type")
1342+
var err error
1343+
if strings.HasPrefix(ct, "application/json") {
1344+
err = c.ShouldBindJSON(&nf)
1345+
} else {
1346+
err = c.ShouldBind(&nf)
1347+
}
13181348
if err == nil {
13191349
n.Name = nf.Name
13201350
n.Tag = nf.Tag
@@ -1323,7 +1353,7 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
13231353
n.RequestHeader = nf.RequestHeader
13241354
n.RequestBody = nf.RequestBody
13251355
n.URL = nf.URL
1326-
verifySSL := nf.VerifySSL == "on"
1356+
verifySSL := nf.VerifySSL == "on" || nf.VerifySSL == "true" || nf.VerifySSL == "1"
13271357
n.VerifySSL = &verifySSL
13281358
n.ID = nf.ID
13291359
ns := model.NotificationServerBundle{
@@ -1404,7 +1434,14 @@ type ddnsForm struct {
14041434
func (ma *memberAPI) addOrEditDDNS(c *gin.Context) {
14051435
var df ddnsForm
14061436
var p model.DDNSProfile
1407-
err := c.ShouldBindJSON(&df)
1437+
// 兼容 JSON 与表单
1438+
ct := c.GetHeader("Content-Type")
1439+
var err error
1440+
if strings.HasPrefix(ct, "application/json") {
1441+
err = c.ShouldBindJSON(&df)
1442+
} else {
1443+
err = c.ShouldBind(&df)
1444+
}
14081445
if err == nil {
14091446
if df.MaxRetries < 1 || df.MaxRetries > 10 {
14101447
err = errors.New("重试次数必须为大于 1 且不超过 10 的整数")
@@ -1413,8 +1450,8 @@ func (ma *memberAPI) addOrEditDDNS(c *gin.Context) {
14131450
if err == nil {
14141451
p.Name = df.Name
14151452
p.ID = df.ID
1416-
enableIPv4 := df.EnableIPv4 == "on"
1417-
enableIPv6 := df.EnableIPv6 == "on"
1453+
enableIPv4 := df.EnableIPv4 == "on" || df.EnableIPv4 == "true" || df.EnableIPv4 == "1"
1454+
enableIPv6 := df.EnableIPv6 == "on" || df.EnableIPv6 == "true" || df.EnableIPv6 == "1"
14181455
p.EnableIPv4 = &enableIPv4
14191456
p.EnableIPv6 = &enableIPv6
14201457
p.MaxRetries = df.MaxRetries
@@ -1494,7 +1531,14 @@ type natForm struct {
14941531
func (ma *memberAPI) addOrEditNAT(c *gin.Context) {
14951532
var nf natForm
14961533
var n model.NAT
1497-
err := c.ShouldBindJSON(&nf)
1534+
// 兼容 JSON 与表单
1535+
ct := c.GetHeader("Content-Type")
1536+
var err error
1537+
if strings.HasPrefix(ct, "application/json") {
1538+
err = c.ShouldBindJSON(&nf)
1539+
} else {
1540+
err = c.ShouldBind(&nf)
1541+
}
14981542
if err == nil {
14991543
n.Name = nf.Name
15001544
n.ID = nf.ID
@@ -1560,7 +1604,14 @@ type alertRuleForm struct {
15601604
func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) {
15611605
var arf alertRuleForm
15621606
var r model.AlertRule
1563-
err := c.ShouldBindJSON(&arf)
1607+
// 兼容 JSON 与表单
1608+
ct := c.GetHeader("Content-Type")
1609+
var err error
1610+
if strings.HasPrefix(ct, "application/json") {
1611+
err = c.ShouldBindJSON(&arf)
1612+
} else {
1613+
err = c.ShouldBind(&arf)
1614+
}
15641615
if err == nil {
15651616
// 清理 RulesRaw 中的千位分隔符和修复 ignore 字段格式
15661617
cleanedRulesRaw := cleanNumbersInJSON(arf.RulesRaw)
@@ -1604,7 +1655,7 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) {
16041655
r.FailTriggerTasksRaw = arf.FailTriggerTasksRaw
16051656
r.RecoverTriggerTasksRaw = arf.RecoverTriggerTasksRaw
16061657
r.NotificationTag = arf.NotificationTag
1607-
enable := arf.Enable == "on"
1658+
enable := arf.Enable == "on" || arf.Enable == "true" || arf.Enable == "1"
16081659
r.TriggerMode = arf.TriggerMode
16091660
r.Enable = &enable
16101661
r.ID = arf.ID

resource/static/main.js

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -87,40 +87,47 @@ function showFormModal(modelSelector, formID, URL, getData) {
8787
}
8888
form.children(".message").remove();
8989
btn.toggleClass("loading");
90-
// 1) 用 Dropdown API 写回隐藏 input 的实时值
90+
// 1) 写回隐藏 input 的实时值
91+
// 兼容当前实现:标签是手动添加到 DOM 的,dropdown API 可能拿不到值
9192
$(formID).find('.ui.multiple.dropdown').each(function() {
9293
const $dropdown = $(this);
9394
const $hidden = $dropdown.find('input[type="hidden"]');
9495
const name = $hidden.attr('name');
9596
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; });
97+
// 优先从可见标签读取 data-value
98+
let values = [];
99+
$dropdown.find('a.ui.label').each(function() {
100+
const v = $(this).attr('data-value');
101+
if (v !== undefined && v !== null && v !== '') {
102+
const n = parseInt(v);
103+
values.push(isNaN(n) ? v : n);
104+
}
105+
});
106+
// 若未读到标签,再回退使用 dropdown API
107+
if (values.length === 0) {
108+
const apiVals = $dropdown.dropdown('get values') || [];
109+
for (let i = 0; i < apiVals.length; i++) {
110+
const n = parseInt(apiVals[i]);
111+
values.push(isNaN(n) ? apiVals[i] : n);
112+
}
113+
}
98114
$hidden.val(JSON.stringify(values));
99115
});
100116

101-
// 2) serialize 生成标准 x-www-form-urlencoded 字符串
102-
const serialized = $(formID).serialize();
117+
// 2) 使用 serializeArray 获取键值对,便于补齐未选中的 checkbox
118+
let arr = $(formID).serializeArray();
103119

104-
// 特殊处理checkbox字段,确保未选中的checkbox也被包含在数据中
105-
// 检查所有checkbox,如果没有在数据中,则设置为空字符串(表示未选中)
120+
// 3) 补齐未选中的 checkbox(用空字符串表示未选中)
106121
$(formID).find('input[type="checkbox"]').each(function() {
107-
const checkboxName = $(this).attr('name');
108-
if (checkboxName && !(checkboxName in data)) {
109-
data[checkboxName] = "";
122+
const name = $(this).attr('name');
123+
if (!name) return;
124+
if (!arr.find(p => p.name === name)) {
125+
arr.push({ name, value: '' });
110126
}
111127
});
112128

113-
// 更优雅:使用 Semantic UI Dropdown API 获取多选值,避免依赖 onChange 或标签扫描
114-
$(formID).find('.ui.multiple.dropdown').each(function() {
115-
const $dropdown = $(this);
116-
const $hidden = $dropdown.find('input[type="hidden"]');
117-
const name = $hidden.attr('name');
118-
if (!name || !name.endsWith('Raw')) return;
119-
let values = $dropdown.dropdown('get values') || [];
120-
// 统一为数字(若能转换),再序列化为 JSON 数组字符串
121-
values = values.map(v => { const n = parseInt(v); return isNaN(n) ? v : n; });
122-
data[name] = JSON.stringify(values);
123-
});
129+
// 4) 序列化为标准 x-www-form-urlencoded 字符串
130+
const serialized = $.param(arr);
124131

125132
// 按标准表单方式提交
126133
$.post(URL, serialized)
@@ -169,7 +176,7 @@ function addOrEditAlertRule(rule) {
169176
} else {
170177
modal.find(".ui.rule-enable.checkbox").checkbox("set unchecked");
171178
}
172-
modal.find("a.ui.label.visible").each((i, el) => {
179+
modal.find("a.ui.label").each((i, el) => {
173180
el.remove();
174181
});
175182

@@ -397,7 +404,7 @@ function addOrEditServer(server, conf) {
397404
modal.find("input[name=id]").val(server ? server.ID : null);
398405
modal.find("input[name=name]").val(server ? server.Name : null);
399406
modal.find("input[name=Tag]").val(server ? server.Tag : null);
400-
modal.find("a.ui.label.visible").each((i, el) => {
407+
modal.find("a.ui.label").each((i, el) => {
401408
el.remove();
402409
});
403410

@@ -537,7 +544,7 @@ function addOrEditMonitor(monitor) {
537544
} else {
538545
modal.find(".ui.nb-lt-notify.checkbox").checkbox("set unchecked");
539546
}
540-
modal.find("a.ui.label.visible").each((i, el) => {
547+
modal.find("a.ui.label").each((i, el) => {
541548
el.remove();
542549
});
543550
if (monitor && monitor.EnableTriggerTask) {
@@ -656,7 +663,7 @@ function addOrEditCron(cron) {
656663
modal.find("select[name=Cover]").val(cron ? cron.Cover : 0);
657664
modal.find("input[name=NotificationTag]").val(cron ? cron.NotificationTag : null);
658665
modal.find("input[name=Scheduler]").val(cron ? cron.Scheduler : null);
659-
modal.find("a.ui.label.visible").each((i, el) => {
666+
modal.find("a.ui.label").each((i, el) => {
660667
el.remove();
661668
});
662669

@@ -731,7 +738,28 @@ function addOrEditCron(cron) {
731738
},
732739
// 禁用onChange事件,避免干扰现有标签
733740
onChange: function(value, text, $choice) {
734-
// 不做任何操作,保持现有标签不变
741+
// 同步隐藏域,保持与标签一致
742+
var dropdown = $(this);
743+
var hiddenInput = dropdown.find('input[type="hidden"][name="ServersRaw"]');
744+
if (hiddenInput.length) {
745+
var currentValues = [];
746+
dropdown.find('a.ui.label').each(function() {
747+
var labelValue = $(this).attr('data-value');
748+
if (labelValue !== undefined && labelValue !== null && labelValue !== '') {
749+
var n = parseInt(labelValue);
750+
currentValues.push(isNaN(n) ? labelValue : n);
751+
}
752+
});
753+
// 若标签为空,回退到 API 获取值
754+
if (currentValues.length === 0) {
755+
var apiVals = dropdown.dropdown('get values') || [];
756+
for (var i = 0; i < apiVals.length; i++) {
757+
var n2 = parseInt(apiVals[i]);
758+
currentValues.push(isNaN(n2) ? apiVals[i] : n2);
759+
}
760+
}
761+
hiddenInput.val(JSON.stringify(currentValues));
762+
}
735763
}
736764
});
737765
}, 500); // 延迟500ms确保标签已经创建完成
@@ -847,7 +875,7 @@ function initializeServersDropdown() {
847875

848876
// 获取当前所有可见的标签
849877
var currentValues = [];
850-
dropdown.find('a.ui.label.visible').each(function() {
878+
dropdown.find('a.ui.label').each(function() {
851879
var labelValue = $(this).attr('data-value');
852880
if (labelValue) {
853881
currentValues.push(parseInt(labelValue));
@@ -871,7 +899,7 @@ function initializeServersDropdown() {
871899
// 更新隐藏的input值
872900
var hiddenInput = dropdown.find('input[type="hidden"]');
873901
var currentValues = [];
874-
dropdown.find('a.ui.label.visible').each(function() {
902+
dropdown.find('a.ui.label').each(function() {
875903
var labelValue = $(this).attr('data-value');
876904
if (labelValue && $(this)[0] !== $label[0]) {
877905
currentValues.push(parseInt(labelValue));
@@ -918,7 +946,7 @@ function initializeTasksDropdown() {
918946

919947
// 获取当前所有可见的标签
920948
var currentValues = [];
921-
dropdown.find('a.ui.label.visible').each(function() {
949+
dropdown.find('a.ui.label').each(function() {
922950
var labelValue = $(this).attr('data-value');
923951
if (labelValue) {
924952
currentValues.push(parseInt(labelValue));
@@ -942,7 +970,7 @@ function initializeTasksDropdown() {
942970
// 更新隐藏的input值
943971
var hiddenInput = dropdown.find('input[type="hidden"]');
944972
var currentValues = [];
945-
dropdown.find('a.ui.label.visible').each(function() {
973+
dropdown.find('a.ui.label').each(function() {
946974
var labelValue = $(this).attr('data-value');
947975
if (labelValue && $(this)[0] !== $label[0]) {
948976
currentValues.push(parseInt(labelValue));
@@ -989,7 +1017,7 @@ function initializeDDNSDropdown() {
9891017

9901018
// 获取当前所有可见的标签
9911019
var currentValues = [];
992-
dropdown.find('a.ui.label.visible').each(function() {
1020+
dropdown.find('a.ui.label').each(function() {
9931021
var labelValue = $(this).attr('data-value');
9941022
if (labelValue) {
9951023
currentValues.push(parseInt(labelValue));
@@ -1013,7 +1041,7 @@ function initializeDDNSDropdown() {
10131041
// 更新隐藏的input值
10141042
var hiddenInput = dropdown.find('input[type="hidden"]');
10151043
var currentValues = [];
1016-
dropdown.find('a.ui.label.visible').each(function() {
1044+
dropdown.find('a.ui.label').each(function() {
10171045
var labelValue = $(this).attr('data-value');
10181046
if (labelValue && $(this)[0] !== $label[0]) {
10191047
currentValues.push(parseInt(labelValue));

0 commit comments

Comments
 (0)