// +---------------------------------------------------------------------- // | layui表单设计器 [基于Sortable开发] // +---------------------------------------------------------------------- // | Copyright (c) 2020-2030 http://www.swiftadmin.net // +---------------------------------------------------------------------- // | git://github.com/meystack/layui-form-design.git 616550110 // +---------------------------------------------------------------------- // | Author: meystack Apache 2.0 License Code // +---------------------------------------------------------------------- layui.define(['form', 'jquery', 'layer', 'admin', 'cascader'], function (exports) { "use strict"; var $ = layui.$ , form = layui.form , layer = layui.layer , admin = layui.admin , cascader = layui.cascader //模块名 , MOD_NAME = 'formDesign' , MOD_INDEX = 'layui_' + MOD_NAME + '_index' //模块索引名 , TAG_NAME = undefined //外部接口 , MODULE_FORMDESIGN_NAME = { config: {} , index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0 //设置全局项 , set: function (options) { var that = this; that.config = $.extend({}, that.config, options); return that; } //事件 , on: function (events, callback) { return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 , thisTags = function () { var that = this , options = that.config , id = options.id || that.index; thisTags.that[id] = that; //记录当前实例对象 return { config: options //重置实例 , reload: function (options) { that.reload.call(that, options); } } } //字符常量 , STR_ELEM = 'layui-MODULE_FORMDESIGN_NAME', STR_HIDE = 'layui-hide', STR_DISABLED = 'layui-disabled' , STR_NONE = 'layui-none', STR_EMPTY = '' , STR_FORMDESIGN = 'formDesign', LAY_FORM_ITEM = 'layui-form-item', LAY_FORM_DIV = '' , LAY_INLINE_CLASS = 'layui-input-inline', LAY_BLOCK_CLASS = 'layui-input-block' , LAY_INPUT_INLINE = '
', LAY_INPUT_BLOCK = '
' , LAY_COMPONENT_MOVE = 'layui-component-move', LAY_COMPONENT_TOOLS = 'layui-component-tools' //主模板 , TPL_MAIN = ['
从左侧拖入组件进行表单设计
'].join('') , TPL_RIGHT_MAIN = ['
请点击组件修改属性
'].join('') //构造器 , Class = function (options) { var that = this; that.index = ++MODULE_FORMDESIGN_NAME.index; that.config = $.extend({}, that.config, MODULE_FORMDESIGN_NAME.config, options); that.render(); }; //默认配置 Class.prototype.config = { id: null, data: [], // 当前元素集合 eval: '', // 当前HTML数据 count: 0, // 当前组件总数 state: null, // 当前活动实例 index: [], // 组件分类索引 itemIndex: {}, // 子组件元素索引 master: undefined // 主界面拖拽实例 }; // 重载实例 Class.prototype.reload = function (options) { var that = this; // 防止数组深度合并 layui.each(options, function (key, item) { if (layui._typeof(item) === 'array') delete that.config[key]; }); that.config = $.extend(true, {}, that.config, options); that.render(); }; // 语言标签 Class.prototype.lang = { index: "序号", tag: "组件类型", label: "标签名", name: "* 字段名", type: '表单类型', placeholder: '占位提示', default: '默认值', min: '最小', // 当类型为number的时候 max: '最大', data_min: '最小', // 自动渲染组件 data_max: '最大', maxlength: '文本长度', // text lay_verify: '验证规则', width: '组件宽度', height: '组件高度', lay_skin: '样式', labelhide: '隐藏标签', labelwidth: '文本宽度', uploadtype: '上传样式', readonly: "只读属性", disabled: "禁用表单", required: "必填项", lay_search: '搜索模式', data_datetype: "日期类型", options: "选项", data_maxvalue: "最大值", data_minvalue: "最小值", data_dateformat: "显示格式", data_half: "显示半星", theme: "皮肤", data_theme: "主题", data_color: "颜色", data_length: "星星个数", interval: "间隔毫秒", data_range: '左右面板', data_step: '步长', data_input: '输入框', data_showstep: '显示断点', data_default: '默认值', data_value: '选项值', data_parents: '关联父类', tips: '文字提示', size: '文件大小', data_size: '文件大小', data_accept: '上传类型', msg: '消息提示', offset: '提示位置', btnsize: '按钮大小', text: '文本', textarea: '多行文本', border: '分割线', column: '栅格列数', editorType: '编辑器类型', } // 组件属性 Class.prototype.fields = { input: { index: '-1', tag: 'input', name: '-1', label: "单行文本", type: 'text', placeholder: "请输入", default: '', labelwidth: '110', width: 100, maxlength: '', min: 0, max: 0, required: false, readonly: false, disabled: false, labelhide: false, lay_verify: '' }, textarea: { index: '-1', tag: 'textarea', name: '-1', label: "多行文本", placeholder: "请输入", default: '', maxlength: '', labelwidth: 110, width: 100, required: false, readonly: false, disabled: false, labelhide: false }, radio: { index: '-1', tag: "radio", name: '-1', label: "单选框", labelwidth: 110, width: 100, disabled: false, labelhide: false, options: [ { title: '男', value: '1', checked: true, }, { title: '女', value: '0', checked: false, } ] }, checkbox: { index: '-1', tag: "checkbox", name: '-1', label: "多选框", lay_skin: 'primary', labelwidth: 110, width: 100, disabled: false, labelhide: false, options: [ { title: '写作', value: 'write', checked: true, }, { title: '阅读', value: 'read', checked: true, }, { title: '游戏', value: 'game', checked: false, } ] }, select: { index: '-1', tag: "select", name: '-1', label: "下拉框", labelwidth: 110, width: 100, lay_search: false, disabled: false, required: false, labelhide: false, options: [ { title: '选项1', value: '1', checked: false, }, { title: '选项2', value: '2', checked: true, }, { title: '选项3', value: '3', checked: false, } ] }, date: { index: '-1', tag: "date", name: '-1', label: "日期组件", labelwidth: 110, width: 100, data_datetype: "datetime", // year month date time datetime = select data_dateformat: "yyyy-MM-dd HH:mm:ss", placeholder: 'yyyy-MM-dd', data_maxvalue: "9999-12-31", data_minvalue: "1900-01-01", data_range: false, // switch readonly: false, disabled: false, required: false, labelhide: false, }, colorpicker: { index: '-1', tag: "colorpicker", name: '-1', label: "颜色选择器", labelwidth: 110, width: 100, disabled: false, required: false, labelhide: false, }, slider: { index: '-1', tag: "slider", name: '-1', label: "滑块", labelwidth: 110, width: 100, data_max: 100, data_min: 0, data_step: 1, data_default: 10, data_theme: '#1890ff', data_input: false, data_showstep: false, disabled: false, labelhide: false, }, rate: { index: '-1', tag: "rate", name: '-1', label: "评分", labelwidth: 110, width: 100, data_default: 1, data_length: 5, data_half: false, data_theme: '#1890ff', readonly: false, labelhide: false, }, switch: { index: '-1', tag: "switch", name: '-1', label: "开关", labelwidth: 110, width: 100, disabled: false, labelhide: false, }, cascader: { index: '-1', tag: "cascader", name: '-1', label: "级联选择器", data_value: "label", // 默认为标签 labelwidth: 110, width: 100, data_parents: true, labelhide: false }, editor: { index: '-1', tag: "editor", name: '-1', label: "编辑器", editorType: 'lay-editor', // 编辑器类型 labelwidth: 110, width: 100, labelhide: false }, upload: { index: '-1', tag: "upload", name: '-1', label: "文件上传", uploadtype: 'file', labelwidth: 110, width: 100, data_size: 102400, data_accept: 'file', // 文件 音频 视频 images disabled: false, required: false, labelhide: false }, tags: { index: '-1', tag: "tags", name: '-1', label: "关键词", labelwidth: 110, width: 100, labelhide: false, }, json: { index: '-1', tag: "json", name: '-1', label: "数组组件", labelwidth: 110, width: 100, labelhide: false, }, tips: { index: '-1', tag: "tips", name: '-1', msg: '消息提示', offset: 4, }, button: { index: '-1', tag: "button", name: '-1', text: '按钮', theme: '', btnsize: '', }, note: { index: '-1', tag: "note", name: '-1', textarea: '便签信息', width: 100, }, subtraction: { index: '-1', tag: "subtraction", name: '-1', border: '', width: 100, }, space: { index: '-1', tag: "space", name: '-1', height: 10, // 像素 }, tab: { index: '-1', tag: "tab", name: '-1', options: [ { title: '选项1', value: 'tab1', checked: true, }, { title: '选项2', value: 'tab2', checked: false, }, ], children: [ { children: [] }, { children: [], }, ] }, grid: { index: '-1', tag: "grid", name: '-1', column: 2, children: [ { children: [] }, { children: [], }, ] }, }; // 获取组件JSON数据 Class.prototype.getComponentJson = function (name) { var type = this.fields[name]; try { return JSON.parse(JSON.stringify(type)); } catch (error) { console.warn(name + ' is not existing'); } return type; } // 初始化渲染 Class.prototype.render = function () { var that = this , options = that.config; options.id = options.elem.replace('#', ''); // 获取当前元素 var othis = options.elem = $(options.elem); if (!othis[0]) return; $('#Propertie').html(TPL_RIGHT_MAIN); var arrs = ['sort_1', 'sort_2', 'sort_3']; for (let index = 0; index < arrs.length; index++) { const element = arrs[index]; const getById = document.getElementById(element); that.config.index[element] = new Sortable(getById, { group: { name: STR_FORMDESIGN, pull: 'clone', put: false, }, sort: false, animation: 150, onChoose: function (evt) { }, // 拖动前显示 onAdd: function (evt) { }, // 添加到这里 onEnd: function (evt) { }, // 拖动结束 }); } // 主要接口 options.master = new Sortable(document.getElementById(options.id), { group: { name: STR_FORMDESIGN, }, animation: 150, ghostClass: "sortableghost", chosenClass: "sortablechosen", swapClass: 'highlight', filter: function (evt, item) { if ($(item).hasClass('layui-tab')) { return true; } if ($(item).hasClass('tpl_main')) { return true; } if ($(item).data('type') == 'space') { return true; } return false; }, onAdd: function (evt) { // FIX-BUG if (!options.count) { evt.newIndex = options.count; } var item = evt.item, id = $(item).attr('id'); var data = that.getComponentJson($(item).data('tag')); if (typeof id != 'undefined') { data = JSON.parse(JSON.stringify(that.recursiveFindElem(options.data, id))); that.recursiveDelete(options.data, id); } data.index = options.count++; data.name = data.tag + '_' + data.index; options.data.splice(evt.newIndex, 0, data); options.state = data; that.renderComponent(options.data, $('#' + options.id)); }, onUpdate: function (evt) { if (evt.to.id == options.id) { [options.data[evt.newIndex], options.data[evt.oldIndex]] = [options.data[evt.oldIndex], options.data[evt.newIndex]]; } }, onEnd: function (evt) { } }); // 查询下当前data的数据信息,是否为字符串 if (typeof options.eval == 'string') { try { var data = JSON.parse($(options.eval).val()); options.data = data; options.state = data[0]; options.count = data.length; that.reloadComponent(); } catch (error) { othis.append(TPL_MAIN); // layer.msg('初始化','info'); } } else { othis.append(TPL_MAIN); } that.events(); }; //事件 Class.prototype.events = function () { var that = this, options = that.config; $('body').on('click', '#formBuilder ul li', function (e) { var othis = $(this), index = $(othis).index(), parentId = $(othis).parents('#layui-tab').parent().attr('id'); var element = that.recursiveFindElem(options.data, parentId); try { // 切换选项卡状态 for (var key = 0; key < element.options.length; key++) { var subElem = element.options[key]; if (key == index) { subElem.checked = true; } else { subElem.checked = false; } } } catch (error) { console.log(index, parentId); } }) // 解析组件属性 $('body').on('click', '#' + options.id + ' .layui-form-item', function (e) { // 禁止冒泡 // 过滤元素中按钮 if ($(e.toElement).hasClass('layui-btn') == false && $(e.toElement).hasClass('layui-upload-file') == false && $(e.toElement).parent().hasClass('layui-tab-title') == false) { e.preventDefault(); e.stopPropagation(); } var othis = $(this), name = othis.attr('id'); if (typeof name == 'undefined') { return true; } $('div.active').each(function (k, n) { $(n).removeClass('active'); }) $(othis).addClass('active'); options.state = that.recursiveFindElem(options.data, name); that.getPropertieValues(options.state); }) // 复制节点 $('body').on('click', '#' + options.id + ' .layui-icon-picture-fine', function (e) { var othis = this; var copyElem = []; var name = $(othis).parents('.' + LAY_FORM_ITEM).attr('id'); var cycleElem = function (array, name) { for (let index = 0; index < array.length; index++) { const element = array[index]; if (element.name == name) { copyElem = JSON.parse(JSON.stringify(element)); copyElem.index = options.count++;; copyElem.name = copyElem.tag + '_' + copyElem.index; // 节点插入 array.splice(index + 1, 0, copyElem); break; } if (typeof element.children != 'undefined' && element.children.length) { var subElem = element.children; for (let i = 0; i < subElem.length; i++) { if (subElem[i].children.length) { var item = cycleElem(subElem[i].children, name); if (item != [] && typeof item != 'undefined') { return item; } } } } } } cycleElem(options.data, name); options.state = copyElem; // 复制BUG 需要去重 var nodes = []; var randRepeat = function (array) { for (let index = 0; index < array.length; index++) { var element = array[index]; if (nodes.indexOf(element.name) != -1) { element.name = element.name + 't'; } nodes.push(element.name); if (typeof element.children != 'undefined' && element.children.length) { var subElem = element.children; for (let i = 0; i < subElem.length; i++) { if (subElem[i].children.length) { randRepeat(subElem[i].children); } } } } } randRepeat(options.data); that.reloadComponent(); }) // 删除节点 $('body').on('click', '#' + options.id + ' .layui-icon-delete', function (e) { var othis = this; layer.confirm('确定要删除元素吗?', { }, function (index, layero) { var name = $(othis).parents('.' + LAY_FORM_ITEM).attr('id'); // 点击删除后,返回为未定义 options.state = that.recursiveDelete(options.data, name) || []; that.reloadComponent(); layer.close(index); }) }) // 当前EVAL存在则进行数据赋值 $('body').on('click', function (e) { try { if ($(options.eval).length) { $(options.eval).val(JSON.stringify(options.data)); } } catch (error) { console.warn(error); } }) // 编辑标签 $('body').on('keyup', '#Propertie #label', function (e) { $('#' + options.state.name).find('label:eq(0)').text($(this).val()); var element = that.recursiveFindElem(options.data, options.state.name); element.label = $(this).val(); }) // 占位提示 $('body').on('keyup', '#Propertie #placeholder', function (e) { $('#' + options.state.name).find(options.state.tag + ':eq(0)').prop('placeholder', $(this).val()); var element = that.recursiveFindElem(options.data, options.state.name); element.placeholder = $(this).val(); }) // layui-change 更新后操作 // layui-keyup 键入后操作 $('body').on('change', '#Propertie .layui-change', function (e) { var othis = this; var oid = $(othis).attr('id'); var oval = $(othis).val(); if (oid == 'name') { var existing = that.recursiveFindElem(options.data, oval); if (oval.length <= 1 || existing) { layer.msg('Logo is shorter or already exist', 'error'); return false; } } var element = that.recursiveFindElem(options.data, options.state.name); try { if (typeof element[oid] != 'undefined') { element[oid] = oval; } } catch (error) { console.log('undefined element'); } that.reloadComponent(); }) // 图片上传类型修改 $('body').on('click', '#Propertie #uploadtype', function (e) { var othis = this; var oval = $(othis).attr('value'); var element = that.recursiveFindElem(options.data, options.state.name); try { element.uploadtype = oval; } catch (error) { console.log('undefined element'); } $('#Propertie #uploadtype').each(function (i, e) { $(e).prop('class', 'layui-badge layui-bg-gray'); }) $(othis).prop('class', 'layui-badge layui-bg-blue'); that.reloadComponent(); }) // 级联选择器类型 $('body').on('click', '#Propertie #data_value', function (e) { var othis = this; var oval = $(othis).attr('value'); var element = that.recursiveFindElem(options.data, options.state.name); try { element.data_value = oval; } catch (error) { console.log('undefined element'); } $('#Propertie #data_value').each(function (i, e) { $(e).prop('class', 'layui-badge layui-bg-gray'); }) $(othis).prop('class', 'layui-badge layui-bg-blue'); that.reloadComponent(); }) // 全局SELECT属性 form.on('select(componentSelected)', function (data) { var field = $(data.elem).data('field') , element = that.recursiveFindElem(options.data, options.state.name); if (!data.value) { return layer.error('请选择字段'); } try { if (element.tag === 'grid') { var children = element.children; var length = children.length; if (data.value > length) { // 添加元素 children.push({ children: [] }); } else if (data.value < length) { var d = length - data.value; for (var i = 0; i < children.length; i++) { if (d <= 0) { break; } // 当前无子类 if (!children[i].children.length) { d--; children.splice(i, 1); } } // 如果过滤完还有的话 // 则还需要循环下 if (d >= 1) { while (d) { d--; children.splice(d, 1); } } } } element[field] = data.value; if (field === 'name') { element['label'] = tableInfo[data.value]; } } catch (error) { console.warn('undefined element'); } that.reloadComponent(); }) // 全局组件状态 form.on('switch(componentChecked)', function (data) { let field = $(this).data('field') , element = that.recursiveFindElem(options.data, options.state.name); try { // 过滤主题 if (field === 'lay_skin') { element.lay_skin = data.elem.checked ? 'primary' : STR_EMPTY; } else { element[field] = data.elem.checked ? true : false; } } catch (error) { console.log('undefined element'); } that.reloadComponent(); }) // 其他验证规则 form.on('checkbox(verify)', function (data) { that.setInputVerify(data.elem.checked, $(this).val()); let element = that.recursiveFindElem(options.data, options.state.name); let verify = element.lay_verify === '' ? [] : element.lay_verify.split('|'); if (data.elem.checked) { verify.push(data.value); } else { verify.splice(data.value, 1); } element.lay_verify = verify.join('|'); }) // 添加选项 $('body').on('click', 'button.layui-add-option', function (click) { that.checkSelectRadio(options.state.tag, $('#Propertie #name').val(), null); }) // 编辑radio checkbox 组件信息 $('body').on('change', '#form-options input', function (click) { var othis = $(this), parentIndex = $(othis).parent('.' + LAY_INLINE_CLASS).index(), selfIndex = $(othis).index() - 1, val = $(othis).val(), field = $('#field').val(); var element = that.recursiveFindElem(options.data, options.state.name); for (const key in element.options) { if (key == parentIndex) { var item = element.options[key]; if (selfIndex) { item.value = val; } else { item.title = val; } } } that.reloadComponent(); }) // 删除选项 $('body').on('click', '#form-options .layui-icon-subtraction', function (click) { that.checkSelectRadio(options.state.tag, $('#Propertie #name').val(), $(this).prev().val(), false); }) // 预览表单 $('body').on('click', '.layui-btn-component', function (e) { var othis = this, subHtml = STR_EMPTY, formName = $('#formName').val(), html = '
'; html += $('#formBuilder').html(); html += '
'; html = html.replace(/]+>/g, '').replace(/<\/ol>/g, ''); html = html.replace(/
.*?<\/div>/g, ''); // 获取提交代码 subHtml = html.substring(0, html.indexOf('')); subHtml += ''; subHtml += html.substring(html.indexOf('')); html = subHtml; var formWidth = $('#formWidth').val(); if (!formWidth) { formWidth = '65%'; } var formHeight = $('#formHeight').val(); if (!formHeight) { formHeight = '65%'; } layer.open({ type: 1, title: '预览表单 - ' + formName, maxmin: true, area: [formWidth, formHeight], content: html, success: function (index, layero) { // 暂时只渲染layui元素 // 剩下的需要在自身页面进行渲染 form.render(); } }) }) // 清空表单设计 $('body').on('click', '.layui-form-clear', function (e) { layer.confirm('确定要清空表单设计吗?', { }, function (index, layero) { options.data = []; $('#' + options.id).html(TPL_MAIN); $('#Propertie').html(TPL_RIGHT_MAIN); layer.close(index); }) }) // 导出表单 $('body').on('click', '.layui-btn-export', function (e) { $('#json-code').val(JSON.stringify(options.data, null, 4)); $('#import-code').addClass(STR_HIDE); $('#copy-code').removeClass(STR_HIDE); layer.open({ type: 1 , offset: '130px' , content: $('.layui-htmlview') , area: ['800px', '660px'] , shade: false , resize: false , success: function (layero, index) { } }); }) // 复制代码 $('body').on('click', '#copy-code', function (e) { var data = document.getElementById("json-code"); data.select(); if (document.execCommand('copy')) { layer.msg('复制成功'); } layer.closeAll(); }) // 导入表单 $('body').on('click', '.layui-btn-import', function (e) { $('#copy-code').addClass(STR_HIDE); $('#import-code').removeClass(STR_HIDE); layer.open({ type: 1 , offset: '130px' , content: $('.layui-htmlview') , area: ['800px', '660px'] , shade: false , resize: false , success: function (layero, index) { $('body').on('click', '#import-code', function (e) { try { var data = $('#json-code').val(); options.data = JSON.parse(data); options.state = options.data[0]; that.reloadComponent(); layer.close(index); } catch (error) { layer.msg('缺少参数', 'error'); } }) } }); }) // 加载表单 $('body').on('click', '.button--text', function (e) { var id = $(this).data('id'); layer.confirm('是否加载这个模板?加载后会覆盖设计器当前表单', function (index) { $(layer).find('.layui-layer-btn0').css('pointer-events', 'none'); $.ajax({ url: '//api.swiftadmin.net/form/read?id=' + id, type: "get", data: [], success: function (res) { if (res.code == 200) { options.data = JSON.parse(res.data); options.state = options.data[0]; that.reloadComponent(); } } }); layer.close(index); }) }) }; /** * 增删组件选项 * @param {*} tag * @param {*} name * @param {*} value * @param {*} action */ Class.prototype.checkSelectRadio = function (tag, name, value, action = true) { var options = this.config; var element = this.recursiveFindElem(options.data, name); if (typeof element === 'undefined') { return layer.error('请选择字段后再操作'); } if (action) { if (typeof element.options === 'undefined') { return layer.error('当前组件无选项'); } element.options.splice(element.options.length, 0, { title: '选项' + element.options.length, value: 'value', checked: false }); if (element.tag == 'tab') { element.children.push({ children: [] }); } } else { for (const key in element.options) { var item = element.options[key]; if (item.value == value) { element.options.splice(key, 1); if (element.tag == 'tab') { element.children.splice(key, 1); } break; } } } this.reloadComponent(); } /** * 设置表单验证规则 * @param {*} checked * @param {*} field */ Class.prototype.setInputVerify = function (checked = false, field = '') { var elem = this.config.state.name; var rules = $('#' + elem).find('input:eq(0)').attr('lay-verify') || []; if (typeof rules != 'object') { rules = rules.split('|'); } if (checked) { rules[rules.length] = field; $('#' + elem).find('input:eq(0)').attr('lay-verify', rules.join('|')); } else { for (let index = 0; index < rules.length; index++) { const el = rules[index]; if (el == field) { rules.splice(index, 1); } } if (rules.length) { $('#' + elem).find('input:eq(0)').attr('lay-verify', rules.join('|')); } else { $('#' + elem).find('input:eq(0)').removeAttr('lay-verify'); } } } /** * 获取HTML代码 * @param {*} lable * @param {*} id * @param {*} value * @param {*} classed */ Class.prototype.getPropertieHtml = function (lable, id, value, classed = '', attr = '') { var proHtml = '
'; if (lable) { proHtml += ''; } proHtml += LAY_INPUT_INLINE; proHtml += ''; proHtml += LAY_FORM_DIV + LAY_FORM_DIV; return proHtml; } /** * 模板碎片 * @param {*} lable * @returns */ Class.prototype.getPropertieDebris = function (lable, hide = '') { var proHtml = '
'; if (lable) { proHtml += ''; } proHtml += LAY_INPUT_INLINE; return proHtml; } /** * 获取标签文字 * @param {*} field */ Class.prototype.getLang = function (field) { if (typeof this.lang[field] != 'undefined') { return this.lang[field]; } else { return field + ' undefined'; } } /** * 获取表单属性 * @param {*} elem * @param {*} type */ Class.prototype.getPropertieValues = function (data, type) { var that = this, options = that.config, optionsHtml = STR_EMPTY; for (const key in data) { // 过滤index if (key == 'index') { continue; } var value = data[key]; if (key == 'options' || key == 'children') { // 过滤信息 } else { optionsHtml += that.getPropertieDebris(that.getLang(key)); } switch (key) { case 'tag': optionsHtml += ''; break; case 'label': case 'placeholder': // 标签和描述占位符 optionsHtml += ''; break; case 'name': if (typeof tableInfo !== undefined) { if (data.tag == 'tab') { optionsHtml += ''; } else { optionsHtml += ''; } } break; case 'msg': case 'text': case 'color': case 'default': case 'data_default': case 'data_theme': optionsHtml += ''; break; case 'type': optionsHtml += ''; break; case 'data_datetype': optionsHtml += ''; break; case 'data_dateformat': optionsHtml += ''; break; case 'offset': var attrs = { 1: '上', 2: '左', 3: '下', 4: '右' }; optionsHtml += ''; break; case 'theme': var attrs = { '': '默认', 'layui-btn-normal': '百搭', 'layui-btn-warm': '暖色', 'layui-btn-danger': '警告', 'layui-btn-disabled': '禁用' }; optionsHtml += ''; break; case 'btnsize': var attrs = { '': '默认按钮', 'layui-btn-lg': '大型按钮', 'layui-btn-sm': '小型按钮', 'layui-btn-xs': '迷你按钮', 'layui-btn-fluid': '流体按钮' }; optionsHtml += ''; break; case 'data_accept': optionsHtml += ''; break; case 'max': case 'min': case 'size': case 'height': case 'data_max': case 'data_min': case 'data_step': case 'data_size': optionsHtml += ''; break; case 'data_maxvalue': case 'data_minvalue': optionsHtml += ''; break; case 'width': // 滑块操作 optionsHtml += '
'; break; case 'labelwidth': optionsHtml += '
'; break; case 'maxlength': optionsHtml += ''; break; case 'minmax': for (const key in data.minmax) { var num = data.minmax[key]; optionsHtml += ''; if (key == 0) { optionsHtml += '-'; } } break; case 'lay_skin': case 'required': case 'readonly': case 'disabled': case 'labelhide': case 'lay_search': case 'data_range': case 'data_showstep': case 'data_half': case 'data_input': case 'data_parents': optionsHtml += ''; break; case 'data_value': var type = ['label', 'value']; for (const index in type) { optionsHtml += ' ' + type[index] + ''; } break; case 'lay_verify': var verify = [ { title: '手机', value: 'phone' }, { title: '邮箱', value: 'email' }, { title: '网址', value: 'url' }, { title: '数字', value: 'number' }, { title: '日期', value: 'date' }, { title: '身份证', value: 'identity' }, ]; for (const key in verify) { var check = verify[key]; optionsHtml += '' + type[index] + ''; } break; case 'maxlength': case 'data_length': optionsHtml += ''; break; case 'textarea': optionsHtml += '';; break; case 'border': var attrs = { '': '默认', 'layui-border-red': '赤色', 'layui-border-orange': '橙色', 'layui-border-green ': '墨绿色', 'layui-border-cyan': '青色', 'layui-border-blue': '蓝色', 'layui-border-black': '黑色', }; optionsHtml += ''; break; case 'editorType': var attrs = { 'lay-editor': 'tinymce', 'lay-markdown': 'markdown', }; optionsHtml += ''; break; case 'options': optionsHtml += this.formOptionHeader(); for (const key in data.options) { var option = data.options[key]; optionsHtml += LAY_INPUT_INLINE; optionsHtml += ''; optionsHtml += ''; optionsHtml += ''; optionsHtml += ''; optionsHtml += LAY_FORM_DIV; } optionsHtml += '
'; optionsHtml += ''; optionsHtml += LAY_FORM_DIV optionsHtml += LAY_FORM_DIV + LAY_FORM_DIV; break; case 'column': var attrs = [2, 3, 4]; optionsHtml += ''; break; default: break; } optionsHtml += '
'; } $('#Propertie').html(optionsHtml); form.render(null, 'Propertie'); // 最大化时间回调操作 var datetime = $('#data_maxvalue, #data_minvalue'); datetime.each(function (index, obj) { layui.laydate.render({ elem: this , type: 'date' , format: 'yyyy-MM-dd' , done: function (value, date, endDate) { var element = that.recursiveFindElem(options.data, options.state.name); try { element[$(obj).attr('id')] = value; } catch (error) { console.log(error); } that.reloadComponent(); } }); }) // 选项拖动接口 if ($('#Propertie #form-options').length) { new Sortable(document.getElementById('form-options'), { handle: '.layui-icon-slider', animation: 150, onAdd: function (evt) { }, onUpdate: function (evt) { var element = that.recursiveFindElem(options.data, options.state.name); try { var op = element.options; [op[evt.newIndex], op[evt.oldIndex]] = [op[evt.oldIndex], op[evt.newIndex]]; // 是否内容区域也需要编辑? that.reloadComponent(); } catch (error) { // 捕获异常 console.warn(error); } }, onEnd: function (evt) { } }); } layui.each($(".layui-sliders"), function (key, elem) { var othat = $(this), obj = othat.attr('id'), val = othat.data('value'), min = othat.data('min') || 10, max = othat.data('max') || 100, theme = othat.data('theme') || '#1890ff'; layui.slider.render({ elem: elem , min: min , max: max , input: true , theme: theme , value: val , step: 2 , change: function (value) { if (value <= min || isNaN(value)) { value = min; } var element = that.recursiveFindElem(options.data, options.state.name); try { element[obj] = value } catch (error) { console.warn(error); } that.reloadComponent(); } }) }) } /** * 获取选项表头 * @param {*} options * @returns */ Class.prototype.formOptionHeader = function (options = 'form-options') { var _options = '
'; _options += '选项'; _options += '
'; _options += '
'; return _options; } /** * 获取工具栏HTML * @returns */ Class.prototype.getToolsHtml = function () { var tools = '
'; tools += ' '; tools += ' '; tools += LAY_FORM_DIV; return tools; } // 获取组件代码 Class.prototype.renderComponent = function (data, elem) { var that = this, outerHTML = STR_EMPTY, options = that.config; /** * 代码预处理 * 编辑器需要预先移除节点 */ $(elem).find('.editorsrv').each(function (i, n) { $(n).parent().find('.tox-tinymce').remove(); $(n).remove(); }); elem.empty(STR_EMPTY); // 循环渲染表单 for (let index = 0; index < data.length; index++) { var element = data[index]; outerHTML = that.renderComponentItem[element.tag].render(element); elem.append($(outerHTML).append(that.getToolsHtml()).prop("outerHTML")); switch (element.tag) { case 'input': break; case 'date': admin.components.datetime(); break; case 'colorpicker': admin.components.colorpicker(); break; case 'slider': admin.components.slider(); break; case 'rate': admin.components.rate(); break; case 'upload': admin.components.upload(); break; case 'tags': admin.components.tags(); break; case 'cascader': admin.components.cascader('input#' + element.name); break; case 'editor': if (element.editorType === 'lay-editor') { tinymce.init({ selector: '#' + element.name + '_tiny', language: 'zh_CN', }) } else { let elem = '#' + element.name + '_tiny'; let height = $(elem).data('height') || '400px'; let _id = 'markdown_' + Math.round(Math.random() * 36); $(elem).after('
'); new Cherry({ id: _id, toolbars: { theme: 'light', float: false, bubble : false // array or false }, editor: { height: height, defaultModel: 'editOnly', } }); } break; case 'tab': case 'grid': var children = $('#' + element.name + ' .children'); var childItem = [] $.each(children, function (index, item) { that.gridtabSortable(item); childItem[index] = item; }) // 递归渲染里面的子元素 $.each(element.children, function (index, item) { if (item.children.length) { that.renderComponent(item.children, $(childItem[index])); } }) break; default: break; } if (typeof options.state != 'undefined') { that.getPropertieValues(options.state); } else if (options.data.length) { options.state = options.data[options.data.length - 1]; that.getPropertieValues(options.state); } } // 取消其他活动选项 $('#' + options.id + ' div.active').each(function (k, n) { $(n).removeClass('active'); }) if (typeof options.state != undefined) { $('div#' + options.state.name).addClass('active'); } // 渲染表单 form.render(); } /** * 重新渲染组件 */ Class.prototype.reloadComponent = function () { this.renderComponent(this.config.data, $('#' + this.config.id)); } /** * 是否隐藏标签 * @param {*} labelhide * @param {*} data * @returns */ var getBeforeLabel = function (labelhide = false, data) { var labelHtml = '
'; return html; } }, date: { render: function (data) { var html = getBeforeItem(data); html += getBeforeLabel(data.labelhide, data); html += ''; html += '
'; html += '
'; return html; } }, slider: { render: function (data) { var html = getBeforeItem(data); html += getBeforeLabel(data.labelhide, data); html += ''; html += '
'; html += '
'; html += '
'; return html; } }, cascader: { render: function (data) { var html = getBeforeItem(data); html += getBeforeLabel(data.labelhide, data); html += ''; html += '
'; return html; } }, editor: { render: function (data) { var html = getBeforeItem(data); html += getBeforeLabel(data.labelhide, data); html += '