!44 增加功能:菜单维护增加服务器端验证

Merge pull request !44 from Argo/dev-Menus
This commit is contained in:
Argo 2019-11-14 19:33:40 +08:00 committed by Gitee
commit b8ea250a52
9 changed files with 101 additions and 25 deletions

View File

@ -44,5 +44,25 @@ namespace Bootstrap.Admin.Controllers.Api
{
return MenuHelper.RetrieveMenus(User.Identity.Name).Where(m => m.Menus.Count() > 0).OrderBy(m => m.Name).Select(m => m.Name);
}
/// <summary>
/// 通过指定菜单检查子菜单是否有子菜单
/// </summary>
/// <returns></returns>
[HttpGet("{id}")]
public bool ValidateMenuBySubMenu(string id)
{
return !MenuHelper.RetrieveAllMenus(User.Identity.Name).Where(m => m.ParentId == id).Any();
}
/// <summary>
/// 通过指定菜单检查父级菜单是否为菜单类型 资源与按钮返回 false
/// </summary>
/// <returns></returns>
[HttpGet("{id}")]
public bool ValidateParentMenuById(string id)
{
return MenuHelper.RetrieveAllMenus(User.Identity.Name).FirstOrDefault(m => m.Id == id)?.IsResource == 0;
}
}
}

View File

@ -147,10 +147,11 @@
<input type="text" class="form-control flex-sm-fill" id="url" placeholder="不可为空4000字以内" maxlength="4000" data-valid="true" />
</div>
<div class="form-group col-sm-6">
<label class="control-label" for="category">菜单类别</label>
<select data-toggle="lgbSelect" class="d-none" data-default-val="1" id="category">
<option value="0">系统菜单</option>
<option value="1">外部菜单</option>
<label class="control-label" for="isRes">菜单类型</label>
<select data-toggle="lgbSelect" class="d-none menuChild" data-default-val="0" id="isRes" data-valid="true">
<option value="0">菜单</option>
<option value="1">资源</option>
<option value="2">按钮</option>
</select>
</div>
<div class="form-group col-sm-6">
@ -162,14 +163,6 @@
<option value="_top">顶级窗口</option>
</select>
</div>
<div class="form-group col-sm-6">
<label class="control-label" for="isRes">菜单类型</label>
<select data-toggle="lgbSelect" class="d-none" data-default-val="0" id="isRes">
<option value="0">菜单</option>
<option value="1">资源</option>
<option value="2">按钮</option>
</select>
</div>
<div class="form-group col-sm-6">
<label class="control-label" for="app">所属应用</label>
<select data-toggle="lgbSelect" class="d-none" data-default-val="@BootstrapAppContext.AppId" id="app">
@ -179,6 +172,13 @@
}
</select>
</div>
<div class="form-group col-sm-6">
<label class="control-label" for="category">菜单类别</label>
<select data-toggle="lgbSelect" class="d-none" disabled data-default-val="1" id="category">
<option value="0">系统菜单</option>
<option value="1">外部菜单</option>
</select>
</div>
</div>
</form>
</div>

View File

@ -353,6 +353,10 @@ body.trans-mute * {
right: 45px;
}
li.is-disabled .dd3-content {
color: #c0c4cc;
}
@media (max-width: 480px) {
.dd3-content .menuType {
display: none;

View File

@ -131,10 +131,10 @@
var html = "";
$.each(menus, function (index, menu) {
if (menu.Menus.length === 0) {
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu));
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}" data-resource="{6}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu), menu.IsResource);
}
else {
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu));
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}" data-resource="{7}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu), menu.IsResource);
}
});
return html;
@ -144,10 +144,10 @@
var html = "";
$.each(menus, function (index, menu) {
if (menu.Menus.length === 0) {
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu));
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}" data-resource="{6}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu), menu.IsResource);
}
else {
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu));
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}" data-resource="{7}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu), menu.IsResource);
}
});
return html;

View File

@ -217,6 +217,7 @@ $(function () {
$btnSubmitMenu.data('type', 'parent');
$nestMenuInput.find('label:last').find('input').show();
$nestMenu.find('li.dd-item').hide().remove('[data-id="0"]');
$nestMenu.find('li[data-resource!="0"]').addClass('is-disabled').find(':radio').prop('disabled', true)
$nestMenu.find('li[data-category="' + $category.val() + '"]').show();
showDialog();
});
@ -240,8 +241,16 @@ $(function () {
var type = $(this).data('type');
switch (type) {
case "parent":
$parentMenuID.val($('.dd3-content :radio:checked').val());
$parentMenuName.val($('.dd3-content :radio:checked').next('span').text());
// 父级菜单不可以是资源或者按钮类型
var pId = $('.dd3-content :radio:checked').val();
var check = $.remoteValidate('api/Category/ValidateParentMenuById/' + pId);
if (check) {
$parentMenuID.val(pId);
$parentMenuName.val($('.dd3-content :radio:checked').next('span').text());
}
else {
return false;
}
break;
case "order":
var data = $nestMenu.find('li:visible');
@ -333,4 +342,19 @@ $(function () {
});
}
});
// 所属应用更新是联动菜单类别
var $app = $('#app').on('changed.lgbSelect', function (e) {
var defaultVal = $app.attr('data-default-val');
var val = defaultVal === $app.val() ? '0' : '1';
$category.lgbSelect('val', val);
})
if ($.isFunction($.validator)) {
$.validator.addMethod("menuChild", function (value, element) {
var id = $("#menuID").val();
var check = id === "" || value === "菜单" || $.remoteValidate('api/Category/ValidateMenuBySubMenu/' + id);
return check;
}, "拥有子菜单时菜单类型不可更改为资源或者按钮");
}
});

View File

@ -50,6 +50,10 @@
cursor: not-allowed;
}
.form-select.is-disabled .form-select-append {
color: #c0c4cc;
}
.form-select-input {
color: #606266;
outline: none;

View File

@ -114,11 +114,17 @@
// save attributes
var attrs = [];
["id", "data-default-val"].forEach(function (v, index) {
["id", "name", "class", "data-valid", "data-default-val"].forEach(function (v, index) {
var value = that.$element.attr(v);
if (value !== undefined) attrs.push({ name: v, value: value });
});
var disabled = this.$element.prop('disabled');
// set disabled property
if (disabled) {
this.disabled();
}
// replace element select -> input hidden
this.$element.remove();
this.$element = $('<input type="hidden" data-toggle="lgbSelect" />').val(that.val()).insertBefore(this.$input);
@ -139,12 +145,15 @@
this.$input.removeAttr('disabled');
};
_proto.reset = function (value) {
_proto.reset = function (value, init) {
var that = this;
// keep old value
var oldValue = this.$input.attr('value');
// default select value
if (init == undefined) init = true;
// warning: must use attr('value') method instead of val(). otherwise the others input html element will filled by first element value.
// see https://gitee.com/LongbowEnterprise/longbow-select/issues/IZ3BR?from=project-issue
this.$input.attr('value', '').removeClass('is-valid is-invalid');
@ -153,10 +162,12 @@
$.each(value, function (index) {
var $item = $('<a class="dropdown-item" href="#" data-val="' + this.value + '">' + this.text + '</a>');
that.$menus.append($item);
if (this.selected === true || this.value === oldValue || index === 0 || this.value === that.$element.attr('data-default-val')) {
that.$input.attr('value', this.text);
that.$element.val(this.value).attr('data-text', this.text);
$activeItem = $item;
if (init) {
if (this.selected === true || this.value === oldValue || index === 0 || this.value === that.$element.attr('data-default-val')) {
that.$input.attr('value', this.text);
that.$element.val(this.value).attr('data-text', this.text);
$activeItem = $item;
}
}
});
if ($activeItem !== null) $activeItem.addClass('active');

View File

@ -125,6 +125,19 @@
document.webkitIsFullScreen || window.fullscreen ||
false;
},
remoteValidate: function (url, method) {
if (method === undefined) method = 'get';
var check = false;
jQuery[method]({
url: $.formatUrl(url),
async: false,
cache: false,
success: function (result) {
check = result
}
});
return check;
},
bc: function (options) {
options = $.extend({
id: "",

View File

@ -183,7 +183,7 @@
callback: function (result) {
if (result) {
$(options.bootstrapTable).bootstrapTable('refresh');
handlerCallback.call(that, null, element, { oper: 'save', success: result, data: options.data });
handlerCallback.call(that, null, element, { oper: 'save', success: result, data: [options.data] });
}
}
});