|
|
(function () {
|
|
|
let main = {
|
|
|
grid: null,
|
|
|
initData: null,
|
|
|
};
|
|
|
let welcome = {
|
|
|
grid: null,
|
|
|
initData: null,
|
|
|
};
|
|
|
let currentComponent = null;
|
|
|
let currentScreen = 'welcome';
|
|
|
let cellHeight = 30;
|
|
|
let locale = 'en_US';
|
|
|
|
|
|
var initGridStack = () => {
|
|
|
// 让gridstack知道如何渲染,组件children中的content直接渲染html
|
|
|
GridStack.renderCB = function (el, w) {
|
|
|
el.innerHTML = w.content;
|
|
|
};
|
|
|
|
|
|
GridStack.setupDragIn('#components-panel .component-item', undefined, [
|
|
|
{
|
|
|
w: 4,
|
|
|
h: 4,
|
|
|
type: 'image',
|
|
|
name: userLangConfig[locale].user.image_default_name,
|
|
|
background: '#fff',
|
|
|
image: '',
|
|
|
eventsType: 'click',
|
|
|
eventsAction: '',
|
|
|
defaultFocus: '0',
|
|
|
leftId: '',
|
|
|
rightId: '',
|
|
|
upId: '',
|
|
|
downId: '',
|
|
|
focusedStyle_background: '',
|
|
|
focusedStyle_border_width: 0,
|
|
|
focusedStyle_border_color: '',
|
|
|
focusedStyle_scale: 1,
|
|
|
},
|
|
|
{
|
|
|
w: 4,
|
|
|
h: 2,
|
|
|
type: 'text',
|
|
|
childrenType: '',
|
|
|
name: userLangConfig[locale].user.text_default_name,
|
|
|
background: '#fff',
|
|
|
fontSize: 14,
|
|
|
color: '#333',
|
|
|
text: userLangConfig[locale].user.text_default_content,
|
|
|
fontWeight: 'normal',
|
|
|
eventsType: 'click',
|
|
|
eventsAction: '',
|
|
|
defaultFocus: '0',
|
|
|
leftId: '',
|
|
|
rightId: '',
|
|
|
upId: '',
|
|
|
downId: '',
|
|
|
focusedStyle_background: '',
|
|
|
focusedStyle_border_width: 0,
|
|
|
focusedStyle_border_color: '',
|
|
|
focusedStyle_scale: 1,
|
|
|
},
|
|
|
]);
|
|
|
};
|
|
|
|
|
|
// 生成唯一id
|
|
|
var generateUniqueId = function () {
|
|
|
const timestamp = Date.now().toString(36);
|
|
|
const randomNum = Math.random().toString(36).substring(2);
|
|
|
return timestamp + randomNum;
|
|
|
};
|
|
|
|
|
|
// 判断是画布还是组件
|
|
|
var isScreen = function (type) {
|
|
|
return type === 'screen';
|
|
|
};
|
|
|
|
|
|
/** 初始化 */
|
|
|
var init = function (type, self) {
|
|
|
const initDataStorage = self['initData'];
|
|
|
if (!initDataStorage) {
|
|
|
self['initData'] = {
|
|
|
type: 'screen',
|
|
|
id: `grid_${generateUniqueId()}`,
|
|
|
children: [],
|
|
|
version: '1.0.0',
|
|
|
width: 1920,
|
|
|
height: 1080,
|
|
|
background: '#e2e2e2',
|
|
|
image: '', // 为画布添加image属性
|
|
|
};
|
|
|
} else {
|
|
|
conputedInitData('init', self);
|
|
|
}
|
|
|
self['initData'].el = document.getElementById(`${type}-screen`);
|
|
|
|
|
|
console.log(self['initData'], `${type}Data`);
|
|
|
|
|
|
// 初始化时应用画布背景
|
|
|
const canvasId = `${type}-screen`;
|
|
|
if (self.initData.image) {
|
|
|
$('#' + canvasId)
|
|
|
.css('background-image', `url(${self.initData.image})`)
|
|
|
.css('background-size', 'cover');
|
|
|
} else if (self.initData.background) {
|
|
|
$('#' + canvasId).css('background-color', self.initData.background);
|
|
|
}
|
|
|
|
|
|
self['grid'] = GridStack.init(
|
|
|
{
|
|
|
// 一行高度
|
|
|
cellHeight,
|
|
|
// 间距
|
|
|
margin: 0,
|
|
|
minRow: Math.floor(1080 / 2 / cellHeight),
|
|
|
maxRow: Math.floor(1080 / 2 / cellHeight),
|
|
|
acceptWidgets: true,
|
|
|
float: true,
|
|
|
removable: '#trash',
|
|
|
// subGridOpts: subOptions,
|
|
|
// subGridDynamic: true,
|
|
|
children: self['initData'].children,
|
|
|
column: 24,
|
|
|
},
|
|
|
`#${type}-screen`
|
|
|
);
|
|
|
// console.log(self['grid'], `${type}.grid实例`);
|
|
|
|
|
|
// grid.load(initData.children);
|
|
|
|
|
|
self['grid'].engine.nodes.forEach((item) => {
|
|
|
handleAddComponent(item, self);
|
|
|
});
|
|
|
|
|
|
self['grid'].on('added', function (_event, itemArray) {
|
|
|
console.log(itemArray, '这里触发了添加了added事件');
|
|
|
itemArray.forEach((item) => {
|
|
|
handleAddComponent(item, self);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
self['grid'].on('removed', function (_event, itemArray) {
|
|
|
console.log(itemArray, '这里触发了移除removed事件');
|
|
|
itemArray.forEach((item) => {
|
|
|
handleRemoveComponent(item);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 处理添加组件之后的操作
|
|
|
var handleAddComponent = (component, self) => {
|
|
|
if (!component.id) {
|
|
|
component.id = `${component.type}_${generateUniqueId()}`;
|
|
|
}
|
|
|
// 组件首次加载或被添加到画布时,调用 setComponentView,且没有传递 `fields` 参数。这意味着对组件进行一次完整渲染。它会读取组件对象上所有的初始属性,并一股脑地应用到DOM元素上,确保组件从一开始就显示正确的样式。
|
|
|
setComponentView(component);
|
|
|
|
|
|
component.el.addEventListener('click', (e) => {
|
|
|
e.stopPropagation();
|
|
|
console.log(isScreen(component.type) ? `点击画布` : `点击组件`, component);
|
|
|
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 清除之前选中组件的获取焦点后的样式
|
|
|
clearOldFocusStyle();
|
|
|
currentComponent = component;
|
|
|
// 右侧显示组件属性列表
|
|
|
if (!$('#props-panel').find('form').is(':visible')) {
|
|
|
$('#props-panel').find('.wait-box').hide();
|
|
|
$('#props-panel').find('form').show();
|
|
|
}
|
|
|
// 将当前选中组件的属性显示在右侧列表中
|
|
|
setCurrentComponentProps(currentComponent);
|
|
|
|
|
|
// 非画布时设置
|
|
|
if (!isScreen(component.type)) {
|
|
|
// 设置当前选中组件的获取焦点后的样式
|
|
|
setCurrentFocusStyle();
|
|
|
// 设置上下左右移动组件ID
|
|
|
setMoveComponentId(currentComponent, self);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var clearOldFocusStyle = function () {
|
|
|
if (currentComponent && !isScreen(currentComponent.type)) {
|
|
|
let el = $(currentComponent.el).find('.grid-stack-item-content');
|
|
|
el.css('background', 'none');
|
|
|
if (currentComponent.image) {
|
|
|
el.find('img').attr('src', currentComponent.image);
|
|
|
}
|
|
|
if (currentComponent.background) {
|
|
|
el.css('background', currentComponent.background);
|
|
|
}
|
|
|
el.css('border-color', '');
|
|
|
el.css('border-width', '');
|
|
|
el.css('transform', '');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var setCurrentFocusStyle = function () {
|
|
|
if (currentComponent && !isScreen(currentComponent.type)) {
|
|
|
let el = $(currentComponent.el).find('.grid-stack-item-content');
|
|
|
if (currentComponent.focusedStyle_background) {
|
|
|
el.css('background', currentComponent.focusedStyle_background);
|
|
|
}
|
|
|
el.css('border-color', currentComponent.focusedStyle_border_color);
|
|
|
el.css('border-width', currentComponent.focusedStyle_border_width + 'px');
|
|
|
el.css('transform', `scale(${currentComponent.focusedStyle_scale})`);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 设置上下左右移动组件ID
|
|
|
var setMoveComponentId = function (component, self) {
|
|
|
const allComponents = self['grid'].save();
|
|
|
if (allComponents.length <= 1) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
setMoveComponentHtml('leftId', component, allComponents);
|
|
|
setMoveComponentHtml('rightId', component, allComponents);
|
|
|
setMoveComponentHtml('upId', component, allComponents);
|
|
|
setMoveComponentHtml('downId', component, allComponents);
|
|
|
};
|
|
|
|
|
|
var setMoveComponentHtml = function (idName, component, allComponents) {
|
|
|
let el = $(`#${idName}`);
|
|
|
let componentsHtml = [{ value: '', text: el.find('option').eq(0).text() }];
|
|
|
allComponents
|
|
|
.filter((item) => item.id !== component.id)
|
|
|
.map((item) => {
|
|
|
componentsHtml.push({ value: item.id, text: `${item.name}(${item.id})`, selected: item.id === component[idName] });
|
|
|
});
|
|
|
el.empty();
|
|
|
componentsHtml.forEach((item) => {
|
|
|
el.append(
|
|
|
$('<option>', {
|
|
|
value: item.value,
|
|
|
text: item.text,
|
|
|
selected: item.selected || false,
|
|
|
})
|
|
|
);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var handleRemoveComponent = (component) => {
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
currentComponent = null;
|
|
|
hidePropsPanel();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var hidePropsPanel = () => {
|
|
|
// 右侧显示请选择组件
|
|
|
if (!$('#props-panel').find('wait-box').is(':visible')) {
|
|
|
$('#props-panel').find('.wait-box').show();
|
|
|
$('#props-panel').find('form').hide();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 颜色选择器统一处理
|
|
|
var initColorPicker = function (type, component) {
|
|
|
let options = {
|
|
|
elem: `#${type}`,
|
|
|
alpha: true,
|
|
|
format: 'rgb',
|
|
|
done: function (color) {
|
|
|
const el = $(component.el);
|
|
|
let cptColor = rgbaToHex(color);
|
|
|
switch (type) {
|
|
|
case 'background':
|
|
|
component.background = cptColor;
|
|
|
if (isScreen(component.type)) {
|
|
|
component.image = '';
|
|
|
}
|
|
|
if (!cptColor) {
|
|
|
if (isScreen(component.type)) {
|
|
|
el.css('background', 'none');
|
|
|
} else {
|
|
|
el.find('.grid-stack-item-content').css('background', 'none');
|
|
|
}
|
|
|
} else {
|
|
|
if (isScreen(component.type)) {
|
|
|
el.css('background', color);
|
|
|
} else {
|
|
|
el.find('.grid-stack-item-content').css('background', color);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
case 'color':
|
|
|
component.color = cptColor;
|
|
|
el.find('span').css('color', cptColor);
|
|
|
break;
|
|
|
case 'focusedStyle_background':
|
|
|
component.focusedStyle_background = cptColor;
|
|
|
el.find('.grid-stack-item-content').css('background', cptColor);
|
|
|
break;
|
|
|
case 'focusedStyle_border_color':
|
|
|
component.focusedStyle_border_color = cptColor;
|
|
|
el.find('.grid-stack-item-content').css('border-color', cptColor);
|
|
|
break;
|
|
|
}
|
|
|
},
|
|
|
};
|
|
|
if (component[type]) {
|
|
|
options.color = component[type];
|
|
|
}
|
|
|
layui.colorpicker.render(options);
|
|
|
};
|
|
|
|
|
|
//将当前选中组件的属性显示在右侧列表中
|
|
|
var setCurrentComponentProps = function (component) {
|
|
|
// 设置标题
|
|
|
if (isScreen(component.type)) {
|
|
|
$('#component-prop').hide();
|
|
|
$('#page-prop').show();
|
|
|
} else {
|
|
|
$('#component-prop').show();
|
|
|
$('#page-prop').hide();
|
|
|
}
|
|
|
|
|
|
// 设置复制按钮
|
|
|
if (isScreen(component.type)) {
|
|
|
$('#copy-component').hide();
|
|
|
} else {
|
|
|
$('#copy-component').show();
|
|
|
}
|
|
|
|
|
|
const form = $('#props-panel').find('form');
|
|
|
if (component.hasOwnProperty('childrenType')) {
|
|
|
form.find('#childrenType').val(component.childrenType);
|
|
|
form.find('#childrenType').parent().show();
|
|
|
} else {
|
|
|
form.find('#childrenType').parent().hide();
|
|
|
}
|
|
|
|
|
|
if (!isScreen(component.type)) {
|
|
|
form.find('#name').val(component.name);
|
|
|
form.find('#image').parent().show();
|
|
|
} else {
|
|
|
form.find('#name').parent().hide();
|
|
|
}
|
|
|
|
|
|
if (component.hasOwnProperty('image')) {
|
|
|
form.find('#image').val(component.image);
|
|
|
form.find('#image').parent().show();
|
|
|
} else {
|
|
|
form.find('#image').parent().hide();
|
|
|
}
|
|
|
|
|
|
if (component.hasOwnProperty('background')) {
|
|
|
initColorPicker('background', component);
|
|
|
form.find('#background').parent().show();
|
|
|
} else {
|
|
|
form.find('#background').parent().hide();
|
|
|
}
|
|
|
|
|
|
if (component.type === 'text') {
|
|
|
form.find('#text').val(component.text);
|
|
|
form.find('#fontSize').val(component.fontSize);
|
|
|
initColorPicker('color', component);
|
|
|
form.find('#fontWeight').val(component.fontWeight);
|
|
|
form.find('#text').parent().show();
|
|
|
form.find('#fontSize').parent().show();
|
|
|
form.find('#color').parent().show();
|
|
|
form.find('#fontWeight').parent().show();
|
|
|
} else {
|
|
|
form.find('#text').parent().hide();
|
|
|
form.find('#fontSize').parent().hide();
|
|
|
form.find('#color').parent().hide();
|
|
|
form.find('#fontWeight').parent().hide();
|
|
|
}
|
|
|
|
|
|
if (!isScreen(component.type)) {
|
|
|
form.find('#eventsType').val(component.eventsType);
|
|
|
form.find('#eventsAction').val(component.eventsAction);
|
|
|
form.find('#defaultFocus').val(component.defaultFocus);
|
|
|
form.find('#leftId').val(component.leftId);
|
|
|
form.find('#rightId').val(component.rightId);
|
|
|
form.find('#upId').val(component.upId);
|
|
|
form.find('#downId').val(component.downId);
|
|
|
|
|
|
initColorPicker('focusedStyle_background', component);
|
|
|
form.find('#focusedStyle_border_width').val(component.focusedStyle_border_width);
|
|
|
initColorPicker('focusedStyle_border_color', component);
|
|
|
form.find('#focusedStyle_scale').val(component.focusedStyle_scale);
|
|
|
|
|
|
form.find('#eventsType').parent().show();
|
|
|
form.find('#eventsAction').parent().show();
|
|
|
form.find('#defaultFocus').parent().show();
|
|
|
form.find('#leftId').parent().show();
|
|
|
form.find('#rightId').parent().show();
|
|
|
form.find('#upId').parent().show();
|
|
|
form.find('#downId').parent().show();
|
|
|
form.find('#focusedStyle_background').parent().show();
|
|
|
form.find('#focusedStyle_border_width').parent().show();
|
|
|
form.find('#focusedStyle_border_color').parent().show();
|
|
|
form.find('#focusedStyle_scale').parent().show();
|
|
|
} else {
|
|
|
form.find('#eventsType').parent().hide();
|
|
|
form.find('#eventsAction').parent().hide();
|
|
|
form.find('#defaultFocus').parent().hide();
|
|
|
form.find('#leftId').parent().hide();
|
|
|
form.find('#rightId').parent().hide();
|
|
|
form.find('#upId').parent().hide();
|
|
|
form.find('#downId').parent().hide();
|
|
|
form.find('#focusedStyle_background').parent().hide();
|
|
|
form.find('#focusedStyle_border_width').parent().hide();
|
|
|
form.find('#focusedStyle_border_color').parent().hide();
|
|
|
form.find('#focusedStyle_scale').parent().hide();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 定义组件设置配置策略
|
|
|
const componentStrategies = {
|
|
|
background: function (el, value, component) {
|
|
|
initColorPicker('background', component);
|
|
|
|
|
|
// 初始化的时候调用设置
|
|
|
if (!isScreen(component.type)) {
|
|
|
if (!value) {
|
|
|
el.find('.grid-stack-item-content').css('background', 'none');
|
|
|
} else {
|
|
|
el.find('.grid-stack-item-content').css('background', value);
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
image: function (el, value, component) {
|
|
|
if (!value) return;
|
|
|
if (isScreen(component.type)) {
|
|
|
el.css('background', `url(${value}) no-repeat center center`).css('background-size', 'cover');
|
|
|
component.background = '';
|
|
|
} else {
|
|
|
el.find('img').attr('src', value);
|
|
|
}
|
|
|
},
|
|
|
fontSize: function (el, value) {
|
|
|
if (!value) return;
|
|
|
el.find('span').css('font-size', value + 'px');
|
|
|
},
|
|
|
color: function (el, value, component) {
|
|
|
initColorPicker('color', component);
|
|
|
el.find('span').css('color', value);
|
|
|
},
|
|
|
text: function (el, value) {
|
|
|
if (!value) return;
|
|
|
el.find('span').text(value);
|
|
|
},
|
|
|
fontWeight: function (el, value) {
|
|
|
if (!value) return;
|
|
|
el.find('span').css('font-weight', value);
|
|
|
},
|
|
|
defaultFocus: function (el, value, component) {
|
|
|
if (value != '1') {
|
|
|
return;
|
|
|
}
|
|
|
// 默认聚焦一个画布只能存在一个true
|
|
|
let childrens = currentScreen === 'welcome' ? welcome.grid.engine.nodes : main.grid.engine.nodes;
|
|
|
childrens.forEach((item) => {
|
|
|
if (item.id !== component.id) {
|
|
|
item.defaultFocus = '0';
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
focusedStyle_background: function (el, value, component) {
|
|
|
initColorPicker('focusedStyle_background', component);
|
|
|
if (!value) return;
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
el.find('.grid-stack-item-content').css('background', value);
|
|
|
}
|
|
|
},
|
|
|
focusedStyle_border_width: function (el, value, component) {
|
|
|
if (!value) return;
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
el.find('.grid-stack-item-content').css('border-width', value + 'px');
|
|
|
}
|
|
|
},
|
|
|
focusedStyle_border_color: function (el, value, component) {
|
|
|
initColorPicker('focusedStyle_border_color', component);
|
|
|
if (!value) return;
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
el.find('.grid-stack-item-content').css('border-color', value);
|
|
|
}
|
|
|
},
|
|
|
focusedStyle_scale: function (el, value, component) {
|
|
|
if (!value) return;
|
|
|
if (currentComponent && currentComponent.id === component.id) {
|
|
|
el.find('.grid-stack-item-content').css('transform', `scale(${value})`);
|
|
|
}
|
|
|
},
|
|
|
};
|
|
|
|
|
|
// 设置当前传递组件的视图展示
|
|
|
var setComponentView = function (component, fields = null) {
|
|
|
const el = $(component.el);
|
|
|
|
|
|
// 确定要处理的属性
|
|
|
const propsToHandle = fields || Object.keys(componentStrategies);
|
|
|
|
|
|
// 遍历并执行对应的策略
|
|
|
propsToHandle.forEach((prop) => {
|
|
|
if (componentStrategies[prop] && component[prop] !== undefined) {
|
|
|
componentStrategies[prop](el, component[prop], component);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 定义映射关系:元素ID -> 事件类型 -> 组件属性
|
|
|
const elementMappings = {
|
|
|
name: { event: 'blur', property: 'name' },
|
|
|
childrenType: { event: 'change', property: 'childrenType' },
|
|
|
background: { event: 'blur', property: 'background' },
|
|
|
image: { event: 'change', property: 'image' },
|
|
|
fontSize: { event: 'blur', property: 'fontSize' },
|
|
|
color: { event: 'blur', property: 'color' },
|
|
|
text: { event: 'blur', property: 'text' },
|
|
|
fontWeight: { event: 'blur', property: 'fontWeight' },
|
|
|
eventsType: { event: 'change', property: 'eventsType' },
|
|
|
eventsAction: { event: 'change', property: 'eventsAction' },
|
|
|
defaultFocus: { event: 'change', property: 'defaultFocus' },
|
|
|
leftId: { event: 'change', property: 'leftId' },
|
|
|
rightId: { event: 'change', property: 'rightId' },
|
|
|
upId: { event: 'change', property: 'upId' },
|
|
|
downId: { event: 'change', property: 'downId' },
|
|
|
focusedStyle_background: { event: 'blur', property: 'focusedStyle_background' },
|
|
|
focusedStyle_border_width: { event: 'blur', property: 'focusedStyle_border_width' },
|
|
|
focusedStyle_border_color: { event: 'blur', property: 'focusedStyle_border_color' },
|
|
|
focusedStyle_scale: { event: 'blur', property: 'focusedStyle_scale' },
|
|
|
};
|
|
|
|
|
|
// 统一绑定函数
|
|
|
var bindComponentEvents = function () {
|
|
|
Object.keys(elementMappings).forEach((elementId) => {
|
|
|
const mapping = elementMappings[elementId];
|
|
|
const $element = $('#' + elementId);
|
|
|
|
|
|
if ($element.length) {
|
|
|
// 组件名称添加失去焦点事件或者change事件
|
|
|
$element.off(mapping.event).on(mapping.event, function () {
|
|
|
const value = $(this).val();
|
|
|
currentComponent[mapping.property] = value;
|
|
|
/**
|
|
|
* 组件的属性在右侧面板中被修改时
|
|
|
* 用户选中一个组件后,在右侧的属性面板中修改了某个值(例如,修改了字号,或者更改了图片URL),然后输入框失去焦点(blur)或值改变(change)
|
|
|
* 在这个时机调用 setComponentView,并且传递了 `fields` 参数,该参数是一个只包含被修改属性名称的数组(例如 ['fontSize'])。这意味着进行一次高效的增量更新。程序精确地告诉setComponentView:“只需要更新字体大小这一个样式,其他的别动。”
|
|
|
*/
|
|
|
setComponentView(currentComponent, [mapping.property]);
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 处理Tab切换的逻辑
|
|
|
var handleTabSwitch = function () {
|
|
|
$('#canvas-tabs .tab-button').on('click', function () {
|
|
|
var $this = $(this);
|
|
|
// 如果已经是激活状态,则不执行任何操作
|
|
|
if ($this.hasClass('active')) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 处理按钮的激活状态
|
|
|
$this.siblings().removeClass('active');
|
|
|
$this.addClass('active');
|
|
|
|
|
|
// 处理画布的显示/隐藏
|
|
|
var tabId = $this.data('tab');
|
|
|
$('#' + tabId).show();
|
|
|
$('.grid-stack')
|
|
|
.not('#' + tabId)
|
|
|
.hide();
|
|
|
|
|
|
// 处理当前选中screen
|
|
|
var type = $this.data('type');
|
|
|
currentScreen = type;
|
|
|
// 处理右侧面板的显示/隐藏
|
|
|
currentComponent = null;
|
|
|
hidePropsPanel();
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 抽取校验函数
|
|
|
function validateDefaultFocus(children) {
|
|
|
const { default_focus_tip } = userLangConfig[locale].user;
|
|
|
if (children.length) {
|
|
|
let hasDefaultFocus = false;
|
|
|
children.forEach((item) => {
|
|
|
if (item.defaultFocus == '1') {
|
|
|
hasDefaultFocus = true;
|
|
|
}
|
|
|
});
|
|
|
if (!hasDefaultFocus) {
|
|
|
layer.msg(`${default_focus_tip}`);
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// 保存时判断是否满足条件可保存
|
|
|
var canSave = function () {
|
|
|
const { please_input, template_name } = userLangConfig[locale].user;
|
|
|
if (!$('#templateName').val()) {
|
|
|
layer.msg(`${please_input}${template_name}`);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const welcomeChildrens = welcome.grid.save();
|
|
|
const mainChildrens = main.grid.save();
|
|
|
if (!validateDefaultFocus(welcomeChildrens)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (!validateDefaultFocus(mainChildrens)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
// 点击保存按钮处理
|
|
|
var handleSaveClick = function () {
|
|
|
$('.save-container').click(function () {
|
|
|
if (!canSave()) {
|
|
|
return;
|
|
|
}
|
|
|
main.initData.children = main.grid.save();
|
|
|
welcome.initData.children = welcome.grid.save();
|
|
|
console.log(main.initData);
|
|
|
console.log(welcome.initData);
|
|
|
localStorage.setItem('mainData', JSON.stringify(conputedInitData('save', main)));
|
|
|
localStorage.setItem('welcomeData', JSON.stringify(conputedInitData('save', welcome)));
|
|
|
|
|
|
let id = getQueryParam('id');
|
|
|
let data = {
|
|
|
name: $('#templateName').val(),
|
|
|
content: JSON.stringify({
|
|
|
mainData: conputedInitData('save', main),
|
|
|
welcomeData: conputedInitData('save', welcome),
|
|
|
}),
|
|
|
};
|
|
|
if (id) {
|
|
|
data.id = id;
|
|
|
}
|
|
|
requestFN(
|
|
|
{
|
|
|
type: 'POST',
|
|
|
url: id ? 'update' : 'save',
|
|
|
data,
|
|
|
},
|
|
|
function () {}
|
|
|
);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 点击复制组件按钮处理
|
|
|
var handleCopyComponentClick = function () {
|
|
|
$('#copy-component').click(function () {
|
|
|
if (!currentComponent) {
|
|
|
return;
|
|
|
}
|
|
|
console.log(currentComponent);
|
|
|
let widget = {
|
|
|
w: currentComponent.w,
|
|
|
h: currentComponent.h,
|
|
|
name: userLangConfig[locale].user[`${currentComponent.type}_default_name`],
|
|
|
type: currentComponent.type,
|
|
|
background: currentComponent.background,
|
|
|
eventsType: currentComponent.eventsType,
|
|
|
eventsAction: currentComponent.eventsAction,
|
|
|
defaultFocus: '0',
|
|
|
leftId: currentComponent.leftId,
|
|
|
rightId: currentComponent.rightId,
|
|
|
upId: currentComponent.upId,
|
|
|
downId: currentComponent.downId,
|
|
|
focusedStyle_background: currentComponent.focusedStyle_background,
|
|
|
focusedStyle_border_width: currentComponent.focusedStyle_border_width,
|
|
|
focusedStyle_border_color: currentComponent.focusedStyle_border_color,
|
|
|
focusedStyle_scale: currentComponent.focusedStyle_scale,
|
|
|
content: currentComponent.content,
|
|
|
};
|
|
|
if (currentComponent.type === 'image') {
|
|
|
widget.image = currentComponent.image;
|
|
|
} else if (currentComponent.type === 'text') {
|
|
|
widget.childrenType = currentComponent.childrenType;
|
|
|
widget.fontSize = currentComponent.fontSize;
|
|
|
widget.color = currentComponent.color;
|
|
|
widget.text = currentComponent.text;
|
|
|
widget.fontWeight = currentComponent.fontWeight;
|
|
|
}
|
|
|
if (currentScreen === 'main') {
|
|
|
main.grid.addWidget(widget);
|
|
|
} else if (currentScreen === 'welcome') {
|
|
|
welcome.grid.addWidget(widget);
|
|
|
}
|
|
|
console.log(welcome.grid.save());
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 点击画布处理
|
|
|
var handleCanvasClick = function () {
|
|
|
handleAddComponent(welcome.initData, welcome);
|
|
|
handleAddComponent(main.initData, main);
|
|
|
};
|
|
|
|
|
|
// 辅助函数:将带下划线的属性转换为嵌套对象
|
|
|
var transformUnderscoreData = function (obj) {
|
|
|
const newObj = { ...obj }; // 复制所有属性,包括原始带下划线的属性
|
|
|
for (const key in obj) {
|
|
|
if (obj.hasOwnProperty(key) && key.includes('_')) {
|
|
|
const parts = key.split('_');
|
|
|
let current = newObj;
|
|
|
// 遍历除最后一个部分外的所有部分,以创建嵌套结构
|
|
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
|
const part = parts[i];
|
|
|
// 如果当前层级中不存在该部分,则创建一个新对象
|
|
|
if (!current[part] || typeof current[part] !== 'object') {
|
|
|
current[part] = {};
|
|
|
}
|
|
|
current = current[part];
|
|
|
}
|
|
|
// 将原始值赋给嵌套结构的最后一个键
|
|
|
current[parts[parts.length - 1]] = obj[key];
|
|
|
}
|
|
|
}
|
|
|
return newObj;
|
|
|
};
|
|
|
// 保存的时候计算x,y,w,h
|
|
|
var conputedInitData = function (type, self) {
|
|
|
if (type === 'save') {
|
|
|
const { el, ...otherInfo } = self['initData'];
|
|
|
let initDataCopy = JSON.parse(JSON.stringify(otherInfo));
|
|
|
initDataCopy.children.forEach((item) => {
|
|
|
item.xCopy = item.x;
|
|
|
item.x = item.x * (1920 / 24);
|
|
|
item.yCopy = item.y;
|
|
|
item.y = item.y * cellHeight * 2;
|
|
|
|
|
|
item.wCopy = item.w;
|
|
|
item.w = item.w * (1920 / 24);
|
|
|
if (!item.hasOwnProperty('h')) {
|
|
|
item.h = 1;
|
|
|
}
|
|
|
item.hCopy = item.h;
|
|
|
item.h = item.h * cellHeight * 2;
|
|
|
item.fontSize = item.fontSize ? parseInt(item.fontSize) : item.fontSize;
|
|
|
item.defaultFocus = item.defaultFocus == '1' ? true : false;
|
|
|
|
|
|
// 调用辅助函数处理带下划线的数据
|
|
|
Object.assign(item, transformUnderscoreData(item)); // 将转换后的属性合并回item
|
|
|
});
|
|
|
console.log(initDataCopy);
|
|
|
return initDataCopy;
|
|
|
}
|
|
|
if (type === 'init') {
|
|
|
self['initData'].children.forEach((item) => {
|
|
|
item.x = item.xCopy;
|
|
|
item.y = item.yCopy;
|
|
|
item.w = item.wCopy;
|
|
|
item.h = item.hCopy;
|
|
|
item.defaultFocus = item.defaultFocus == true ? '1' : '0';
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var i18n = function () {
|
|
|
return new Promise((resolve) => {
|
|
|
requestFN({ url: '/getLanguage', hasPreFix: false }, function (data) {
|
|
|
data.language = 'zh_CN';
|
|
|
locale = data.language;
|
|
|
// 设置语言
|
|
|
layui.i18n.set({
|
|
|
locale: locale,
|
|
|
messages: {
|
|
|
// 扩展其他语言包
|
|
|
en_US: userLangConfig['en_US'],
|
|
|
zh_CN: userLangConfig['zh_CN'],
|
|
|
},
|
|
|
});
|
|
|
// 渲染页面模板
|
|
|
const template = $('#template').html();
|
|
|
const html = layui.laytpl(template, { tagStyle: 'modern' }).render();
|
|
|
$('#root').html(html);
|
|
|
resolve();
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var getImageData = function () {
|
|
|
requestFN({ url: 'listResourceByType', data: { type: 'image' } }, function (data) {
|
|
|
let el = $('#image');
|
|
|
let componentsHtml = [{ value: '', text: el.find('option').eq(0).text() }];
|
|
|
data.map((item) => {
|
|
|
componentsHtml.push({ value: api.baseUrl + item.path, text: `${item.name}` });
|
|
|
});
|
|
|
el.empty();
|
|
|
componentsHtml.forEach((item) => {
|
|
|
el.append(
|
|
|
$('<option>', {
|
|
|
value: item.value,
|
|
|
text: item.text,
|
|
|
selected: item.selected || false,
|
|
|
})
|
|
|
);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var getMenuData = function () {
|
|
|
requestFN({ url: 'listResourceByType', data: { type: 'menu' } }, function (data) {
|
|
|
let el = $('#eventsAction');
|
|
|
let componentsHtml = [{ value: '', text: el.find('option').eq(0).text() }];
|
|
|
data.map((item) => {
|
|
|
componentsHtml.push({ value: item.name, text: `${item.name}` });
|
|
|
});
|
|
|
el.empty();
|
|
|
componentsHtml.forEach((item) => {
|
|
|
el.append(
|
|
|
$('<option>', {
|
|
|
value: item.value,
|
|
|
text: item.text,
|
|
|
selected: item.selected || false,
|
|
|
})
|
|
|
);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var getComponentData = function () {
|
|
|
requestFN({ url: 'listResourceByType', data: { type: 'component' } }, function (data) {
|
|
|
let el = $('#childrenType');
|
|
|
let componentsHtml = [{ value: '', text: el.find('option').eq(0).text() }];
|
|
|
data.map((item) => {
|
|
|
componentsHtml.push({ value: item.name, text: `${item.name}` });
|
|
|
});
|
|
|
el.empty();
|
|
|
componentsHtml.forEach((item) => {
|
|
|
el.append(
|
|
|
$('<option>', {
|
|
|
value: item.value,
|
|
|
text: item.text,
|
|
|
selected: item.selected || false,
|
|
|
})
|
|
|
);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 获取单个参数
|
|
|
var getQueryParam = function (param) {
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
|
return urlParams.get(param);
|
|
|
};
|
|
|
|
|
|
var getTemplateData = function () {
|
|
|
return new Promise((resolve) => {
|
|
|
let id = getQueryParam('id');
|
|
|
if (id) {
|
|
|
requestFN({ url: 'getById', data: { id } }, function (data) {
|
|
|
$('#templateName').val(data.name);
|
|
|
const { welcomeData, mainData } = JSON.parse(data.content);
|
|
|
welcome.initData = welcomeData;
|
|
|
main.initData = mainData;
|
|
|
resolve();
|
|
|
});
|
|
|
} else {
|
|
|
resolve();
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/** 执行方法 */
|
|
|
$(function () {
|
|
|
(async function () {
|
|
|
// 国际化
|
|
|
await i18n();
|
|
|
// 获取模版数据
|
|
|
await getTemplateData();
|
|
|
|
|
|
getImageData();
|
|
|
getMenuData();
|
|
|
getComponentData();
|
|
|
|
|
|
// 初始化
|
|
|
initGridStack();
|
|
|
init('welcome', welcome);
|
|
|
init('main', main);
|
|
|
// 调用绑定
|
|
|
bindComponentEvents();
|
|
|
// 处理Tab切换
|
|
|
handleTabSwitch();
|
|
|
// 处理保存按钮
|
|
|
handleSaveClick();
|
|
|
// 处理复制组件按钮
|
|
|
handleCopyComponentClick();
|
|
|
// 处理画布点击事件
|
|
|
handleCanvasClick();
|
|
|
})();
|
|
|
});
|
|
|
})();
|