Commit 4e2a11fb authored by rockyl's avatar rockyl

增加节点选择器

增加参数连接器
parent fe14e83c
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"id": "entry", "id": "entry",
"name": "Entry", "name": "Entry",
"group": "base", "group": "base",
"options": {}, "props": {},
"output": [ "output": [
"success" "success"
] ]
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
"id": "wait", "id": "wait",
"name": "Wait", "name": "Wait",
"group": "base", "group": "base",
"options": { "props": {
"duration": { "duration": {
"type": "number", "type": "number",
"default": 1000 "default": 1000
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
"uuid": "2", "uuid": "2",
"meta": "wait", "meta": "wait",
"alias": "等待", "alias": "等待",
"options": { "props": {
"duration": 500 "duration": 500
} }
} }
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
{ {
"id": "wave", "id": "wave",
"name": "Wave", "name": "Wave",
"options": { "props": {
"duration": { "duration": {
"type": "number", "type": "number",
"default": 1000 "default": 1000
......
...@@ -11,17 +11,19 @@ const data = { ...@@ -11,17 +11,19 @@ const data = {
{ {
id: 'entry', id: 'entry',
name: 'Entry', name: 'Entry',
desc: '入口',
group: 'base', group: 'base',
type: 'builtin', type: 'builtin',
options: {}, props: {},
output: ['success'], output: ['success'],
}, },
{ {
id: 'wait', id: 'wait',
name: 'Wait', name: 'Wait',
desc: '等待执行',
group: 'base', group: 'base',
type: 'builtin', type: 'builtin',
options: { props: {
duration: {type: 'number', default: 1000}, duration: {type: 'number', default: 1000},
}, },
output: ['complete'], output: ['complete'],
...@@ -29,6 +31,7 @@ const data = { ...@@ -29,6 +31,7 @@ const data = {
{ {
id: 'prefab1', id: 'prefab1',
name: 'Prefab1', name: 'Prefab1',
desc: '转盘预设',
type: 'builtin', type: 'builtin',
isPrefab: true, isPrefab: true,
subEntry: '1', subEntry: '1',
...@@ -45,7 +48,7 @@ const data = { ...@@ -45,7 +48,7 @@ const data = {
uuid: '2', uuid: '2',
meta: 'wait', meta: 'wait',
alias: '等待', alias: '等待',
options: { props: {
duration: 500, duration: 500,
}, },
}, },
...@@ -56,7 +59,7 @@ const data = { ...@@ -56,7 +59,7 @@ const data = {
{ {
id: 'wave', id: 'wave',
name: 'Wave', name: 'Wave',
options: { props: {
duration: {type: 'number', default: 1000}, duration: {type: 'number', default: 1000},
name: {type: 'string', default: 'hello'}, name: {type: 'string', default: 'hello'},
color: {type: 'color', default: '#123456'}, color: {type: 'color', default: '#123456'},
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
"operator": "卞龙亭", "operator": "卞龙亭",
"create_time": "2019-09-19T06:56:01.000Z", "create_time": "2019-09-19T06:56:01.000Z",
"update_time": "2019-09-19T06:56:01.000Z", "update_time": "2019-09-19T06:56:01.000Z",
"data": "{\"views\":[{\"name\":\"view1\",\"type\":\"node\",\"properties\":{},\"uuid\":\"3a357816-5581-41ba-aa6f-4a6cc40ae396\",\"children\":[{\"name\":\"rect\",\"type\":\"rect\",\"properties\":{\"width\":50,\"height\":50,\"fillColor\":\"rgba(105, 182, 255, 1)\",\"strokeWidth\":0,\"x\":10,\"y\":10},\"events\":{\"click\":{\"once\":false,\"behaviors\":[{\"uuid\":\"aa1\",\"alias\":\"主过程\",\"meta\":\"main\"}]}},\"scripts\":[{\"script\":\"wave\",\"options\":{\"duration\":500,\"autoPlay\":true,\"type\":\"cubicIn\"}}],\"uuid\":\"f97bbf76-6923-4669-b5a3-e6382753e49a\"}]}],\"assets\":[],\"dataMapping\":[],\"processMap\":{\"main\":{\"id\":\"main\",\"name\":\"Main\",\"options\":{},\"subEntry\":\"1\",\"sub\":{\"a1\":{\"uuid\":\"a1\",\"alias\":\"入口\",\"meta\":\"entry\",\"output\":{\"success\":[\"a2\"]},\"design\":{\"x\":10,\"y\":10}},\"a2\":{\"uuid\":\"a2\",\"alias\":\"test\",\"meta\":\"test\",\"options\":{\"text\":\"hello\"},\"output\":{\"success\":[],\"failed\":[]},\"design\":{\"x\":20,\"y\":100}}}},\"test\":{\"id\":\"test\",\"name\":\"Test\",\"options\":{\"text\":{\"type\":\"string\",\"default\":\"\"}},\"output\":[\"success\",\"failed\"]}}}" "data": "{\"views\":[{\"name\":\"view1\",\"type\":\"node\",\"properties\":{},\"uuid\":\"3a357816-5581-41ba-aa6f-4a6cc40ae396\",\"children\":[{\"name\":\"rect\",\"type\":\"rect\",\"properties\":{\"width\":50,\"height\":50,\"fillColor\":\"rgba(105, 182, 255, 1)\",\"strokeWidth\":0,\"x\":10,\"y\":10},\"events\":{\"click\":{\"once\":false,\"behaviors\":[{\"uuid\":\"aa1\",\"alias\":\"主过程\",\"meta\":\"main\"}]}},\"scripts\":[{\"script\":\"wave\",\"props\":{\"duration\":500,\"autoPlay\":true,\"type\":\"cubicIn\"}}],\"uuid\":\"f97bbf76-6923-4669-b5a3-e6382753e49a\"}]}],\"assets\":[],\"dataMapping\":[],\"processMap\":{\"main\":{\"id\":\"main\",\"name\":\"Main\",\"props\":{},\"subEntry\":\"1\",\"sub\":{\"a1\":{\"uuid\":\"a1\",\"alias\":\"入口\",\"meta\":\"entry\",\"output\":{\"success\":[\"a2\"]},\"design\":{\"x\":10,\"y\":10}},\"a2\":{\"uuid\":\"a2\",\"alias\":\"test\",\"meta\":\"test\",\"props\":{\"text\":\"hello\"},\"output\":{\"success\":[],\"failed\":[]},\"design\":{\"x\":20,\"y\":100}}}},\"test\":{\"id\":\"test\",\"name\":\"Test\",\"props\":{\"text\":{\"type\":\"string\",\"default\":\"\"}},\"output\":[\"success\",\"failed\"]}}}"
} }
} }
\ No newline at end of file
...@@ -8,7 +8,8 @@ const data = { ...@@ -8,7 +8,8 @@ const data = {
"type": "node", "type": "node",
"properties": {}, "properties": {},
"uuid": "3a357816-5581-41ba-aa6f-4a6cc40ae396", "uuid": "3a357816-5581-41ba-aa6f-4a6cc40ae396",
"children": [{ "children": [
{
"name": "rect", "name": "rect",
"type": "rect", "type": "rect",
"properties": { "properties": {
...@@ -35,14 +36,15 @@ const data = { ...@@ -35,14 +36,15 @@ const data = {
scripts: [ scripts: [
{ {
script: 'wave', script: 'wave',
options: { props: {
duration: 500, duration: 500,
autoPlay: true, autoPlay: true,
type: 'cubicIn', type: 'cubicIn',
} }
} }
], ],
}] },
]
}], }],
"assets": [ "assets": [
{ {
...@@ -206,7 +208,7 @@ const data = { ...@@ -206,7 +208,7 @@ const data = {
{ {
id: 'main', id: 'main',
name: 'Main', name: 'Main',
options: {}, props: {},
subEntry: 'a1', subEntry: 'a1',
sub: { sub: {
a1: { a1: {
...@@ -225,8 +227,8 @@ const data = { ...@@ -225,8 +227,8 @@ const data = {
uuid: 'a2', uuid: 'a2',
alias: 'test', alias: 'test',
meta: 'test', meta: 'test',
options: { props: {
text: 'hello', text: '$_linked_$',
}, },
output: { output: {
success: [], success: [],
...@@ -242,13 +244,15 @@ const data = { ...@@ -242,13 +244,15 @@ const data = {
{ {
id: 'test', id: 'test',
name: 'Test', name: 'Test',
options: { desc: '测试过程',
props: {
text: {alias: '文本', type: 'string', default: '你好'}, text: {alias: '文本', type: 'string', default: '你好'},
num: {alias: '数字', type: 'number', default: 1}, num: {alias: '数字', type: 'number', default: 1},
type: {alias: '类型', type: 'enum', enum: ['rotate', 'jump', 'breath'], default: 'rotate'}, type: {alias: '类型', type: 'enum', enum: ['rotate', 'jump', 'breath'], default: 'rotate'},
autoPlay: {alias: '自动播放', type: 'boolean', default: false}, autoPlay: {alias: '自动播放', type: 'boolean', default: false},
color: {alias: '颜色', type: 'color', default: '#123456'}, color: {alias: '颜色', type: 'color', default: '#123456'},
asset: {alias: '素材', type: 'asset',}, asset: {alias: '素材', type: 'asset',},
node: {alias: '节点', type: 'node',},
}, },
output: ['success', 'failed'], output: ['success', 'failed'],
script: "console.log('test');", script: "console.log('test');",
......
<template> <template>
<el-select v-model="selected" :filterable="filterable" allow-create placeholder="请选择"> <el-select v-model="selected" :filterable="filterable" allow-create placeholder="请选择">
<el-option <el-option
v-for="item in options" v-for="item in props"
:style="`${optionStyle}${item.value}`" :style="`${optionStyle}${item.value}`"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
...@@ -36,7 +36,7 @@ export default { ...@@ -36,7 +36,7 @@ export default {
}; };
}, },
computed: { computed: {
options() { props() {
return this.optionList || this.optionMapper[this.optionType]; return this.optionList || this.optionMapper[this.optionType];
}, },
optionStyle() { optionStyle() {
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
"Upload": "Upload", "Upload": "Upload",
"Edit": "Edit", "Edit": "Edit",
"Name": "Name", "Name": "Name",
"Desc": "Desc",
"Event": "Event",
"No desc": "No desc",
"Description": "Description",
"Failed to fetch": "Network error!", "Failed to fetch": "Network error!",
"In processing": "In processing", "In processing": "In processing",
"Projects": "Projects", "Projects": "Projects",
...@@ -30,8 +34,11 @@ ...@@ -30,8 +34,11 @@
"Saving": "Saving…", "Saving": "Saving…",
"Create project": "Create project", "Create project": "Create project",
"Rename project": "Rename project", "Rename project": "Rename project",
"Options Editor": "Options Editor", "Props Editor": "Props Editor",
"Edit Behavior": "Edit Behavior",
"Trigger once": "Trigger once",
"Meta Editor": "Meta Editor", "Meta Editor": "Meta Editor",
"Link to parent": "Link to parent",
"Input project name": "Input project name", "Input project name": "Input project name",
"Invalid project name": "Invalid project name", "Invalid project name": "Invalid project name",
"Creating project": "Creating project…", "Creating project": "Creating project…",
...@@ -68,6 +75,8 @@ ...@@ -68,6 +75,8 @@
"Meta is in use, can not delete": "Meta is in use, can not delete!", "Meta is in use, can not delete": "Meta is in use, can not delete!",
"Are you sure to delete this meta": "Are you sure to delete this meta?", "Are you sure to delete this meta": "Are you sure to delete this meta?",
"This Meta ID is in use, can not save": "This Meta ID is in use, can not save!", "This Meta ID is in use, can not save": "This Meta ID is in use, can not save!",
"Custom node desc": "Custom node",
"Divider node desc": "Divider node, exit will be executed in sequence",
"menu": { "menu": {
"save": "Save", "save": "Save",
"details": "Details", "details": "Details",
......
...@@ -3,6 +3,7 @@ import App from './App.vue' ...@@ -3,6 +3,7 @@ import App from './App.vue'
import router from './router' import router from './router'
import store from './store/index' import store from './store/index'
import i18n from './i18n' import i18n from './i18n'
import './vue-resize'
Vue.config.productionTip = false; Vue.config.productionTip = false;
...@@ -16,5 +17,3 @@ new Vue({ ...@@ -16,5 +17,3 @@ new Vue({
i18n, i18n,
render: h => h(App) render: h => h(App)
}).$mount('#app'); }).$mount('#app');
//todo 节点选择器
\ No newline at end of file
...@@ -14,19 +14,21 @@ export const behaviorStore = { ...@@ -14,19 +14,21 @@ export const behaviorStore = {
currentBehavior: null, currentBehavior: null,
processContext: [], processContext: [],
originData: null, originData: null,
originBehaviors: null,
behaviors: null, behaviors: null,
}, },
mutations: { mutations: {
behavior_startEdit(state, {originData, behaviors, event}) { behavior_startEdit(state, {originData, behaviors, event}) {
state.originData = originData; state.originData = originData;
state.behaviors = behaviors; state.originBehaviors = behaviors;
state.behaviors = JSON.parse(JSON.stringify(behaviors));
state.data = JSON.parse(JSON.stringify(originData)); state.data = JSON.parse(JSON.stringify(originData));
if (behaviors.length > 0) { if (state.behaviors.length > 0) {
state.currentBehavior = behaviors[0]; state.currentBehavior = state.behaviors[0];
} else { } else {
let metaUUID = generateUUID(); let metaUUID = generateUUID();
state.currentBehavior = behaviors[0] = { state.currentBehavior = state.behaviors[0] = {
uuid: generateUUID(), uuid: generateUUID(),
alias: event, alias: event,
meta: metaUUID, meta: metaUUID,
...@@ -34,16 +36,20 @@ export const behaviorStore = { ...@@ -34,16 +36,20 @@ export const behaviorStore = {
let subEntryUUID = generateUUID(); let subEntryUUID = generateUUID();
state.data.processes.push({ state.data.processes.push({
id: metaUUID, id: metaUUID,
name: 'event', name: event,
options: {}, props: {},
subEntry: subEntryUUID, subEntry: subEntryUUID,
sub: { sub: {
[subEntryUUID]: { [subEntryUUID]: {
uuid: subEntryUUID, uuid: subEntryUUID,
alias: 'Entry', alias: 'Entry',
meta: 'entry', meta: 'entry',
}, design: {
x: 10,
y: 10,
} }
},
},
}); });
} }
}, },
...@@ -53,7 +59,10 @@ export const behaviorStore = { ...@@ -53,7 +59,10 @@ export const behaviorStore = {
}, },
behavior_save(state) { behavior_save(state) {
state.originData.processes = state.data.processes; state.originData.processes = state.data.processes;
state.behaviors[0] = state.currentBehavior; state.originBehaviors[0] = state.currentBehavior;
},
behavior_cancel(state) {
}, },
updateProcesses(state, {targetMetaID, replaceMetaID}) { updateProcesses(state, {targetMetaID, replaceMetaID}) {
for (let process of state.data.processes) { for (let process of state.data.processes) {
...@@ -102,6 +111,9 @@ export const behaviorStore = { ...@@ -102,6 +111,9 @@ export const behaviorStore = {
behavior_getAssetByUUID: state => uuid => { behavior_getAssetByUUID: state => uuid => {
return state.data.assets.find(item => item.uuid === uuid); return state.data.assets.find(item => item.uuid === uuid);
}, },
behavior_views: state=>{
return state.data.views;
}
}, },
actions: { actions: {
addCustomProcessMeta({commit, state}) { addCustomProcessMeta({commit, state}) {
...@@ -109,7 +121,7 @@ export const behaviorStore = { ...@@ -109,7 +121,7 @@ export const behaviorStore = {
id: generateUUID(), id: generateUUID(),
name: 'Custom', name: 'Custom',
script: '', script: '',
options: {}, props: {},
output: ['success', 'failed'], output: ['success', 'failed'],
}; };
commit('addProcessMeta', meta); commit('addProcessMeta', meta);
...@@ -118,8 +130,8 @@ export const behaviorStore = { ...@@ -118,8 +130,8 @@ export const behaviorStore = {
addDividerProcessMeta({commit, state}) { addDividerProcessMeta({commit, state}) {
let meta = { let meta = {
id: generateUUID(), id: generateUUID(),
isDivider: true,
name: 'Divider', name: 'Divider',
isDivider: true,
output: ['p0'], output: ['p0'],
}; };
commit('addProcessMeta', meta); commit('addProcessMeta', meta);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
import {envApi} from "../../api"; import {envApi} from "../../api";
import i18n from "../../i18n";
export const envStore = { export const envStore = {
state: { state: {
...@@ -34,11 +35,13 @@ export const envStore = { ...@@ -34,11 +35,13 @@ export const envStore = {
const dividerProcess = { const dividerProcess = {
id: 'divider', id: 'divider',
name: 'Divider', name: 'Divider',
desc: i18n.t('Divider node desc'),//'分流节点,出口会按顺序一次执行',
}; };
tree.unshift(dividerProcess); tree.unshift(dividerProcess);
const customProcess = { const customProcess = {
id: 'custom', id: 'custom',
name: 'Custom', name: 'Custom',
desc: i18n.t('Custom node desc'),//'自定义节点',
}; };
tree.unshift(customProcess); tree.unshift(customProcess);
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* Created by rockyl on 2019-09-25. * Created by rockyl on 2019-09-25.
*/ */
export default function (options = {}) { export default function (props = {}) {
const {mutationTypes = []} = options; const {mutationTypes = []} = props;
return (store) => { return (store) => {
store.subscribe((mutation, state) => { store.subscribe((mutation, state) => {
if (mutationTypes.includes(mutation.type)) { if (mutationTypes.includes(mutation.type)) {
......
...@@ -161,6 +161,11 @@ $dock-pin-width: 9px; ...@@ -161,6 +161,11 @@ $dock-pin-width: 9px;
float: right; float: right;
border: 1px solid $--border-color-base; border: 1px solid $--border-color-base;
} }
.linked-icon {
float: right;
color: $--color-success;
}
} }
} }
...@@ -224,6 +229,18 @@ $dock-pin-width: 9px; ...@@ -224,6 +229,18 @@ $dock-pin-width: 9px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.linked{
display: block;
height: 26px;
overflow: hidden;
border: 1px solid $--border-color-base;
border-radius: 4px;
background-color: $--background-color-base;
flex: 1;
padding: 0 5px;
color: $--color-text-secondary;
}
.el-input-group__prepend { .el-input-group__prepend {
padding: 0 5px; padding: 0 5px;
} }
...@@ -243,17 +260,36 @@ $dock-pin-width: 9px; ...@@ -243,17 +260,36 @@ $dock-pin-width: 9px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.name-input{
}
.scrollbar { .scrollbar {
margin-right: -5px;
padding-top: 5px; padding-top: 5px;
flex: 1; flex: 1;
.scrollbar-view{
padding-right: 10px;
}
.el-form-item__content { .el-form-item__content {
display: flex; display: flex;
justify-content: flex-end;
.el-input-number--mini { .el-input-number--mini {
flex: 1; flex: 1;
} }
} }
.node-select-container{
flex: 1;
}
.string-editor-container{
flex: 1;
height: 28px;
}
} }
} }
} }
...@@ -275,7 +311,7 @@ $dock-pin-width: 9px; ...@@ -275,7 +311,7 @@ $dock-pin-width: 9px;
} }
} }
.options-editor-dialog { .props-editor-dialog {
.scrollbar { .scrollbar {
width: 100%; width: 100%;
height: 40vh; height: 40vh;
...@@ -309,3 +345,18 @@ $dock-pin-width: 9px; ...@@ -309,3 +345,18 @@ $dock-pin-width: 9px;
width: 400px; width: 400px;
} }
} }
.node-select-popover{
.tree-scrollbar {
width: 100%;
height: 200px;
}
.bottom-bar{
margin-top: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
...@@ -20,6 +20,8 @@ export const RENDERER_TYPES= { ...@@ -20,6 +20,8 @@ export const RENDERER_TYPES= {
CANVAS: 'canvas', CANVAS: 'canvas',
}; };
export const linkedFlag = '$_linked_$';
export function messageError(e) { export function messageError(e) {
Message({ Message({
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
......
...@@ -111,7 +111,7 @@ export default { ...@@ -111,7 +111,7 @@ export default {
textAlign: { textAlign: {
title: '文本对齐', title: '文本对齐',
type: 'select', type: 'select',
options: [ props: [
{ label: '靠左', value: 'left' }, { label: '靠左', value: 'left' },
{ label: '居中', value: 'center' }, { label: '居中', value: 'center' },
{ label: '靠右', value: 'right' } { label: '靠右', value: 'right' }
...@@ -121,7 +121,7 @@ export default { ...@@ -121,7 +121,7 @@ export default {
/*verticalAlign: { /*verticalAlign: {
title: '纵向对齐', title: '纵向对齐',
type: 'select', type: 'select',
options: [ props: [
{ label: '靠上', value: 'up' }, { label: '靠上', value: 'up' },
{ label: '居中', value: 'middle' }, { label: '居中', value: 'middle' },
{ label: '靠下', value: 'down' } { label: '靠下', value: 'down' }
......
<template> <template>
<div class="zero-inspector-behavior-form" v-if="activeComponent.uuid"> <div class="zero-inspector-behavior-form" v-if="activeComponent.uuid">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"> <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-form ref="form" size="mini" label-width="80px"> <el-form ref="form" size="mini" label-width="60px">
<div v-for="(evn, key) in eventsObj" :key="key"> <div v-for="(evn, key) in eventsObj" :key="key">
<el-form-item label="触发事件:"> <el-form-item :label="$t('Event') + ':'">
<div>{{key}}</div> <div>{{key}}</div>
<div > <div >
<el-tooltip content="是否单次触发" placement="top"> <el-tooltip :content="$t('Trigger once')" placement="top">
<el-switch v-model="evn.once" @change="v => handleOnceChange(key, v)"></el-switch> <el-switch v-model="evn.once" @change="v => handleOnceChange(key, v)"></el-switch>
</el-tooltip> </el-tooltip>
<el-tooltip content="行为编辑" placement="top" style="margin-left: 20px;"> <el-button size="mini" @click="showBehaviorEditor(evn, key)" style="margin-left: 20px;">
<el-button size="mini" @click="showBehaviorEditor(evn, key)"> {{$t('Edit Behavior')}}
行为编辑
<i v-if="evn.behaviors && evn.behaviors.length" class="el-icon-check el-icon--right"></i> <i v-if="evn.behaviors && evn.behaviors.length" class="el-icon-check el-icon--right"></i>
</el-button> </el-button>
</el-tooltip>
</div> </div>
</el-form-item> </el-form-item>
</div> </div>
......
<template> <template>
<div class="behavior"> <div class="behavior">
<split-panes> <split-panes>
<split-panes splitpanes-min="20" :splitpanes-size="20" horizontal> <split-panes splitpanes-min="10" :splitpanes-size="10" horizontal>
<process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="prefabProcessTree" <process-list @edit-meta="onEditMeta" @delete-meta="onDeleteMeta" :data="prefabProcessTree"
class="background full-size" splitpanes-min="20" class="background full-size" splitpanes-min="20"
:splitpanes-size="30"/> :splitpanes-size="30"/>
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
class="background full-size" splitpanes-min="20" class="background full-size" splitpanes-min="20"
:splitpanes-size="70"/> :splitpanes-size="70"/>
</split-panes> </split-panes>
<div class="center full-size background" splitpanes-min="20" :splitpanes-size="60"> <div class="center full-size background" splitpanes-min="20" :splitpanes-size="70">
<edit-path :processStack="processStack" @pop="onPop"/> <edit-path :processStack="processStack" @pop="onPop"/>
<board ref="board" @select-process-node="onSelectProcessNode" @edit-process="editProcess"/> <board ref="board" @select-process-node="onSelectProcessNode" @edit-process="editProcess"/>
</div> </div>
......
<template> <template>
<div class="board" @dragover="onDragOver" @drop="onDrop"> <div class="board" @dragover="onDragOver" @drop="onDrop" v-resize="onResize">
<svg class="svg-board full-size" version="1.1" xmlns="http://www.w3.org/2000/svg" <svg class="svg-board full-size" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="layer" stroke-width="2" fill="none" fill-rule="evenodd"> <g id="layer" stroke-width="2" fill="none" fill-rule="evenodd">
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
import {state} from "./Board/state"; import {state} from "./Board/state";
import events from "../../../global-events"; import events from "../../../global-events";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
//todo 缩放功能
export default { export default {
name: "Board", name: "Board",
components: {ToolTip, LinkLine, ProcessNode,}, components: {ToolTip, LinkLine, ProcessNode,},
...@@ -139,10 +139,13 @@ ...@@ -139,10 +139,13 @@
events.$emit('update-dock-pin-pos'); events.$emit('update-dock-pin-pos');
}); });
}, },
measure() { onResize(){
const {x, y} = this.$el.getBoundingClientRect(); const {x, y} = this.$el.getBoundingClientRect();
state.boardOffset.x = x; state.boardOffset.x = x;
state.boardOffset.y = y; state.boardOffset.y = y;
},
measure() {
this.onResize();
this.$nextTick(() => { this.$nextTick(() => {
events.$emit('update-dock-pin-pos'); events.$emit('update-dock-pin-pos');
......
...@@ -12,12 +12,17 @@ ...@@ -12,12 +12,17 @@
<el-button size="mini" icon="el-icon-plus" circle @click="outputPointModify('add')"></el-button> <el-button size="mini" icon="el-icon-plus" circle @click="outputPointModify('add')"></el-button>
<el-button size="mini" icon="el-icon-minus" circle @click="outputPointModify('remove')"></el-button> <el-button size="mini" icon="el-icon-minus" circle @click="outputPointModify('remove')"></el-button>
</div> </div>
<div v-else class="field-item" v-for="(param, key, index) in meta.options" :key="index"> <div v-else class="field-item" v-for="(param, key, index) in meta.props" :key="index">
<span class="key">{{param.alias || key}}</span>: <span class="key">{{param.alias || key}}</span>:
<span class="" v-if="data.props[key] === linkedFlag">
<i class="el-icon-link linked-icon"></i>
</span>
<template v-else>
<div v-if="param.type === 'color'"> <div v-if="param.type === 'color'">
<div class="color-value" :style="{'background-color': valueToString(param, data, key)}"></div> <div class="color-value" :style="{'background-color': valueToString(param, data, key)}"></div>
</div> </div>
<span v-else class="string-value">{{valueToString(param, data, key)}}</span> <span v-else class="string-value">{{valueToString(param, data, key)}}</span>
</template>
</div> </div>
</div> </div>
<div ref="inputDock" class="dock input"> <div ref="inputDock" class="dock input">
...@@ -38,6 +43,7 @@ ...@@ -38,6 +43,7 @@
import DockPin from "./DockPin"; import DockPin from "./DockPin";
import {state} from "./state"; import {state} from "./state";
import events from "../../../../global-events"; import events from "../../../../global-events";
import {linkedFlag} from "../../../../utils";
export default { export default {
name: "ProcessNode", name: "ProcessNode",
...@@ -51,6 +57,7 @@ ...@@ -51,6 +57,7 @@
height: 100, height: 100,
inputMeta, inputMeta,
active: false, active: false,
linkedFlag,
} }
}, },
mounted() { mounted() {
...@@ -79,18 +86,18 @@ ...@@ -79,18 +86,18 @@
methods: { methods: {
valueToString(param, data, key) { valueToString(param, data, key) {
if (param.type === 'asset') { if (param.type === 'asset') {
if (data.options.hasOwnProperty(key)) { if (data.props.hasOwnProperty(key)) {
let asset = this.$store.getters.behavior_getAssetByUUID(data.options[key]); let asset = this.$store.getters.behavior_getAssetByUUID(data.props[key]);
return asset.name; return asset.name;
} }
} else { } else {
return data.options[key] || param.default; return data.props[key] || param.default;
} }
return ''; return '';
}, },
prepare() { prepare() {
let {design, options, output} = this.process.data; let {design, props, output} = this.process.data;
if (!design) { if (!design) {
this.$set(this.process.data, 'design', {}); this.$set(this.process.data, 'design', {});
design = this.process.data.design; design = this.process.data.design;
...@@ -101,8 +108,8 @@ ...@@ -101,8 +108,8 @@
if (!design.y) { if (!design.y) {
this.$set(design, 'y', 0); this.$set(design, 'y', 0);
} }
if (!options) { if (!props) {
this.$set(this.process.data, 'options', {}); this.$set(this.process.data, 'props', {});
} }
if (!output) { if (!output) {
this.$set(this.process.data, 'output', {}); this.$set(this.process.data, 'output', {});
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
:close-on-click-modal="false" :close-on-click-modal="false"
:append-to-body="true"> :append-to-body="true">
<div class="meta-editor-wrapper"> <div class="meta-editor-wrapper">
<el-form :inline="true" class="info-editor" size="mini"> <el-form class="info-editor" size="mini" label-position="right" label-width="70px">
<template v-if="meta"> <template v-if="meta">
<el-form-item label="ID"> <el-form-item label="ID">
<el-input v-model="meta.id" placeholder="ID" :readonly="!editable"/> <el-input v-model="meta.id" placeholder="ID" :readonly="!editable"/>
...@@ -12,13 +12,15 @@ ...@@ -12,13 +12,15 @@
<el-input v-model="meta.name" placeholder="Name" :readonly="!editable"/> <el-input v-model="meta.name" placeholder="Name" :readonly="!editable"/>
</el-form-item> </el-form-item>
</template> </template>
</el-form>
<el-form class="info-editor" size="mini">
<template v-if="meta"> <template v-if="meta">
<el-form-item label="Options"> <el-form-item label="Desc">
<el-link :underline="false" @click="onClickEditOptions" :disabled="!editable"> <el-input v-model="meta.desc" placeholder="Description" :readonly="!editable"/>
<template v-if="Object.keys(meta.options).length"> </el-form-item>
<el-tag type="success" size="mini" v-for="(option, key) in meta.options" :key="key">{{key}}</el-tag> <el-form-item label="Props">
<el-link :underline="false" @click="onClickEditProps" :disabled="!editable">
<template v-if="Object.keys(meta.props).length">
<el-tag type="success" size="mini" v-for="(option, key) in meta.props" :key="key">{{key}}</el-tag>
</template> </template>
<template v-else>Nothing</template> <template v-else>Nothing</template>
</el-link> </el-link>
...@@ -40,30 +42,30 @@ ...@@ -40,30 +42,30 @@
<el-button size="mini" plain @click="save">Save</el-button> <el-button size="mini" plain @click="save">Save</el-button>
</div> </div>
</div> </div>
<options-editor-dialog ref="optionsEditorDialog"/> <props-editor-dialog ref="propsEditorDialog"/>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import ElFormItem from "./editors/form-item"; import ElFormItem from "./editors/form-item";
import OptionsEditorDialog from "./OptionsEditorDialog"; import PropsEditorDialog from "./PropsEditorDialog";
export default { export default {
name: "MetaEditorDialog", name: "MetaEditorDialog",
components: {OptionsEditorDialog, ElFormItem}, components: {PropsEditorDialog, ElFormItem},
data() { data() {
return { return {
visible: false, visible: false,
meta: null, meta: null,
optionsEditorVisible: false, propsEditorVisible: false,
} }
}, },
computed: { computed: {
editable() { editable() {
return this.meta && this.meta.type !== 'builtin'; return this.meta && this.meta.type !== 'builtin';
}, },
options() { props() {
return Object.keys(this.meta.options).join(',') return Object.keys(this.meta.props).join(',')
}, },
}, },
methods: { methods: {
...@@ -72,8 +74,8 @@ ...@@ -72,8 +74,8 @@
this.meta = JSON.parse(JSON.stringify(meta)); this.meta = JSON.parse(JSON.stringify(meta));
this.oldMetaID = this.meta.id; this.oldMetaID = this.meta.id;
}, },
onClickEditOptions() { onClickEditProps() {
this.$refs.optionsEditorDialog.edit(this.meta.options); this.$refs.propsEditorDialog.edit(this.meta.props);
}, },
save() { save() {
if (this.oldMetaID !== this.meta.id && this.$store.getters.metaIDExists(this.meta.id)) { if (this.oldMetaID !== this.meta.id && this.$store.getters.metaIDExists(this.meta.id)) {
......
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
<span :draggable="draggable(data)" @dragstart.stop="dragProcessStart(data, $event)">{{data.name}}</span> <span :draggable="draggable(data)" @dragstart.stop="dragProcessStart(data, $event)">{{data.name}}</span>
</div> </div>
<el-dropdown v-if="metaEditable(data)" class="more-button" size="mini" trigger="click" <el-dropdown v-if="nodeMenu(data)" class="more-button" size="mini" trigger="click"
@command="(command)=>{onMoreMenu(command, data, node)}"> @command="(command)=>{onMoreMenu(command, data, node)}">
<el-link icon="el-icon-more" :underline="false" @click.stop/> <el-link icon="el-icon-more" :underline="false" @click.stop/>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">{{$t('Edit')}}</el-dropdown-item> <el-dropdown-item command="desc" >{{$t('Desc')}}</el-dropdown-item>
<el-dropdown-item command="delete">{{$t('Delete')}}</el-dropdown-item> <el-dropdown-item command="edit" v-if="metaEditable(data)" divided>{{$t('Edit')}}</el-dropdown-item>
<el-dropdown-item command="delete" v-if="metaEditable(data)">{{$t('Delete')}}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
...@@ -70,11 +71,22 @@ ...@@ -70,11 +71,22 @@
dragProcessStart(data, event) { dragProcessStart(data, event) {
event.dataTransfer.setData('process', data.id); event.dataTransfer.setData('process', data.id);
}, },
nodeMenu(data){
return !data.hasOwnProperty('children')
},
metaEditable(data){ metaEditable(data){
return data.type !== 'builtin' && !data.hasOwnProperty('children') && !editableIds.includes(data.id) && data.isDivider !== true return data.type !== 'builtin' && !data.hasOwnProperty('children') && !editableIds.includes(data.id) && data.isDivider !== true
}, },
onMoreMenu(command, data, node) { onMoreMenu(command, data, node) {
switch (command) { switch (command) {
case 'desc':
this.$alert(data.desc || this.$t('No desc'), data.name + ' ' + this.$t('Description'), {
confirmButtonText: this.$t('Confirm'),
callback: action => {
}
});
break;
case 'edit': case 'edit':
this.$emit('edit-meta', data); this.$emit('edit-meta', data);
break; break;
......
<template> <template>
<div class="wrapper" v-if="process"> <div class="wrapper" v-if="process">
<el-input v-model="process.data.alias" clearable :placeholder="process.meta.name" size="mini"> <el-input class="name-input" v-model="process.data.alias" clearable :placeholder="process.meta.name" size="mini">
<template slot="prepend">{{$t('Name')}}</template> <template slot="prepend">{{$t('Name')}}</template>
</el-input> </el-input>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"
view-class="scrollbar-view"> view-class="scrollbar-view">
<el-form v-model="process" size="mini" label-width="80px" label-position="left" @submit.prevent> <el-form v-model="process" size="mini" label-width="80px" label-position="left" @submit.prevent>
<component v-for="(property, key) in process.meta.options" <component v-for="(property, key) in process.meta.props"
:is="getEditor(property)" :is="getEditor(property)"
v-model="process.data.options[key]" v-model="process.data.props[key]"
:propertyName="key" :propertyName="key"
:property="property" :property="property"
:container="process" :container="process"
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
import BooleanEditor from "./editors/BooleanEditor"; import BooleanEditor from "./editors/BooleanEditor";
import ColorEditor from "./editors/ColorEditor"; import ColorEditor from "./editors/ColorEditor";
import AssetEditor from "./editors/AssetEditor"; import AssetEditor from "./editors/AssetEditor";
import NodeSelectEditor from "./editors/NodeSelectEditor";
const editorMapping = { const editorMapping = {
number: 'NumberEditor', number: 'NumberEditor',
...@@ -34,11 +35,12 @@ ...@@ -34,11 +35,12 @@
boolean: 'BooleanEditor', boolean: 'BooleanEditor',
color: 'ColorEditor', color: 'ColorEditor',
asset: 'AssetEditor', asset: 'AssetEditor',
node: 'NodeSelectEditor',
}; };
export default { export default {
name: "PropertiesEditor", name: "PropertiesEditor",
components: {AssetEditor, ColorEditor, BooleanEditor, EnumEditor, NumberEditor, StringEditor}, components: {NodeSelectEditor, AssetEditor, ColorEditor, BooleanEditor, EnumEditor, NumberEditor, StringEditor},
data() { data() {
return { return {
process: null, process: null,
......
<template> <template>
<el-dialog :title="$t('Options Editor')" width="80%" :visible.sync="visible" <el-dialog :title="$t('Props Editor')" width="80%" :visible.sync="visible"
:close-on-click-modal="false" :close-on-click-modal="false"
:append-to-body="true"> :append-to-body="true">
<div class="options-editor-dialog"> <div class="props-editor-dialog">
<el-button class="add-button" size="mini" circle icon="el-icon-plus" plain @click="addItem"/> <el-button class="add-button" size="mini" circle icon="el-icon-plus" plain @click="addItem"/>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" v-if="options" <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" v-if="props"
view-class="scrollbar-view"> view-class="scrollbar-view">
<div class="wrapper"> <div class="wrapper">
<el-table <el-table
:data="options" :data="props"
style="width: 100%"> style="width: 100%">
<el-table-column <el-table-column
label="Type" label="Type"
...@@ -81,13 +81,13 @@ ...@@ -81,13 +81,13 @@
<script> <script>
export default { export default {
name: "OptionsEditorDialog", name: "PropsEditorDialog",
data() { data() {
return { return {
visible: false, visible: false,
originOptions: null, originProps: null,
copiedOptions: null, copiedProps: null,
options: [], props: [],
types: [ types: [
'boolean', 'boolean',
'string', 'string',
...@@ -95,32 +95,33 @@ ...@@ -95,32 +95,33 @@
'enum', 'enum',
'color', 'color',
'asset', 'asset',
'node',
], ],
} }
}, },
methods: { methods: {
edit(options) { edit(props) {
this.visible = true; this.visible = true;
this.originOptions = options; this.originProps = props;
this.copiedOptions = JSON.parse(JSON.stringify(options)); this.copiedProps = JSON.parse(JSON.stringify(props));
this.options.splice(0); this.props.splice(0);
for (let key in this.copiedOptions) { for (let key in this.copiedProps) {
let option = this.copiedOptions[key]; let option = this.copiedProps[key];
this.options.push({ this.props.push({
key, key,
option, option,
}) })
} }
}, },
save(){ save(){
let keys = Object.keys(this.originOptions); let keys = Object.keys(this.originProps);
for (let key of keys) { for (let key of keys) {
this.$delete(this.originOptions, key); this.$delete(this.originProps, key);
} }
for(let item of this.options){ for(let item of this.props){
if(item.key){ if(item.key){
this.$set(this.originOptions, item.key, item.option); this.$set(this.originProps, item.key, item.option);
} }
} }
...@@ -133,14 +134,14 @@ ...@@ -133,14 +134,14 @@
}, },
addItem(){ addItem(){
this.options.push({ this.props.push({
option: { option: {
type: 'string', type: 'string',
} }
}) })
}, },
deleteItem(index){ deleteItem(index){
this.options.splice(index, 1); this.props.splice(index, 1);
}, },
}, },
} }
......
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-select :value="editValue" @input="onInput" :placeholder="property.default" class="el-select"> <el-select :value="editValue" @input="onInput" :placeholder="property.default" class="el-select">
<el-option <el-option
v-for="(item, key) in assets" v-for="(item, key) in assets"
......
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-switch :value="editValue" @input="onInput" <el-switch :value="editValue" @input="onInput"
class="picker"></el-switch> class="picker"></el-switch>
</editor-wrapper> </editor-wrapper>
......
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName" class="color-editor-container"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName" class="color-editor-container">
<el-color-picker <el-color-picker
class="picker" class="picker"
:value="editValue" :value="editValue"
......
<template> <template>
<el-form-item class="editor-wrapper" :label="property.alias || propertyName" content-float="right" :content-width="contentWidth" :labelOffsetTop="labelOffsetTop"> <el-form-item class="editor-wrapper" :label="property.alias || propertyName" content-float="right"
:content-width="contentWidth" :labelOffsetTop="labelOffsetTop">
<template v-if="linked">
<span class="linked">Linked to parent</span>
</template>
<template v-else>
<slot></slot> <slot></slot>
</template>
<el-popover
trigger="click"
>
<div>
<span>{{$t('Link to parent')}}: </span>
<el-switch :value="linked" @input="onChange"/>
</div>
<el-link style="padding: 3px;" slot="reference" icon="el-icon-link" :underline="false"
:type="linked ? 'success' : 'default'"/>
</el-popover>
</el-form-item> </el-form-item>
</template> </template>
<script> <script>
import camelcase from 'camelcase' import camelcase from 'camelcase'
import ElFormItem from "./form-item"; import ElFormItem from "./form-item";
import {linkedFlag} from "../../../../utils";
export default { export default {
name: "EditorWrapper", name: "EditorWrapper",
components: {ElFormItem}, components: {ElFormItem},
props: { props: {
property: Object, property: Object,
value: {},
container: {},
propertyName: String, propertyName: String,
contentWidth: { contentWidth: {
type: String, type: String,
...@@ -24,8 +43,19 @@ ...@@ -24,8 +43,19 @@
}, },
}, },
computed: { computed: {
linked() {
return this.value === linkedFlag
}
}, },
methods: {
onChange(v) {
if (v) {
this.$set(this.container.data.props, this.propertyName, linkedFlag);
} else {
this.$delete(this.container.data.props, this.propertyName);
}
}
}
} }
</script> </script>
......
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-select :value="editValue" @input="onInput" :placeholder="property.default" class="el-select"> <el-select :value="editValue" @input="onInput" :placeholder="property.default" class="el-select">
<el-option <el-option
v-for="(item, key) in property.enum" v-for="(item, key) in property.enum"
......
<template>
<editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
placement="top"
popper-class="node-select-popover"
class="node-select-container"
trigger="manual"
width="400"
v-model="popoverVisible"
>
<div>
<el-scrollbar class="tree-scrollbar" wrap-class="wrap-x-hidden">
<el-tree
:data="behavior_views"
:props="defaultProps"
:expand-on-click-node="false"
draggable
highlight-current
:default-expand-all="true"
@node-click="handleNodeClick"
empty-text=""
>
<div slot-scope="{ node, data }" class="tree-node">
{{data.name}}
</div>
</el-tree>
</el-scrollbar>
<div class="bottom-bar">
<div></div>
<el-button-group>
<el-button @click="onCancel" plain>Cancel</el-button>
<el-button @click="onConfirm" type="primary" plain>Confirm</el-button>
</el-button-group>
</div>
</div>
<el-input clearable slot="reference" v-model="editValue" @change="onInput" placeholder="unset">
<template slot="prepend">node://</template>
</el-input>
</el-popover>
<el-button-group>
<el-button :icon="editButtonIcon" @click="onClickEdit"></el-button>
<el-button icon="el-icon-delete" @click="onClickClean"></el-button>
</el-button-group>
</div>
</editor-wrapper>
</template>
<script>
import {mapGetters} from "vuex";
import EditorWrapper from "./EditorWrapper";
const nodeScheme = 'node://';
export default {
name: "NodeSelectEditor",
components: {EditorWrapper,},
props: ['value', 'container', 'property', 'propertyName'],
data() {
return {
editValueOrigin: this.value,
popoverVisible: false,
defaultProps: {
children: 'children',
label: 'name'
},
}
},
computed: {
...mapGetters([
'behavior_views'
]),
editValue: {
get(){
return this.editValueOrigin ? this.editValueOrigin.replace(nodeScheme) : '';
},
set(v){
this.editValueOrigin = v;
},
},
editButtonIcon() {
return this.popoverVisible ? 'el-icon-check' : 'el-icon-edit';
},
},
methods: {
onInput(v, oldValue) {
if (v !== this.value) {
this.$emit('input', v ? nodeScheme + v : undefined, this.container, this.propertyName, oldValue);
}
},
onChange() {
this.$emit('input', nodeScheme + this.selectedNodeUUID, this.container, this.propertyName, this.value);
},
onClickEdit() {
this.popoverVisible = !this.popoverVisible;
},
onClickClean() {
this.$emit('input', undefined, this.container, this.propertyName, this.value);
},
onConfirm() {
this.editValue = this.selectedNodeUUID;
this.onChange();
this.popoverVisible = false;
},
onCancel() {
this.$emit('cancel');
this.popoverVisible = false;
},
handleNodeClick(data, node) {
this.selectedNodeUUID = data.uuid;
},
},
}
</script>
<style scoped>
</style>
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-input-number :value="editValue" @input="onInput" controls-position="right" <el-input-number :value="editValue" @input="onInput" controls-position="right"
:placeholder="defaultValue"></el-input-number> :placeholder="defaultValue"></el-input-number>
</editor-wrapper> </editor-wrapper>
......
<template>
<editor-wrapper :property="property">
<div class="texture-box">
<el-popover
placement="top"
popper-class="raw-editor-popover"
class="raw-name-container"
trigger="manual"
width="400"
v-model="popoverVisible">
<json-editor ref="jsonEditor" :value="editValue" @input="onInput" @cancel="onCancel"></json-editor>
<div slot="reference" class="editor-texture-name">{{rawString}}</div>
</el-popover>
<el-button-group>
<el-button :icon="editButtonIcon" @click="onClickEdit"></el-button>
<el-button icon="el-icon-delete" @click="onClickClean"></el-button>
</el-button-group>
</div>
</editor-wrapper>
</template>
<script>
import JsonEditor from "./JsonEditor";
import EditorWrapper from "./EditorWrapper";
export default {
name: "RawEditor",
components: {JsonEditor, EditorWrapper},
props: ['component', 'value', 'property'],
data() {
return {
popoverVisible: false,
}
},
computed: {
editButtonIcon() {
return this.popoverVisible ? 'el-icon-check' : 'el-icon-edit';
},
rawString() {
return this.editValue ? JSON.stringify(this.editValue) : '';
},
editValue(){
return this.value ? this.value.data : null;
}
},
watch: {
popoverVisible(v){
if(v){
this.$refs.jsonEditor.initValue();
}
}
},
methods: {
onClickEdit() {
this.popoverVisible = !this.popoverVisible;
},
onClickClean() {
this.$emit('input', undefined, this.component, this.property.name, this.value);
},
onInput(v) {
if(v !== this.value){
this.$emit('input', {
_type_: 'raw',
data: v,
}, this.component, this.property.name, this.value);
}
this.popoverVisible = false;
},
onCancel(){
this.popoverVisible = false;
}
},
}
</script>
<style scoped>
.texture-box {
width: 100%;
height: 28px;
display: flex;
font-size: 12px;
}
.editor-texture-name {
line-height: 28px;
height: 28px;
border-radius: 4px 0 0 4px;
color: gray;
padding: 0 5px;
user-select: none;
}
.raw-name-container {
flex: 1;
overflow: hidden;
}
.invalid-link {
color: red;
}
.inspector-append {
width: 45px;
}
</style>
<template> <template>
<editor-wrapper :property="property" :propertyName="propertyName"> <editor-wrapper :value="value" :container="container" :property="property" :propertyName="propertyName">
<div style="display: flex;flex: 1;"> <div style="display: flex;flex: 1;">
<el-popover <el-popover
placement="top" placement="top"
popper-class="input-area-popover" popper-class="input-area-popover"
class="string-name-container" class="string-editor-container"
trigger="manual" trigger="manual"
width="400" width="400"
v-model="popoverVisible" v-model="popoverVisible"
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
type="textarea" type="textarea"
v-model="popoverEditValue" v-model="popoverEditValue"
:placeholder="defaultValue" :placeholder="defaultValue"
:rows="6"> :rows="6"
>
</el-input> </el-input>
<div class="bottom-bar"> <div class="bottom-bar">
<el-button @click="onClean" type="danger" plain>Clean</el-button> <el-button @click="onClean" type="danger" plain>Clean</el-button>
...@@ -24,11 +25,12 @@ ...@@ -24,11 +25,12 @@
</el-button-group> </el-button-group>
</div> </div>
</div> </div>
<el-input clearable slot="reference" v-model="editValue" @change="onChange" :placeholder="defaultValue"/> <el-input clearable slot="reference" :value="editValue" @input="onInput" @change="onChange"
:placeholder="defaultValue"/>
</el-popover> </el-popover>
<el-button-group> <el-button-group>
<el-button :icon="editButtonIcon" @click="onClickEdit"></el-button> <el-button :icon="editButtonIcon" @click="onClickEdit" ></el-button>
<el-button icon="el-icon-delete" @click="onClickClean"></el-button> <el-button icon="el-icon-delete" @click="onClickClean" ></el-button>
</el-button-group> </el-button-group>
</div> </div>
</editor-wrapper> </editor-wrapper>
...@@ -36,7 +38,7 @@ ...@@ -36,7 +38,7 @@
<script> <script>
import EditorWrapper from "./EditorWrapper"; import EditorWrapper from "./EditorWrapper";
import {getEditorDefaultValue} from "../../../../utils"; import {getEditorDefaultValue, linkedFlag} from "../../../../utils";
export default { export default {
name: "StringEditor", name: "StringEditor",
...@@ -44,22 +46,25 @@ ...@@ -44,22 +46,25 @@
props: ['value', 'container', 'property', 'propertyName'], props: ['value', 'container', 'property', 'propertyName'],
data() { data() {
return { return {
editValue: this.value, editValueOrigin: this.value,
popoverEditValue: this.value, popoverEditValue: this.value,
popoverVisible: false, popoverVisible: false,
} }
}, },
computed: { computed: {
editValue() {
return this.editable ? this.editValueOrigin : '';
},
editButtonIcon() { editButtonIcon() {
return this.popoverVisible ? 'el-icon-check' : 'el-icon-edit'; return this.popoverVisible ? 'el-icon-check' : 'el-icon-edit';
}, },
defaultValue() { defaultValue() {
return getEditorDefaultValue(this.property); return getEditorDefaultValue(this.property);
} },
}, },
watch: { watch: {
value(v) { value(v) {
this.editValue = v; this.editValueOrigin = v;
}, },
popoverVisible(v) { popoverVisible(v) {
if (v) { if (v) {
...@@ -74,11 +79,14 @@ ...@@ -74,11 +79,14 @@
onClickClean() { onClickClean() {
this.$emit('input', undefined, this.container, this.propertyName, this.value); this.$emit('input', undefined, this.container, this.propertyName, this.value);
}, },
onInput(v) {
this.editValueOrigin = v;
},
onChange() { onChange() {
this.$emit('input', this.editValue, this.container, this.propertyName, this.value); this.$emit('input', this.editValue, this.container, this.propertyName, this.value);
}, },
onConfirm() { onConfirm() {
this.editValue = this.popoverEditValue; this.editValueOrigin = this.popoverEditValue;
this.onChange(); this.onChange();
this.popoverVisible = false; this.popoverVisible = false;
}, },
...@@ -100,8 +108,4 @@ ...@@ -100,8 +108,4 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.string-name-container {
flex: 1;
}
</style> </style>
<template> <template>
<el-dialog :title="$t('Behavior Editor')" :visible.sync="visible" @opened="onOpened" :fullscreen="true" <el-dialog :title="$t('Behavior Editor')" :visible.sync="visible" @before-close="beforeClose" @opened="onOpened"
:fullscreen="true"
:append-to-body="true" :close-on-click-modal="false" custom-class="behavior-editor-dialog"> :append-to-body="true" :close-on-click-modal="false" custom-class="behavior-editor-dialog">
<behavior-editor ref="behaviorEditor" class="full-size"></behavior-editor> <behavior-editor v-if="editorReady" ref="behaviorEditor" class="full-size"></behavior-editor>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button>
</div> </div>
...@@ -18,11 +19,12 @@ ...@@ -18,11 +19,12 @@
data() { data() {
return { return {
visible: false, visible: false,
editorReady: false,
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
data: state=>state.project.data, data: state => state.project.data,
}), }),
}, },
methods: { methods: {
...@@ -32,6 +34,7 @@ ...@@ -32,6 +34,7 @@
behaviors, behaviors,
event, event,
}); });
this.editorReady = false;
this.visible = true; this.visible = true;
}, },
onSave() { onSave() {
...@@ -39,12 +42,22 @@ ...@@ -39,12 +42,22 @@
this.visible = false; this.visible = false;
this.$emit('change'); this.$emit('change');
}, },
beforeClose() {
this.behavior_cancel();
this.visible = false;
this.$emit('cancel');
},
onOpened() { onOpened() {
this.editorReady = true;
this.$nextTick(() => {
this.$refs.behaviorEditor.edit(); this.$refs.behaviorEditor.edit();
});
}, },
...mapMutations([ ...mapMutations([
'behavior_startEdit', 'behavior_startEdit',
'behavior_save', 'behavior_save',
'behavior_cancel',
]), ]),
} }
} }
......
/**
* Created by rockyl on 2019-11-11.
*/
import Vue from 'vue'
Vue.directive('resize', {
bind(el, binding) {
let width = '', height = '';
function get() {
const style = document.defaultView.getComputedStyle(el);
if (width !== style.width || height !== style.height) {
binding.value({width, height});
}
width = style.width;
height = style.height;
}
el.__vueReize__ = setInterval(get, 500);
},
unbind(el) {
clearInterval(el.__vueReize__);
},
});
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