Commit 3a988bf9 authored by 张晨辰's avatar 张晨辰

feat: 行为编辑

parent 0fcc4e27
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
width="auto" width="auto"
:content="url" :content="url"
> >
<img v-if="url" :src="url" alt="" /> <img style="max-width: 200px;" v-if="url" :src="url" alt="" />
<el-input v-model="swvalue" slot="reference" @drop.native="drop" @dragover.native="dragOver"></el-input> <el-input v-model="swvalue" slot="reference" @drop.native="drop" @dragover.native="dragOver"></el-input>
</el-popover> </el-popover>
</template> </template>
......
...@@ -3,9 +3,7 @@ ...@@ -3,9 +3,7 @@
*/ */
import Vue from "vue"; import Vue from "vue";
import JSZip from "jszip"; import JSZip from "jszip";
import { projectApi } from "../../api"; import { projectApi } from "../../api";
// import { compoleteComponentData } from '../../utils/compoleteCmpData';
import path from "path"; import path from "path";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
import { getCmpProps, flattenViews, getCmpByUUID } from '../../utils/common'; import { getCmpProps, flattenViews, getCmpByUUID } from '../../utils/common';
...@@ -50,7 +48,6 @@ export const projectStore = { ...@@ -50,7 +48,6 @@ export const projectStore = {
Vue.set(localData, 'assets', []); Vue.set(localData, 'assets', []);
Vue.set(localData, 'dataMapping', []); Vue.set(localData, 'dataMapping', []);
} }
// compoleteComponentData(state.data.views);
}, },
/** /**
* 激活组件 * 激活组件
...@@ -58,11 +55,9 @@ export const projectStore = { ...@@ -58,11 +55,9 @@ export const projectStore = {
* @param {*} id * @param {*} id
*/ */
activeComponent(state, item) { activeComponent(state, item) {
// debugger;
if (item !== state.activeComponent) { if (item !== state.activeComponent) {
state.activeComponent = item || state.activeComponent; state.activeComponent = item || state.activeComponent;
state.activeComponent.properties = state.activeComponent.properties || {}; state.activeComponent.properties = state.activeComponent.properties || {};
console.log('mutations activeComponent', state);
} }
}, },
/** /**
...@@ -77,11 +72,14 @@ export const projectStore = { ...@@ -77,11 +72,14 @@ export const projectStore = {
let _prop = _.cloneDeep(state.activeComponent.properties || {}); let _prop = _.cloneDeep(state.activeComponent.properties || {});
if (state.operateStack.length) { if (state.operateStack.length) {
// state.operateStack.shift();
if (state.stackIndex !== 0) { if (state.stackIndex !== 0) {
// 如果操作栈index有值,说明之前做过撤销/重做
// 则把操作index之后的数据都丢弃
state.operateStack = state.operateStack.slice(state.stackIndex); state.operateStack = state.operateStack.slice(state.stackIndex);
} }
} else { } else {
// 如果操作栈中是空的,说明从来没有操作
// 则在开始插入数据的时候,额外插入一条最原始的数据
state.operateStack.unshift({ state.operateStack.unshift({
uuid: state.activeComponent.uuid, uuid: state.activeComponent.uuid,
properties: _.cloneDeep(_prop) properties: _.cloneDeep(_prop)
...@@ -89,14 +87,16 @@ export const projectStore = { ...@@ -89,14 +87,16 @@ export const projectStore = {
} }
state.stackIndex = 0; // 开始编辑的时候,重置操作栈的下标 state.stackIndex = 0; // 开始编辑的时候,重置操作栈的下标
_prop = Object.assign({}, _prop, props); _prop = Object.assign({}, _prop, props);
// 在操作栈中插入最新值
state.operateStack.unshift({ state.operateStack.unshift({
uuid: state.activeComponent.uuid, uuid: state.activeComponent.uuid,
properties: _.cloneDeep(_prop) properties: _.cloneDeep(_prop)
}); });
// 操作栈最大200
if (state.operateStack.length > 200) {
state.operateStack.pop();
}
Vue.set(state.activeComponent, 'properties', _prop); Vue.set(state.activeComponent, 'properties', _prop);
console.log('operateStack', state.operateStack);
// console.log('modifyProperties', state.activeComponent);
}, },
/** /**
* 修改当前组件 * 修改当前组件
...@@ -117,17 +117,14 @@ export const projectStore = { ...@@ -117,17 +117,14 @@ export const projectStore = {
delete prop[key]; delete prop[key];
} }
}); });
console.log('new properties', cmpProps);
Vue.set(state.activeComponent, 'properties', cmpProps); Vue.set(state.activeComponent, 'properties', cmpProps);
} }
console.log('modifyComponent', state.activeComponent);
}, },
/** /**
* assets拖拽 * assets拖拽
* @param {*} data * @param {*} data
*/ */
assetDragStart(state, data) { assetDragStart(state, data) {
console.log('assetDragStart', data);
state.dragUUID = data.uuid; state.dragUUID = data.uuid;
}, },
/** /**
...@@ -143,7 +140,6 @@ export const projectStore = { ...@@ -143,7 +140,6 @@ export const projectStore = {
// 如果uuid不一样,说明是不同节点的操作,需要把下标多移动一位 // 如果uuid不一样,说明是不同节点的操作,需要把下标多移动一位
state.stackIndex += step; state.stackIndex += step;
} }
console.log('undoRedo', state.stackIndex);
let _operate = state.operateStack[state.stackIndex]; let _operate = state.operateStack[state.stackIndex];
if (_operate) { if (_operate) {
let _cmp = getCmpByUUID(_operate.uuid, state.data.views); let _cmp = getCmpByUUID(_operate.uuid, state.data.views);
...@@ -152,7 +148,15 @@ export const projectStore = { ...@@ -152,7 +148,15 @@ export const projectStore = {
} }
} }
}, },
modifyProject(state, ) { /**
* 修改节点的events
* @param {*} state
* @param {*} event
*/
updateNodeEvent(state, event) {
state.activeComponent.events = _.assign(state.activeComponent.events, event)
},
modifyProject(state) {
}, },
addNode(state, { node, name, type }) { addNode(state, { node, name, type }) {
...@@ -160,6 +164,7 @@ export const projectStore = { ...@@ -160,6 +164,7 @@ export const projectStore = {
name, name,
type, type,
properties: {}, properties: {},
events: {},
uuid: generateUUID(), uuid: generateUUID(),
}; };
if (node) { if (node) {
...@@ -265,7 +270,7 @@ export const projectStore = { ...@@ -265,7 +270,7 @@ export const projectStore = {
} }
let result = flattenViews(_.cloneDeep(_view)); let result = flattenViews(_.cloneDeep(_view));
console.log('componentList', result); // console.log('componentList', result);
return result; return result;
} }
}, },
...@@ -369,6 +374,13 @@ export const projectStore = { ...@@ -369,6 +374,13 @@ export const projectStore = {
commit('modifyComponent', data) commit('modifyComponent', data)
}, },
/**
* 编辑节点事件
*/
updateNodeEvent({ commit }, data) {
commit('updateNodeEvent', data)
},
exportView({ state }, view) { exportView({ state }, view) {
let zip = new JSZip(); let zip = new JSZip();
zip.file('view.json', JSON.stringify(view)); zip.file('view.json', JSON.stringify(view));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
line-height: 25px; line-height: 25px;
} }
.zero-inspector-form { .zero-inspector-props-form {
.el-input-number.el-input-number--mini, .el-select.el-select--mini { .el-input-number.el-input-number--mini, .el-select.el-select--mini {
width: 100%; width: 100%;
} }
......
...@@ -256,7 +256,7 @@ export const styles = { ...@@ -256,7 +256,7 @@ export const styles = {
}); });
result += `background-position: center;background-size: 100% 100%;` result += `background-position: center;background-size: 100% 100%;`
console.log('getComponentStyle', result); // console.log('getComponentStyle', result);
return result; return result;
} }
} }
......
export default ['click', 'touchstart', 'touchend', 'touchmove']
\ No newline at end of file
...@@ -2,25 +2,7 @@ ...@@ -2,25 +2,7 @@
<pane icon="el-icon-s-operation" :title="$t('panes.Inspector')"> <pane icon="el-icon-s-operation" :title="$t('panes.Inspector')">
<el-tabs v-model="tab" type="border-card" class="inspector-tabs"> <el-tabs v-model="tab" type="border-card" class="inspector-tabs">
<el-tab-pane label="Props" name="properties"> <el-tab-pane label="Props" name="properties">
<div class="zero-inspector-form"> <props-tab/>
<el-form ref="form" size="mini" v-if="activeComponent.uuid" :model="form" label-width="80px">
<el-divider content-position="left">配置</el-divider>
<el-form-item label="名称">
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item>
<el-form-item label="类型">
<el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型">
<el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option>
</el-select>
</el-form-item>
<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" :item="p" :properties="activeComponent.properties"></dynamic-component>
</el-form-item>
</template>
</el-form>
</div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="Behavior" name="behavior"> <el-tab-pane label="Behavior" name="behavior">
<behavior-tab/> <behavior-tab/>
...@@ -30,63 +12,20 @@ ...@@ -30,63 +12,20 @@
</template> </template>
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex';
import Pane from '../../components/Pane'; import Pane from '../../components/Pane';
import _ from 'lodash';
import { componentsMap, getCmpProps } from '../../utils/common';
import dynamicComponent from './components/dynamicComponent';
import BehaviorTab from "./Inspector/BehaviorTab"; import BehaviorTab from "./Inspector/BehaviorTab";
import PropsTab from "./Inspector/PropsTab";
export default { export default {
name: 'Inspector', name: 'Inspector',
components: {BehaviorTab, Pane, 'dynamic-component': dynamicComponent }, components: {BehaviorTab, PropsTab, Pane},
data() { data() {
return { return {
tab: 'properties', tab: 'properties'
componentsMap,
form: {
name: '',
type: '',
properties: {}
}
}; };
},
computed: {
...mapGetters(['activeComponent', 'componentList']),
cmpProps: function() {
return getCmpProps(this.activeComponent.type);
}
},
watch: {
activeComponent: {
deep: true,
handler: function(val) {
this.form.name = val.name || '';
this.form.type = val.type || '';
this.form.properties = val.properties || {};
}
}
},
methods: {
handleChange(label, v) {
this.$store.dispatch('modifyComponent', {
label: label,
value: v
});
}
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.zero-inspector-form {
width: 100%;
padding-right: 10px;
.el-form-item--mini.el-form-item {
margin-bottom: 10px;
}
.el-divider__text {
background-color: #e9e9e9;
}
}
</style> </style>
\ No newline at end of file
<template> <template>
<div> <div class="zero-inspector-behavior-form" v-if="activeComponent.uuid">
<el-button @click="showBehaviorEditor">行为编辑器</el-button> <el-form ref="form" size="mini" label-width="80px">
<behavior-editor-dialog ref="behaviorEditorDialog"></behavior-editor-dialog> <div v-for="(evn, key) in eventsObj" :key="key">
<el-form-item label="触发事件:">
<div>{{key}}</div>
<div >
<el-tooltip content="是否单次触发" placement="top">
<el-switch v-model="evn.once" @change="v => handleOnceChange(key, v)"></el-switch>
</el-tooltip>
<el-tooltip content="行为编辑" placement="top" style="margin-left: 20px;">
<el-button size="mini" @click="showBehaviorEditor(evn, key)">
行为编辑
<i v-if="evn.behaviors && evn.behaviors.length" class="el-icon-check el-icon--right"></i>
</el-button>
</el-tooltip>
</div>
</el-form-item>
</div>
</el-form>
<behavior-editor-dialog :behaviors="behaviors" @change="v => handleBehaviorsChange(v)" ref="behaviorEditorDialog"></behavior-editor-dialog>
</div> </div>
</template> </template>
<script> <script>
import BehaviorEditorDialog from "../dialogs/BehaviorEditorDialog"; import { mapGetters } from 'vuex';
export default { import _ from 'lodash';
name: "BehaviorTab", import events from '../../../utils/events';
components: {BehaviorEditorDialog}, import BehaviorEditorDialog from '../dialogs/BehaviorEditorDialog';
export default {
name: 'BehaviorTab',
data() {
let eventsObj = {};
events.forEach(event => {
eventsObj[event] = {
once: false,
behaviors: []
};
});
return {
eventsObj,
behaviors: [],
currentEvent: ''
};
},
components: { BehaviorEditorDialog },
computed: {
...mapGetters(['activeComponent', 'componentList'])
},
methods: { methods: {
showBehaviorEditor() { showBehaviorEditor(evn, key) {
this.currentEvent = key;
this.behaviors = evn.behaviors || [];
this.$refs.behaviorEditorDialog.show(); this.$refs.behaviorEditorDialog.show();
},
/**
* 当前选中组件发生变化时,更新eventsObj的数据
*/
updateEventsObj() {
let _events = this.activeComponent.events || {};
_.forIn(this.eventsObj, (value, key) => {
if (_events[key]) {
this.$set(this.eventsObj, key, _.cloneDeep(_events[key]));
} else {
value.once = false;
value.behaviors = [];
} }
});
},
/**
* 是否只执行一次
*/
handleOnceChange(key, v) {
let _event = this.eventsObj[key];
// 如果没有behavior,once没有用处,则不执行
if (_event.behaviors && _event.behaviors.length) {
let event = {};
event[key] = {
once: v,
behaviors: _event.behaviors
};
this.$store.dispatch('updateNodeEvent', event);
} }
},
/**
* 行为发生变化,同步数据
*/
handleBehaviorsChange(v) {
if (this.currentEvent && v && v.length) {
let event = {};
let currentEvent = this.eventsObj[this.currentEvent];
event[this.currentEvent] = Object.assign(currentEvent, { behaviors: v });
this.$store.dispatch('updateNodeEvent', event);
this.updateEventsObj();
} }
}
},
watch: {
'activeComponent.uuid': function() {
this.updateEventsObj();
console.log('activeComponent.uuid change');
}
}
};
</script> </script>
<style scoped> <style scoped>
</style> </style>
\ No newline at end of file
<template>
<div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<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>
<el-form-item label="类型">
<el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型">
<el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option>
</el-select>
</el-form-item>
<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" :item="p" :properties="activeComponent.properties"></dynamic-component>
</el-form-item>
</template>
</el-form>
</el-collapse-item>
<el-collapse-item title="脚本" name="scripts">
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { componentsMap, getCmpProps } from '../../../utils/common';
import dynamicComponent from '../components/dynamicComponent';
export default {
name: 'PropsTab',
components: { 'dynamic-component': dynamicComponent },
data() {
return {
componentsMap,
form: {
name: '',
type: '',
properties: {}
},
configColl: ['properties']
};
},
computed: {
...mapGetters(['activeComponent', 'componentList']),
cmpProps: function() {
return getCmpProps(this.activeComponent.type);
}
},
watch: {
activeComponent: {
deep: true,
handler: function(val) {
this.form.name = val.name || '';
this.form.type = val.type || '';
this.form.properties = val.properties || {};
}
}
},
methods: {
handleChange(label, v) {
this.$store.dispatch('modifyComponent', {
label: label,
value: v
});
}
}
};
</script>
<style lang="scss">
.zero-inspector-props-form {
width: 100%;
padding-right: 10px;
.el-form-item--mini.el-form-item {
margin-bottom: 10px;
}
.el-divider__text {
background-color: #e9e9e9;
}
}
</style>
\ No newline at end of file
...@@ -55,7 +55,7 @@ export default { ...@@ -55,7 +55,7 @@ export default {
width: w, width: w,
height: h height: h
}); });
console.log('handleResize', x, y, w, h); // console.log('handleResize', x, y, w, h);
} }
}, },
...@@ -70,11 +70,11 @@ export default { ...@@ -70,11 +70,11 @@ export default {
x: x, x: x,
y: y y: y
}); });
console.log('handleDragging', x, y); // console.log('handleDragging', x, y);
} }
}, },
resizeStop(x, y, w, h) { resizeStop(x, y, w, h) {
console.log('resizeStop', x, y, w, h); // console.log('resizeStop', x, y, w, h);
} }
}, },
computed: { computed: {
...@@ -97,7 +97,7 @@ export default { ...@@ -97,7 +97,7 @@ export default {
w: _props.width || _node.width.value, w: _props.width || _node.width.value,
h: _props.height || _node.height.value h: _props.height || _node.height.value
}; };
console.log('####position', result); // console.log('####position', result);
return result; return result;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
}, },
onSave() { onSave() {
this.visible = false; this.visible = false;
this.$emit('change')
}, },
onOpened() { onOpened() {
this.$refs.behaviorEditor.measure(); this.$refs.behaviorEditor.measure();
......
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