Commit bb3df274 authored by 张晨辰's avatar 张晨辰

feat: 脚本

parent a12fb83a
......@@ -34,8 +34,7 @@ export default new Vuex.Store({
'addDataMapping',
'deleteDataMapping',
'modifyDataMapping',
'modifyComponent',
'modifyProperties'
'modifyActiveView'
]
})
]
......
......@@ -20,6 +20,7 @@ export const projectStore = {
dataMapping: [],
},
activeComponent: {},
activeComponentCopy: {}, // 当前选中节点的镜像,用来处理拖拽时数据变化频繁的问题
activeIdList: [],
activeViews: '',
dragUUID: '',
......@@ -58,67 +59,79 @@ export const projectStore = {
if (item !== state.activeComponent) {
state.activeComponent = item || state.activeComponent;
state.activeComponent.properties = state.activeComponent.properties || {};
state.activeComponentCopy = _.cloneDeep(state.activeComponent);
}
},
/**
* 修改当前组件的属性
* 修改当前选中的节点
* @param {*} state
* @param {*} data
* @param {*} view
*/
modifyProperties(state, props) {
if (!props) {
modifyActiveView(state, view) {
if (!view) {
return;
}
let _prop = _.cloneDeep(state.activeComponent.properties || {});
let _view = _.cloneDeep(state.activeComponent || {});
if (state.operateStack.length) {
if (state.stackIndex !== 0) {
// 如果操作栈index有值,说明之前做过撤销/重做
// 则把操作index之后的数据都丢弃
state.operateStack = state.operateStack.slice(state.stackIndex);
}
let _last_operate = state.operateStack[0];
// 上一次的操作和最新一次操作uuid不同,表示发生了不同视图的操作
// 需要记录当前视图的原始数据
if (_last_operate.uuid !== _view.uuid) {
state.operateStack.unshift(_.cloneDeep(_view));
}
} else {
// 如果操作栈中是空的,说明从来没有操作
// 则在开始插入数据的时候,额外插入一条最原始的数据
state.operateStack.unshift({
uuid: state.activeComponent.uuid,
properties: _.cloneDeep(_prop)
});
state.operateStack.unshift(_.cloneDeep(_view));
}
state.stackIndex = 0; // 开始编辑的时候,重置操作栈的下标
_prop = Object.assign({}, _prop, props);
_view = _.merge(_view, view);
// 在操作栈中插入最新值
state.operateStack.unshift({
uuid: state.activeComponent.uuid,
properties: _.cloneDeep(_prop)
});
state.operateStack.unshift(_.cloneDeep(_.assign({ uuid: _view.uuid }, view)));
// 操作栈最大200
if (state.operateStack.length > 200) {
state.operateStack.pop();
}
Vue.set(state.activeComponent, 'properties', _prop);
_.forIn(view, (value, key) => {
Vue.set(state.activeComponent, key, _view[key]);
})
if (view.type) {
// view.type有值说明修改了节点的类型
// 如果修改了节点类型,需要删除无用的属性
let defaultProps = Object.keys(getCmpProps(view.type));
let _properties = _.cloneDeep(state.activeComponent.properties);
_.forIn(_properties, (value, key, prop) => {
if (defaultProps.indexOf(key) === -1) {
delete prop[key];
}
});
Vue.set(state.activeComponent, 'properties', _properties);
}
state.activeComponentCopy = _.cloneDeep(state.activeComponent);
},
/**
* 修改当前组件
* 修改当前组件镜像的属性
* @param {*} state
* @param {*} data
* @param {*} props
*/
modifyComponent(state, data) {
if (!data || !data.label) {
modifyCopyProperties(state, props) {
if (!props) {
return;
}
Vue.set(state.activeComponent, data.label, data.value);
if (data.label === 'type') {
// 如果修改了组件类型,需要删除无用的属性
let defaultProps = Object.keys(getCmpProps(data.value));
let cmpProps = _.cloneDeep(state.activeComponent.properties);
_.forIn(cmpProps, (value, key, prop) => {
if (defaultProps.indexOf(key) === -1) {
delete prop[key];
}
});
Vue.set(state.activeComponent, 'properties', cmpProps);
}
let _prop = _.cloneDeep(state.activeComponentCopy.properties || {});
_prop = Object.assign({}, _prop, props);
Vue.set(state.activeComponentCopy, 'properties', _prop);
},
/**
* assets拖拽
......@@ -144,17 +157,12 @@ export const projectStore = {
if (_operate) {
let _cmp = getCmpByUUID(_operate.uuid, state.data.views);
if (_cmp) {
_cmp.properties = _operate.properties;
_cmp = _.merge(_cmp, _operate);
if (_operate.uuid === state.activeComponentCopy.uuid) {
state.activeComponentCopy = _.cloneDeep(_cmp)
}
}
}
},
/**
* 修改节点的events
* @param {*} state
* @param {*} event
*/
updateNodeEvent(state, event) {
state.activeComponent.events = _.assign(state.activeComponent.events, event)
},
modifyProject(state) {
......@@ -252,6 +260,9 @@ export const projectStore = {
activeComponent: state => {
return state.activeComponent;
},
activeComponentCopy: state => {
return state.activeComponentCopy;
},
/**
* 当前激活的组件ID
*/
......@@ -334,8 +345,6 @@ export const projectStore = {
context.state.activeViews = _view.data.uuid;
}
// let _cmp = context.getters.componentList.find(c => c.uuid === data.data.uuid)
context.commit('activeComponent', data.data);
},
/**
......@@ -357,28 +366,49 @@ export const projectStore = {
let _img = new Image();
_img.src = _url;
_img.onload = function () {
commit('modifyProperties', {
commit('modifyActiveView', {
properties: {
width: _img.width,
height: _img.height
}
});
}
}
}
commit('modifyProperties', props)
commit('modifyActiveView', {
properties: props
})
},
/**
* 修改镜像的属性
* @param {*} param0
* @param {*} props
*/
modifyCopyProperties({ commit }, props) {
commit('modifyCopyProperties', props)
},
/**
* 修改组件
* 修改当前选中的节点
*/
modifyComponent({ commit }, data) {
commit('modifyComponent', data)
modifyActiveView({ commit }, view) {
commit('modifyActiveView', view)
},
/**
* 编辑节点事件
* 新增节点脚本
* @param {*} param0
* @param {*} data
*/
updateNodeEvent({ commit }, data) {
commit('updateNodeEvent', data)
addNodeScript({ commit, state }, script) {
let _scripts = _.cloneDeep(state.activeComponent.scripts || []);
_scripts.push({
script: script,
options: {}
});
commit('modifyActiveView', {
scripts: _scripts
})
},
exportView({ state }, view) {
......
export default [{
script: 'wave',
options: {
duration: {
title: 'duration',
type: 'inputNumber',
value: 500
},
autoPlay: {
title: 'autoPlay',
type: 'switch',
value: true
},
type: {
title: 'type',
type: 'swSelect',
value: 'cubicIn'
}
}
}, {
script: 'wave2',
options: {
duration: {
title: 'duration',
type: 'inputNumber',
value: 500
},
autoPlay: {
title: 'autoPlay',
type: 'switch',
value: true
},
type: {
title: 'type',
type: 'swSelect',
value: 'cubicIn'
}
}
}]
\ No newline at end of file
......@@ -81,7 +81,9 @@ export default {
once: v,
behaviors: _event.behaviors
};
this.$store.dispatch('updateNodeEvent', event);
this.$store.dispatch('modifyActiveView', {
events: event
});
}
},
/**
......@@ -92,7 +94,9 @@ export default {
let event = {};
let currentEvent = this.eventsObj[this.currentEvent];
event[this.currentEvent] = Object.assign(currentEvent, { behaviors: v });
this.$store.dispatch('updateNodeEvent', event);
this.$store.dispatch('modifyActiveView', {
events: event
});
this.updateEventsObj();
}
}
......
<template>
<div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<el-form ref="form" size="mini" :model="form" label-width="80px">
<el-collapse v-model="configColl">
<el-collapse-item title="配置" name="properties">
<el-form ref="form" size="mini" :model="form" label-width="80px">
<el-form-item label="名称">
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item>
......@@ -14,13 +14,23 @@
<template v-for="(p, key) in cmpProps">
<el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title">
<!-- {{key}} -->
<dynamic-component :label="key" :component-value="getDynamicValue(p, key)" :component-props="getDynamicProps(p)" :component-type="getDynamicCmpType(p)" @onChange="v => handlePropertiesChange(key, v)"></dynamic-component>
<dynamic-component :component-value="getPropValue(p, key)" :component-props="getPropProps(p)" :component-type="getPropCmpType(p)" @onChange="v => handlePropertiesChange(key, v)"></dynamic-component>
</el-form-item>
</template>
</el-form>
</el-collapse-item>
<el-collapse-item title="脚本" name="scripts">
<div style="text-align: center;">
<el-collapse accordion v-if="activeComponent.scripts && activeComponent.scripts.length">
<template v-for="(script, index) in activeComponent.scripts">
<el-collapse-item :title="getScriptName(script.script)" :key="script + index">
<template v-for="(p, key) in getScriptOptions(script.script)">
<el-form-item :key="activeComponent.uuid + index + key" :label="key">
<dynamic-component :component-value="getScriptValue(p, key, index)" :component-props="getScriptProps(p, index)" :component-type="getScriptType(p, index)" @onChange="v => handleScriptChange(index, key, v)"></dynamic-component>
</el-form-item>
</template>
</el-collapse-item>
</template>
</el-collapse>
<div style="padding-top: 15px;text-align: center;">
<el-popover
placement="top"
width="300"
......@@ -34,6 +44,7 @@
</div>
</el-collapse-item>
</el-collapse>
</el-form>
<!-- <div class="script-config-dialog" v-show="scriptDialog">
<el-tree :data="scripts" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div> -->
......@@ -42,8 +53,8 @@
<script>
import { mapGetters } from 'vuex';
import _ from 'lodash';
import { componentsMap, getCmpProps } from '../../../utils/common';
import scripts from '../../../utils/scripts';
import dynamicComponent from '../components/dynamicComponent';
const componentMapper = {
......@@ -87,38 +98,66 @@ const componentMapper = {
}
};
const scriptTypeMap = {
}
number: {
component: 'el-input-number',
props: {
size: 'mini'
}
},
string: {
component: 'el-input'
},
boolean: {
component: 'el-switch',
props: {
activeColor: '#13ce66',
inactiveColor: '#eee',
width: 40
}
},
color: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
}
};
export default {
name: 'PropsTab',
components: { 'dynamic-component': dynamicComponent },
data() {
console.log('scripts', scripts);
return {
scripts,
componentsMap,
scriptDialog: false,
form: {
name: '',
type: '',
properties: {}
properties: {},
scripts: []
},
defaultProps: {
children: 'children',
label: 'script'
label: 'name'
},
configColl: ['properties']
};
},
computed: {
...mapGetters(['activeComponent', 'componentList']),
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']),
cmpProps: function() {
// 获取properties.js中的默认配置
return getCmpProps(this.activeComponent.type);
},
scripts: function() {
return this.$store.state.env.scripts;
}
},
watch: {
......@@ -133,19 +172,20 @@ export default {
},
methods: {
handleChange(label, v) {
this.$store.dispatch('modifyComponent', {
label: label,
value: v
});
let _view = {};
_view[label] = v;
this.$store.dispatch('modifyActiveView', _view);
},
/**
* 脚本预设对象选中
*/
handleNodeClick(data, node, cmp) {
console.log('handleNodeClick', data);
handleNodeClick(script) {
console.log('handleNodeClick', script);
this.$store.dispatch('addNodeScript', script.id);
this.scriptDialog = false;
},
/**
* 属性栏发生改变
* 基础属性发生改变
*/
handlePropertiesChange(key, v) {
console.log('handlePropertiesChange', key, v);
......@@ -154,31 +194,89 @@ export default {
_prop[key] = v;
this.$store.dispatch('modifyProperties', _prop);
},
/**
* 事件属性发生改变
*/
handleScriptChange(index, key, v) {
let _options = {};
_options[key] = v;
let _scripts = _.cloneDeep(this.activeComponent.scripts);
let _script = _scripts[index];
_script.options = _.assign(_script.options, _options);
_scripts[index] = _script;
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
});
},
/**
* 获取动态组件的类型
*/
getDynamicCmpType(item) {
getPropCmpType(item) {
return componentMapper[item.type].component;
},
/**
* 获取动态组件的属性v-bind
*/
getDynamicProps(item) {
getPropProps(item) {
let _cmp = componentMapper[item.type];
return {
size: 'mini',
...(_cmp.props || {}),
...item.props,
options: item.options || {}
}
};
},
/**
* 获取当前选中节点对应的属性的值
*/
getDynamicValue(item, key) {
// debugger;
let _properties = this.activeComponent.properties;
getPropValue(item, key) {
let _properties = this.activeComponentCopy.properties;
return _properties[key] || item.value;
},
getScriptValue(item, key, index) {
let _script = this.activeComponent.scripts[index];
// let result =
return _script.options[key] || item.default;
},
getScriptProps(item, index) {
let _type = item.type;
let _options = {};
if (_.isArray(_type)) {
// 如果脚本选项对应的类型是数组,说明是枚举类型
_options = item.type.map(i => {
return {
label: i,
value: i
};
});
_options.unshift({
label: '请选择',
value: ''
});
_type = 'select';
}
let _cmp = scriptTypeMap[_type];
return {
size: 'mini',
...(_cmp.props || {}),
options: _options
};
},
getScriptType(item, index) {
// 如果脚本选项对应的类型是数组,说明是枚举类型
let _type = _.isArray(item.type) ? 'select' : item.type;
return scriptTypeMap[_type].component;
},
getScriptName(id) {
console.log('getScriptName', id);
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.name : '';
},
getScriptOptions(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.options : {};
}
}
};
......@@ -195,7 +293,7 @@ export default {
background-color: #e9e9e9;
}
}
.script-config-dialog{
.script-config-dialog {
height: 350px;
}
</style>
\ No newline at end of file
......@@ -19,8 +19,9 @@
:style="styleObject"
v-bind="position"
@dragging="handleDragging"
@dragstop="handleDragStop"
@resizing="handleResize"
@resizestop="resizeStop"
@resizestop="handleResizeStop"
@deactivated="handleDeactivated"
>
</vue-draggable-resizable>
......@@ -46,10 +47,10 @@ export default {
if (!this.active || !this.activeComponentId) {
return false;
}
let _prop = this.activeComponent.properties;
let _prop = this.activeComponentCopy.properties;
if (_prop.x !== x || _prop.y !== y || _prop.width !== w || _prop.height !== h) {
this.$store.dispatch('modifyProperties', {
this.$store.dispatch('modifyCopyProperties', {
x: x,
y: y,
width: w,
......@@ -63,32 +64,57 @@ export default {
if (!this.active || !this.activeComponentId) {
return false;
}
let _prop = this.activeComponent.properties;
let _prop = this.activeComponentCopy.properties;
if (_prop.x !== x || _prop.y !== y) {
this.$store.dispatch('modifyProperties', {
this.$store.dispatch('modifyCopyProperties', {
x: x,
y: y
});
// console.log('handleDragging', x, y);
}
},
resizeStop(x, y, w, h) {
// console.log('resizeStop', x, y, w, h);
handleResizeStop(x, y, w, h) {
if (!this.active || !this.activeComponentId) {
return false;
}
let _prop = this.activeComponent.properties;
if (_prop.x !== x || _prop.y !== y || _prop.width !== w || _prop.height !== h) {
this.$store.dispatch('modifyProperties', {
x: x,
y: y,
width: w,
height: h
});
}
},
handleDragStop(x, y) {
if (!this.active || !this.activeComponentId) {
return false;
}
let _prop = this.activeComponent.properties;
if (_prop.x !== x || _prop.y !== y) {
this.$store.dispatch('modifyProperties', {
x: x,
y: y
});
}
}
},
computed: {
...mapState(['project']),
...mapGetters(['activeComponent', 'componentList', 'activeComponentId']),
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList', 'activeComponentId']),
active() {
return !!this.activeComponentId;
// return this.activeComponentId === (this.activeComponent || {}).uuid;
},
styleObject() {
return styles.getComponentStyle(this.activeComponent, this.project, this.componentList, true);
return styles.getComponentStyle(this.activeComponentCopy, this.project, this.componentList, true);
},
position() {
let _props = this.activeComponent.properties || {};
let _props = this.activeComponentCopy.properties || {};
const _node = properties.node;
// console.log('********', _props);
let result = {
......@@ -120,7 +146,7 @@ export default {
width: 10px;
height: 10px;
font-size: 1px;
background: #EEE;
background: #eee;
border: 1px solid #333;
}
.handle-tl {
......
<template>
<!-- <vue-draggable-resizable
:minw="1"
:minh="1"
:z="2"
:style="styleObject"
:class="[active ? 'choosed-cmp' : 'unchoosed-cmp', isTyping && 'isTyping']"
v-bind="position"
@dragging="handleDragging"
@resizing="handleResize"
@deactivated="handleDeactivated"
>
<div
class="sword-compomnent-content-wrapper"
:contenteditable="false"
@dblclick="handleEnableInput"
@input="handleInput"
@keyup.delete.prevent="changeEditRange"
>
</div>
</vue-draggable-resizable> -->
<custom-node :custom-style="styleObject" :properties="componentData.properties"></custom-node>
</template>
<script>
......@@ -43,14 +22,19 @@ export default {
},
computed: {
...mapState(['project']),
...mapGetters(['componentList']),
...mapGetters(['activeComponentCopy', 'componentList']),
styleObject() {
return styles.getComponentStyle(this.componentData, this.project, this.componentList);
let result = '';
if (this.componentData.uuid === this.activeComponentCopy.uuid) {
result = styles.getComponentStyle(this.activeComponentCopy, this.project, this.componentList);
} else {
result = styles.getComponentStyle(this.componentData, this.project, this.componentList);
}
return result;
}
}
};
</script>
<style>
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment