mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2026-06-06 20:18:10 +08:00
style(menu): 精简菜单编辑表单布局
菜单表单改用通用栅格模块组织层级归属、跳转权限和展示策略,缩短说明文案并开启单行省略,使弹窗内容更紧凑。 将图标选择器合并到菜单图标输入框右侧按钮,保留实时图标预览,减少独立选择器字段占用的空间。 调整链接和权限预览、自动补全下拉样式及图标选择 iframe 打开方式,并补充测试覆盖新布局类名、预览字段和旧文案移除。
This commit is contained in:
parent
7e87c0d65a
commit
7408a162b6
@ -152,98 +152,121 @@ SCRIPT);
|
|||||||
->define(function ($form) use ($context) {
|
->define(function ($form) use ($context) {
|
||||||
$form->action(strval($context['actionUrl'] ?? ''))
|
$form->action(strval($context['actionUrl'] ?? ''))
|
||||||
->attrs(['id' => 'MenuForm', 'data-table-id' => 'MenuTable'])
|
->attrs(['id' => 'MenuForm', 'data-table-id' => 'MenuTable'])
|
||||||
->class('system-menu-form');
|
->class(['system-menu-form', 'ta-form-nowrap']);
|
||||||
$form->html('<style id="SystemMenuFormStyle">' . self::renderFormStyle() . '</style>');
|
$form->html('<style id="SystemMenuFormStyle">' . self::renderFormStyle() . '</style>');
|
||||||
|
|
||||||
FormModules::section($form, [
|
FormModules::section($form, [
|
||||||
'title' => '层级归属',
|
'title' => '层级归属',
|
||||||
'description' => '先确认上级菜单与菜单名称。分组菜单建议将链接留空或填写 #,业务页面建议直接指向真实页面节点。',
|
'description' => '确认上级与名称,分组菜单可用 #。',
|
||||||
], function ($section) use ($context) {
|
], function ($section) use ($context) {
|
||||||
$grid = $section->div()->class('layui-row layui-col-space15');
|
$grid = FormModules::grid($section, 2, 'system-menu-form-row ta-form-grid-compact', 8);
|
||||||
|
|
||||||
$left = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
$parent = FormModules::gridColumn($grid, 2, 'system-menu-basic-col');
|
||||||
$left->fields(function ($fields) use ($context) {
|
$parent->fields(function ($fields) use ($context) {
|
||||||
$fields->select('pid', '上级菜单', 'Parent Menu', true, '请选择上级菜单或顶级菜单。当前仅支持三级菜单结构,叶子菜单不能继续挂载子节点。', self::buildParentOptions(is_array($context['menus'] ?? null) ? $context['menus'] : []), '', ['lay-search' => null])
|
$fields->select('pid', '上级菜单', 'Parent Menu', true, '选择上级,叶子菜单不可挂载。', self::buildParentOptions(is_array($context['menus'] ?? null) ? $context['menus'] : []), '', ['lay-search' => null]);
|
||||||
->text('title', '菜单名称', 'Menu Title', true, '请填写菜单名称,建议控制在 4-8 个汉字,便于导航栏展示。', null, [
|
|
||||||
'placeholder' => '请输入菜单名称',
|
|
||||||
'required-error' => '菜单名称不能为空!',
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$right = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
$title = FormModules::gridColumn($grid, 2, 'system-menu-basic-col');
|
||||||
FormModules::readonlyField($right, [
|
$title->fields(function ($fields) {
|
||||||
'title' => '结构约束',
|
$fields->text('title', '菜单名称', 'Menu Title', true, '建议 4-8 个汉字。', null, [
|
||||||
'subtitle' => 'Structure Rules',
|
'placeholder' => '请输入菜单名称',
|
||||||
'value' => '顶级菜单 / 二级分组 / 三级页面',
|
'required-error' => '菜单名称不能为空!',
|
||||||
'help' => '系统会在保存时校验父子关系,禁止挂到叶子菜单下,也禁止形成循环层级。',
|
]);
|
||||||
]);
|
});
|
||||||
|
|
||||||
|
FormModules::note($section, '层级最多三级:顶级菜单 / 二级分组 / 三级页面。', 'help-block color-desc system-menu-section-note');
|
||||||
});
|
});
|
||||||
|
|
||||||
FormModules::section($form, [
|
FormModules::section($form, [
|
||||||
'title' => '跳转与权限',
|
'title' => '跳转与权限',
|
||||||
'description' => '菜单链接建议填写完整页面节点,如 system/user/index。权限节点为空时,系统会优先根据菜单链接解析访问控制节点。',
|
'description' => '设置菜单链接、参数与权限节点。',
|
||||||
], function ($section) {
|
], function ($section) {
|
||||||
$grid = $section->div()->class('layui-row layui-col-space15');
|
$grid = FormModules::grid($section, 2, 'system-menu-form-row ta-form-grid-compact', 8);
|
||||||
|
|
||||||
$route = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
$route = FormModules::gridColumn($grid, 2);
|
||||||
$route->fields(function ($fields) {
|
$route->fields(function ($fields) {
|
||||||
$fields->text('url', '菜单链接', 'Menu Url', false, '支持系统页面节点、外部地址、插件布局地址或 # 分组节点。保存时会自动标准化链接格式。', null, [
|
$fields->text('url', '菜单链接', 'Menu Url', false, '页面节点、外链或 # 分组。', null, [
|
||||||
'placeholder' => '例如:system/user/index、https://example.com/docs 或 #',
|
'placeholder' => '例如:system/user/index、https://example.com/docs 或 #',
|
||||||
])->text('params', '链接参数', 'Query Params', false, '设置菜单链接的 GET 访问参数,如 tab=user&mode=list。', null, [
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$permission = FormModules::gridColumn($grid, 2);
|
||||||
|
$permission->fields(function ($fields) {
|
||||||
|
$fields->text('node', '权限节点', 'Permission Node', false, '留空时按菜单链接推导。', null, [
|
||||||
|
'placeholder' => '例如:system/user/index',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$params = FormModules::gridColumn($grid, 2);
|
||||||
|
$params->fields(function ($fields) {
|
||||||
|
$fields->text('params', '链接参数', 'Query Params', false, 'GET 参数,如 tab=user。', null, [
|
||||||
'placeholder' => '请输入链接参数',
|
'placeholder' => '请输入链接参数',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
$permission = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
$target = FormModules::gridColumn($grid, 2);
|
||||||
$permission->fields(function ($fields) {
|
$target->fields(function ($fields) {
|
||||||
$fields->text('node', '权限节点', 'Permission Node', false, '显式指定注释式 RBAC 节点。若留空,将按菜单链接推导默认访问节点。', null, [
|
$fields->select('target', '打开方式', 'Target Window', true, '选择链接打开方式。', [
|
||||||
'placeholder' => '例如:system/user/index',
|
|
||||||
])->select('target', '打开方式', 'Target Window', true, '设置菜单链接的打开方式。', [
|
|
||||||
'_self' => '当前窗口',
|
'_self' => '当前窗口',
|
||||||
'_blank' => '新窗口',
|
'_blank' => '新窗口',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
$preview = $section->div()->class('layui-row layui-col-space15');
|
$preview = FormModules::grid($section, 2, 'system-menu-preview-row ta-form-grid-compact', 8);
|
||||||
$previewUrl = $preview->div()->class('layui-col-xs12 layui-col-md6');
|
$previewUrl = FormModules::gridColumn($preview, 2, 'system-menu-preview-col');
|
||||||
FormModules::readonlyField($previewUrl, [
|
FormModules::readonlyField($previewUrl, [
|
||||||
'title' => '标准化链接预览',
|
'title' => '链接预览',
|
||||||
'subtitle' => 'Normalized Target',
|
'subtitle' => 'Normalized',
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'input_attrs' => [
|
'input_attrs' => [
|
||||||
'data-menu-url-preview' => null,
|
'data-menu-url-preview' => null,
|
||||||
'placeholder' => '根据菜单链接与参数自动生成',
|
'placeholder' => '保存前自动预览',
|
||||||
],
|
],
|
||||||
'help' => '预览仅用于提示保存结果,实际写库仍以后端校验为准。',
|
'help' => '预览标准化后的链接。',
|
||||||
]);
|
]);
|
||||||
$previewNode = $preview->div()->class('layui-col-xs12 layui-col-md6');
|
$previewNode = FormModules::gridColumn($preview, 2, 'system-menu-preview-col');
|
||||||
FormModules::readonlyField($previewNode, [
|
FormModules::readonlyField($previewNode, [
|
||||||
'title' => '鉴权节点预览',
|
'title' => '权限预览',
|
||||||
'subtitle' => 'Resolved Node',
|
'subtitle' => 'Resolved',
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'input_attrs' => [
|
'input_attrs' => [
|
||||||
'data-menu-node-preview' => null,
|
'data-menu-node-preview' => null,
|
||||||
'placeholder' => '未显式设置时按菜单链接推导',
|
'placeholder' => '留空时自动推导',
|
||||||
],
|
],
|
||||||
'help' => '权限节点必须来自注释式 RBAC 的有效 @auth 节点。',
|
'help' => '预览 RBAC 访问节点。',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
FormModules::section($form, [
|
FormModules::section($form, [
|
||||||
'title' => '展示策略',
|
'title' => '展示策略',
|
||||||
'description' => '统一维护菜单图标、排序权重与启停状态。图标支持 layui 与 iconfont 字体类名。',
|
'description' => '设置图标、排序和启停状态。',
|
||||||
], function ($section) {
|
], function ($section) {
|
||||||
$grid = $section->div()->class('layui-row layui-col-space15');
|
$grid = FormModules::grid($section, 3, 'system-menu-form-row ta-form-grid-compact', 8);
|
||||||
|
|
||||||
$fields = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
$iconField = FormModules::gridColumn($grid, 3, 'system-menu-display-col system-menu-icon-col');
|
||||||
$fields->fields(function ($fields) {
|
$iconField->fields(function ($fields) {
|
||||||
$status = $fields->text('icon', '菜单图标', 'Menu Icon', false, '可手动输入图标类名,或通过右侧图标选择器回填。', null, [
|
$icon = $fields->text('icon', '菜单图标', 'Menu Icon', false, '输入类名或点击选择。', null, [
|
||||||
'placeholder' => '例如:layui-icon layui-icon-set-fill',
|
'placeholder' => '例如:layui-icon layui-icon-set-fill',
|
||||||
])->text('sort', '排序权重', 'Sort Order', false, '数值越大越靠前。', null, [
|
]);
|
||||||
|
$icon->inputRightIcon('layui-icon-theme system-menu-icon-field-button', [
|
||||||
|
'data-open-menu-icon' => null,
|
||||||
|
'title' => BuilderLang::text('选择菜单图标'),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$sortField = FormModules::gridColumn($grid, 3, 'system-menu-display-col system-menu-sort-col');
|
||||||
|
$sortField->fields(function ($fields) {
|
||||||
|
$fields->text('sort', '排序权重', 'Sort Order', false, '数值越大越靠前。', null, [
|
||||||
'type' => 'number',
|
'type' => 'number',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'placeholder' => '请输入排序权重',
|
'placeholder' => '请输入排序权重',
|
||||||
])->defaultValue(0)->radio('status', '使用状态', 'Status', '', true, [
|
])->defaultValue(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
$statusField = FormModules::gridColumn($grid, 3, 'system-menu-display-col system-menu-status-col');
|
||||||
|
$statusField->fields(function ($fields) {
|
||||||
|
$status = $fields->radio('status', '使用状态', 'Status', '', true, [
|
||||||
'required-error' => '请选择当前菜单的启用状态。',
|
'required-error' => '请选择当前菜单的启用状态。',
|
||||||
]);
|
]);
|
||||||
$status->body()->class('system-menu-status-options')->end()->options([
|
$status->body()->class('system-menu-status-options')->end()->options([
|
||||||
@ -251,25 +274,7 @@ SCRIPT);
|
|||||||
0 => '已禁用',
|
0 => '已禁用',
|
||||||
])->defaultValue('1');
|
])->defaultValue('1');
|
||||||
});
|
});
|
||||||
|
$section->div()->class('layui-form-mid color-desc system-menu-icon-preview')->html(sprintf(
|
||||||
$picker = $grid->div()->class('layui-col-xs12 layui-col-md6');
|
|
||||||
FormModules::pickerField($picker, [
|
|
||||||
'title' => '图标选择器',
|
|
||||||
'subtitle' => 'Icon Picker',
|
|
||||||
'value' => '点击打开图标选择器',
|
|
||||||
'class' => 'block system-menu-icon-picker',
|
|
||||||
'control_class' => 'relative',
|
|
||||||
'input_class' => 'layui-input pr40',
|
|
||||||
'attrs' => ['data-open-menu-icon' => null],
|
|
||||||
'input_attrs' => [
|
|
||||||
'data-open-menu-icon' => null,
|
|
||||||
'data-menu-icon-picker-text' => null,
|
|
||||||
'placeholder' => '点击选择图标并自动回填',
|
|
||||||
],
|
|
||||||
'icon_attrs' => ['data-open-menu-icon' => null],
|
|
||||||
'help' => '选择后会自动同步到“菜单图标”字段,并实时预览当前图标样式。',
|
|
||||||
]);
|
|
||||||
$picker->div()->class('layui-form-mid color-desc system-menu-icon-preview')->html(sprintf(
|
|
||||||
'<span class="inline-flex items-center"><i class="layui-icon layui-icon-set-fill font-s14 mr-8" data-menu-icon-preview></i><span data-menu-icon-preview-text>%s</span></span>',
|
'<span class="inline-flex items-center"><i class="layui-icon layui-icon-set-fill font-s14 mr-8" data-menu-icon-preview></i><span data-menu-icon-preview-text>%s</span></span>',
|
||||||
self::escape(BuilderLang::text('未设置图标'))
|
self::escape(BuilderLang::text('未设置图标'))
|
||||||
));
|
));
|
||||||
@ -353,23 +358,24 @@ SCRIPT;
|
|||||||
private static function renderFormStyle(): string
|
private static function renderFormStyle(): string
|
||||||
{
|
{
|
||||||
return <<<'STYLE'
|
return <<<'STYLE'
|
||||||
#MenuForm .system-menu-icon-picker .layui-input {
|
#MenuForm .system-menu-section-note {
|
||||||
cursor: pointer;
|
margin-top: -2px;
|
||||||
padding-right: 44px !important;
|
margin-bottom: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
#MenuForm .system-menu-icon-picker .input-right-icon {
|
#MenuForm .system-menu-preview-row {
|
||||||
top: 1px;
|
margin-top: 2px;
|
||||||
right: 1px;
|
}
|
||||||
width: 34px;
|
#MenuForm .system-menu-preview-col .layui-input {
|
||||||
height: 32px;
|
cursor: default;
|
||||||
line-height: 32px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-left: 1px solid var(--ta-border-color, #dce8e5);
|
|
||||||
border-radius: 0 3px 3px 0;
|
|
||||||
}
|
}
|
||||||
#MenuForm .system-menu-icon-preview {
|
#MenuForm .system-menu-icon-preview {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
min-height: 20px;
|
min-height: 20px;
|
||||||
margin-top: 8px;
|
margin-top: 0;
|
||||||
padding: 0 2px;
|
padding: 0 2px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
@ -377,6 +383,29 @@ SCRIPT;
|
|||||||
width: 18px;
|
width: 18px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
#MenuForm [data-field-name="icon"] .layui-input {
|
||||||
|
padding-right: 44px !important;
|
||||||
|
}
|
||||||
|
#MenuForm [data-field-name="icon"] .system-menu-icon-field-button {
|
||||||
|
top: 1px;
|
||||||
|
right: 1px;
|
||||||
|
width: 34px;
|
||||||
|
height: 32px;
|
||||||
|
color: var(--ta-accent, #009688);
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 32px !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: center;
|
||||||
|
border-left: 1px solid var(--ta-border-color, #dce8e5);
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
background: var(--ta-surface-soft, #f7fbfb) !important;
|
||||||
|
}
|
||||||
|
#MenuForm [data-field-name="icon"] .system-menu-icon-field-button:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--ta-accent, #009688) !important;
|
||||||
|
}
|
||||||
#MenuForm [data-field-name="status"] .system-menu-status-options {
|
#MenuForm [data-field-name="status"] .system-menu-status-options {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
min-height: 34px !important;
|
min-height: 34px !important;
|
||||||
@ -384,13 +413,16 @@ SCRIPT;
|
|||||||
line-height: 32px !important;
|
line-height: 32px !important;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
border-color: var(--ta-border-color, #dce8e5);
|
border-color: var(--ta-border-color, #dce8e5);
|
||||||
background: var(--ta-surface-soft, #f7fbfb) !important;
|
background: var(--ta-surface-soft, #f7fbfb) !important;
|
||||||
}
|
}
|
||||||
#MenuForm [data-field-name="status"] .system-menu-status-options .layui-form-radio {
|
#MenuForm [data-field-name="status"] .system-menu-status-options .layui-form-radio {
|
||||||
margin: 0 18px 0 0;
|
margin: 0 12px 0 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#MenuForm [data-field-name="status"] .system-menu-status-options .layui-form-radio > i {
|
#MenuForm [data-field-name="status"] .system-menu-status-options .layui-form-radio > i {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
@ -404,6 +436,7 @@ STYLE;
|
|||||||
return sprintf(<<<'SCRIPT'
|
return sprintf(<<<'SCRIPT'
|
||||||
$.module.use(['jquery.autocompleter'], function () {
|
$.module.use(['jquery.autocompleter'], function () {
|
||||||
var menuForm = document.getElementById('MenuForm') || {};
|
var menuForm = document.getElementById('MenuForm') || {};
|
||||||
|
var $form = $('#MenuForm');
|
||||||
var menuFormNodes = JSON.parse((menuForm.dataset || {}).menuNodes || '[]');
|
var menuFormNodes = JSON.parse((menuForm.dataset || {}).menuNodes || '[]');
|
||||||
var menuFormAuths = JSON.parse((menuForm.dataset || {}).menuAuths || '[]');
|
var menuFormAuths = JSON.parse((menuForm.dataset || {}).menuAuths || '[]');
|
||||||
var iconPickerUrl = String((menuForm.dataset || {}).menuIconPickerUrl || '');
|
var iconPickerUrl = String((menuForm.dataset || {}).menuIconPickerUrl || '');
|
||||||
@ -435,57 +468,60 @@ $.module.use(['jquery.autocompleter'], function () {
|
|||||||
return parts.join('/');
|
return parts.join('/');
|
||||||
};
|
};
|
||||||
var syncIconPreview = function () {
|
var syncIconPreview = function () {
|
||||||
var value = $.trim(String($('[name="icon"]').val() || ''));
|
var value = $.trim(String($form.find('[name="icon"]').val() || ''));
|
||||||
var preview = $('[data-menu-icon-preview]').get(0);
|
var preview = $form.find('[data-menu-icon-preview]').get(0);
|
||||||
if (preview) {
|
if (preview) {
|
||||||
preview.className = value || 'layui-icon layui-icon-set-fill';
|
preview.className = value || 'layui-icon layui-icon-set-fill font-s14 mr-8';
|
||||||
}
|
}
|
||||||
$('[data-menu-icon-preview-text]').text(value || menuI18n.iconNotSet);
|
$form.find('[data-menu-icon-preview-text]').text(value || menuI18n.iconNotSet);
|
||||||
$('[data-menu-icon-picker-text]').val(value || '').attr('title', value || '');
|
|
||||||
};
|
};
|
||||||
var syncTargetPreview = function () {
|
var syncTargetPreview = function () {
|
||||||
var url = $.trim(String($('[name="url"]').val() || ''));
|
var url = $.trim(String($form.find('[name="url"]').val() || ''));
|
||||||
var params = $.trim(String($('[name="params"]').val() || '')).replace(/^[?&]+/, '');
|
var params = $.trim(String($form.find('[name="params"]').val() || '')).replace(/^[?&]+/, '');
|
||||||
var target = normalizeTarget(url);
|
var target = normalizeTarget(url);
|
||||||
if (target !== '#' && params) {
|
if (target !== '#' && params) {
|
||||||
target += (/^(https?:\/\/|\/\/)/i.test(target) && target.indexOf('?') >= 0 ? '&' : '?') + params;
|
target += (/^(https?:\/\/|\/\/)/i.test(target) && target.indexOf('?') >= 0 ? '&' : '?') + params;
|
||||||
}
|
}
|
||||||
$('[data-menu-url-preview]').val(target || '#');
|
$form.find('[data-menu-url-preview]').val(target || '#');
|
||||||
|
|
||||||
var node = normalizeNode($('[name="node"]').val());
|
var node = normalizeNode($form.find('[name="node"]').val());
|
||||||
if (!node && target !== '#' && !/^(https?:\/\/|\/\/|@|\[)/i.test(target)) {
|
if (!node && target !== '#' && !/^(https?:\/\/|\/\/|@|\[)/i.test(target)) {
|
||||||
node = target.split('?')[0].split('/').slice(0, 3).join('/');
|
node = target.split('?')[0].split('/').slice(0, 3).join('/');
|
||||||
}
|
}
|
||||||
$('[data-menu-node-preview]').val(node || menuI18n.nodeNotExplicitlySet);
|
$form.find('[data-menu-node-preview]').val(node || menuI18n.nodeNotExplicitlySet);
|
||||||
};
|
};
|
||||||
$('body').off('click', '[data-open-menu-icon]').on('click', '[data-open-menu-icon]', function () {
|
$('body').off('click', '[data-open-menu-icon]').on('click', '[data-open-menu-icon]', function () {
|
||||||
if (!iconPickerUrl) return false;
|
if (!iconPickerUrl) return false;
|
||||||
$.form.modal(iconPickerUrl + (iconPickerUrl.indexOf('?') >= 0 ? '&' : '?') + 'field=' + encodeURIComponent('icon'), {}, menuI18n.chooseMenuIcon, undefined, undefined, undefined, '900px');
|
$.form.iframe(iconPickerUrl + (iconPickerUrl.indexOf('?') >= 0 ? '&' : '?') + 'field=' + encodeURIComponent('icon'), menuI18n.chooseMenuIcon, ['900px', '700px']);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
$('[name="icon"]').on('change input', syncIconPreview);
|
$form.find('input[name=url]').autocompleter({
|
||||||
$('[name="url"], [name="params"], [name="node"]').on('change input', syncTargetPreview);
|
|
||||||
$('input[name=url]').autocompleter({
|
|
||||||
limit: 6,
|
limit: 6,
|
||||||
|
customClass: ['ta-form-autocompleter'],
|
||||||
highlightMatches: true,
|
highlightMatches: true,
|
||||||
template: '{{ label }} <span> {{ title }} </span>',
|
template: '{{ label }} <span> {{ title }} </span>',
|
||||||
callback: function (node) {
|
callback: function (node) {
|
||||||
if (!$('input[name=node]').val()) $('input[name=node]').val(node).trigger('change');
|
if (!$form.find('input[name=node]').val()) $form.find('input[name=node]').val(node).trigger('change');
|
||||||
|
syncTargetPreview();
|
||||||
},
|
},
|
||||||
source: (function (subjects, data) {
|
source: (function (subjects, data) {
|
||||||
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
|
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
|
||||||
return data;
|
return data;
|
||||||
})(menuFormNodes, [])
|
})(menuFormNodes, [])
|
||||||
});
|
});
|
||||||
$('input[name=node]').autocompleter({
|
$form.find('input[name=node]').autocompleter({
|
||||||
limit: 5,
|
limit: 5,
|
||||||
|
customClass: ['ta-form-autocompleter'],
|
||||||
highlightMatches: true,
|
highlightMatches: true,
|
||||||
template: '{{ label }} <span> {{ title }} </span>',
|
template: '{{ label }} <span> {{ title }} </span>',
|
||||||
|
callback: syncTargetPreview,
|
||||||
source: (function (subjects, data) {
|
source: (function (subjects, data) {
|
||||||
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
|
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
|
||||||
return data;
|
return data;
|
||||||
})(menuFormAuths, [])
|
})(menuFormAuths, [])
|
||||||
});
|
});
|
||||||
|
$form.find('[name="icon"]').on('change input', syncIconPreview);
|
||||||
|
$form.find('[name="url"], [name="params"], [name="node"]').on('change input', syncTargetPreview);
|
||||||
syncIconPreview();
|
syncIconPreview();
|
||||||
syncTargetPreview();
|
syncTargetPreview();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -159,10 +159,38 @@ class MenuControllerTest extends SqliteIntegrationTestCase
|
|||||||
|
|
||||||
$this->assertStringContainsString('form-builder-schema', $html);
|
$this->assertStringContainsString('form-builder-schema', $html);
|
||||||
$this->assertStringContainsString('name="title"', $html);
|
$this->assertStringContainsString('name="title"', $html);
|
||||||
|
$this->assertStringContainsString('ta-form-nowrap', $html);
|
||||||
|
$this->assertStringContainsString('data-form-builder-standard-style', $html);
|
||||||
|
$this->assertStringContainsString('system-menu-form-row', $html);
|
||||||
|
$this->assertStringContainsString('layui-col-space8', $html);
|
||||||
|
$this->assertStringContainsString('ta-form-grid-compact', $html);
|
||||||
|
$this->assertStringContainsString('ta-form-grid-2', $html);
|
||||||
|
$this->assertStringContainsString('ta-form-grid-3', $html);
|
||||||
|
$this->assertStringContainsString('layui-col-xs6 ta-form-grid-col', $html);
|
||||||
|
$this->assertStringContainsString('layui-col-xs4 ta-form-grid-col', $html);
|
||||||
|
$this->assertStringContainsString('width:50%!important', $html);
|
||||||
|
$this->assertStringContainsString('width:33.333333%!important', $html);
|
||||||
|
$this->assertStringContainsString('margin-bottom:6px', $html);
|
||||||
|
$this->assertStringContainsString('system-menu-basic-col', $html);
|
||||||
|
$this->assertStringContainsString('system-menu-display-col', $html);
|
||||||
$this->assertStringContainsString('data-menu-nodes=', $html);
|
$this->assertStringContainsString('data-menu-nodes=', $html);
|
||||||
$this->assertStringContainsString('data-menu-auths=', $html);
|
$this->assertStringContainsString('data-menu-auths=', $html);
|
||||||
$this->assertStringContainsString('data-open-menu-icon', $html);
|
$this->assertStringContainsString('data-open-menu-icon', $html);
|
||||||
$this->assertStringContainsString('标准化链接预览', $html);
|
$this->assertStringContainsString('ta-form-autocompleter', $html);
|
||||||
|
$this->assertStringContainsString('top:58px', $html);
|
||||||
|
$this->assertStringContainsString('层级最多三级', $html);
|
||||||
|
$this->assertStringContainsString('链接预览', $html);
|
||||||
|
$this->assertStringContainsString('权限预览', $html);
|
||||||
|
$this->assertStringContainsString('data-menu-url-preview', $html);
|
||||||
|
$this->assertStringContainsString('data-menu-node-preview', $html);
|
||||||
|
$this->assertStringContainsString('data-menu-icon-preview', $html);
|
||||||
|
$this->assertStringContainsString('选择上级,叶子菜单不可挂载。', $html);
|
||||||
|
$this->assertStringContainsString('GET 参数,如 tab=user。', $html);
|
||||||
|
$this->assertStringNotContainsString('当前仅支持三级菜单结构', $html);
|
||||||
|
$this->assertStringNotContainsString('保存时会自动标准化链接格式', $html);
|
||||||
|
$this->assertStringNotContainsString('标准化链接预览', $html);
|
||||||
|
$this->assertStringNotContainsString('鉴权节点预览', $html);
|
||||||
|
$this->assertStringNotContainsString('图标选择器', $html);
|
||||||
$this->assertStringContainsString('name="target"', $html);
|
$this->assertStringContainsString('name="target"', $html);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,10 +200,10 @@ class MenuControllerTest extends SqliteIntegrationTestCase
|
|||||||
|
|
||||||
$html = $this->callActionHtml('add', ['pid' => 0]);
|
$html = $this->callActionHtml('add', ['pid' => 0]);
|
||||||
|
|
||||||
$this->assertStringContainsString('Icon Picker', $html);
|
|
||||||
$this->assertStringContainsString('Icon not set', $html);
|
|
||||||
$this->assertStringContainsString('Choose Menu Icon', $html);
|
$this->assertStringContainsString('Choose Menu Icon', $html);
|
||||||
$this->assertStringNotContainsString('未设置图标', $html);
|
$this->assertStringContainsString('Icon not set', $html);
|
||||||
|
$this->assertStringNotContainsString('Icon Picker', $html);
|
||||||
|
$this->assertStringNotContainsString('选择菜单图标', $html);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddAndEditPersistMenuFields(): void
|
public function testAddAndEditPersistMenuFields(): void
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user