Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Z
zeroing-editor
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
劳工
zeroing-editor
Commits
0a0442d1
Commit
0a0442d1
authored
Nov 04, 2019
by
rockyl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
行为编辑器完成
parent
bb3df274
Changes
44
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
2119 additions
and
355 deletions
+2119
-355
行为编辑器设计.md
docs/行为编辑器设计.md
+11
-0
项目拆分.xmind
docs/项目拆分.xmind
+0
-0
info-.json
mock/api/editor/info-.json
+0
-0
index.js
mock/api/editor/info/index.js
+8
-2
data-.json
mock/api/project/query/data-.json
+0
-0
index.js
mock/api/project/query/data/index.js
+10
-6
config.js
src/config.js
+2
-2
en.json
src/locales/en.json
+6
-0
router.js
src/router.js
+0
-5
index.js
src/store/index.js
+10
-3
behavior.js
src/store/modules/behavior.js
+106
-0
env.js
src/store/modules/env.js
+21
-3
project.js
src/store/modules/project.js
+17
-13
behavior.scss
src/themes/light/behavior.scss
+154
-9
editor.scss
src/themes/light/editor.scss
+1
-1
index.scss
src/themes/light/index.scss
+20
-0
inspector.scss
src/themes/light/inspector.scss
+25
-0
index.js
src/utils/index.js
+26
-1
BehaviorEditorWrapper.vue
src/views/BehaviorEditorWrapper.vue
+0
-15
BehaviorTab.vue
src/views/Editor/Inspector/BehaviorTab.vue
+3
-1
PropsTab.vue
src/views/Editor/Inspector/PropsTab.vue
+45
-43
BehaviorEditor.vue
src/views/Editor/behavior-editor/BehaviorEditor.vue
+106
-165
Board.vue
src/views/Editor/behavior-editor/Board.vue
+140
-22
EditPath.vue
src/views/Editor/behavior-editor/Board/EditPath.vue
+32
-0
Process.js
src/views/Editor/behavior-editor/Board/Process.js
+7
-11
ProcessNode.vue
src/views/Editor/behavior-editor/Board/ProcessNode.vue
+44
-20
ToolTip.vue
src/views/Editor/behavior-editor/Board/ToolTip.vue
+1
-0
MetaEditorDialog.vue
src/views/Editor/behavior-editor/MetaEditorDialog.vue
+90
-0
OptionsEditorDialog.vue
src/views/Editor/behavior-editor/OptionsEditorDialog.vue
+148
-0
ProcessList.vue
src/views/Editor/behavior-editor/ProcessList.vue
+49
-5
Properties.vue
src/views/Editor/behavior-editor/Properties.vue
+0
-15
PropertiesEditor.vue
src/views/Editor/behavior-editor/PropertiesEditor.vue
+56
-0
BooleanEditor.vue
src/views/Editor/behavior-editor/editors/BooleanEditor.vue
+38
-0
ColorEditor.vue
src/views/Editor/behavior-editor/editors/ColorEditor.vue
+64
-0
EditorWrapper.vue
src/views/Editor/behavior-editor/editors/EditorWrapper.vue
+34
-0
EnumEditor.vue
src/views/Editor/behavior-editor/editors/EnumEditor.vue
+27
-0
EnumSelect.vue
.../Editor/behavior-editor/editors/EnumEditor/EnumSelect.vue
+49
-0
EventEditor.vue
src/views/Editor/behavior-editor/editors/EventEditor.vue
+207
-0
NumberEditor.vue
src/views/Editor/behavior-editor/editors/NumberEditor.vue
+36
-0
RawEditor.vue
src/views/Editor/behavior-editor/editors/RawEditor.vue
+107
-0
StringEditor.vue
src/views/Editor/behavior-editor/editors/StringEditor.vue
+107
-0
form-item.vue
src/views/Editor/behavior-editor/editors/form-item.vue
+294
-0
BehaviorEditorDialog.vue
src/views/Editor/dialogs/BehaviorEditorDialog.vue
+12
-5
yarn.lock
yarn.lock
+6
-8
No files found.
docs/行为编辑器设计.md
0 → 100644
View file @
0a0442d1
# 库
*
builtins 内建
*
customs 自定义
# 库中的嵌套
builtins不能引用customs中的过程,但是customs能引用builtins中的过程
库中的过程只能使用引用,即带有脚本的过程只暴露在根中
# 索引
为方便查找,所有集合都采用id作为键名
在树状列表中用到的列表需转化一次成为可用数据结构
docs/项目拆分.xmind
View file @
0a0442d1
No preview for this file type
mock/api/editor/info.json
→
mock/api/editor/info
-
.json
View file @
0a0442d1
File moved
mock/api/editor/info/index.js
View file @
0a0442d1
...
...
@@ -12,6 +12,7 @@ const data = {
id
:
'entry'
,
name
:
'Entry'
,
group
:
'base'
,
type
:
'builtin'
,
options
:
{},
output
:
[
'success'
],
},
...
...
@@ -19,6 +20,7 @@ const data = {
id
:
'wait'
,
name
:
'Wait'
,
group
:
'base'
,
type
:
'builtin'
,
options
:
{
duration
:
{
type
:
'number'
,
default
:
1000
},
},
...
...
@@ -27,7 +29,9 @@ const data = {
{
id
:
'prefab1'
,
name
:
'Prefab1'
,
type
:
'builtin'
,
isPrefab
:
true
,
subEntry
:
'1'
,
sub
:
{
1
:
{
uuid
:
'1'
,
...
...
@@ -54,8 +58,10 @@ const data = {
name
:
'Wave'
,
options
:
{
duration
:
{
type
:
'number'
,
default
:
1000
},
type
:
{
type
:
'string'
,
default
:
'yoyo'
},
ease
:
{
type
:
'string'
,
default
:
'linear'
},
name
:
{
type
:
'string'
,
default
:
'hello'
},
color
:
{
type
:
'color'
,
default
:
'#123456'
},
type
:
{
type
:
[
'rotate'
,
'jump'
,
'breath'
],
default
:
'rotate'
},
ease
:
{
type
:
[
'linear'
,
'cubic'
,
'back'
],
default
:
'linear'
},
autoPlay
:
{
type
:
'boolean'
,
default
:
false
},
}
}
...
...
mock/api/project/query/data.json
→
mock/api/project/query/data
-
.json
View file @
0a0442d1
File moved
mock/api/project/query/data/index.js
View file @
0a0442d1
...
...
@@ -46,12 +46,12 @@ const data = {
}],
"assets"
:
[],
"dataMapping"
:
[],
process
Map
:
{
main
:
{
process
es
:
[
{
id
:
'main'
,
name
:
'Main'
,
options
:
{},
subEntry
:
'1'
,
subEntry
:
'
a
1'
,
sub
:
{
a1
:
{
uuid
:
'a1'
,
...
...
@@ -83,15 +83,19 @@ const data = {
},
}
},
test
:
{
{
id
:
'test'
,
name
:
'Test'
,
options
:
{
text
:
{
type
:
'string'
,
default
:
''
},
text
:
{
alias
:
'文本'
,
type
:
'string'
,
default
:
'你好'
},
num
:
{
alias
:
'数字'
,
type
:
'number'
,
default
:
1
},
type
:
{
alias
:
'类型'
,
type
:
'enum'
,
enum
:
[
'rotate'
,
'jump'
,
'breath'
],
default
:
'rotate'
},
autoPlay
:
{
alias
:
'自动播放'
,
type
:
'boolean'
,
default
:
false
},
},
output
:
[
'success'
,
'failed'
],
script
:
"console.log('test');"
,
},
}
],
};
const
data1
=
{
"views"
:
[{
...
...
src/config.js
View file @
0a0442d1
...
...
@@ -2,8 +2,8 @@
* Created by rockyl on 2019-09-19.
*/
export
const
API_HOST
=
'http://10.10.95.74:7777'
;
//
export const API_HOST = 'http://localhost:3002';
//
export const API_HOST = 'http://10.10.95.74:7777';
export
const
API_HOST
=
'http://localhost:3002'
;
export
const
UPLOAD_FILE_URL
=
API_HOST
+
'/api/uploadFile'
;
export
const
PARSE_BUNDLE_URL
=
API_HOST
+
'/api/parsePSD'
;
...
...
src/locales/en.json
View file @
0a0442d1
...
...
@@ -11,6 +11,8 @@
"Import"
:
"Import"
,
"Export"
:
"Export"
,
"Upload"
:
"Upload"
,
"Edit"
:
"Edit"
,
"Name"
:
"Name"
,
"Failed to fetch"
:
"Network error!"
,
"In processing"
:
"In processing"
,
"Projects"
:
"Projects"
,
...
...
@@ -28,6 +30,8 @@
"Saving"
:
"Saving…"
,
"Create project"
:
"Create project"
,
"Rename project"
:
"Rename project"
,
"Options Editor"
:
"Options Editor"
,
"Meta Editor"
:
"Meta Editor"
,
"Input project name"
:
"Input project name"
,
"Invalid project name"
:
"Invalid project name"
,
"Creating project"
:
"Creating project…"
,
...
...
@@ -61,6 +65,8 @@
"Invalid asset name"
:
"Invalid asset name"
,
"Copied field to clipboard"
:
"Copied {field} to clipboard"
,
"Unsaved Alert"
:
"You are leaving, but the project is not saved. Do you want to save it?"
,
"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?"
,
"menu"
:
{
"save"
:
"Save"
,
"preview"
:
"Preview"
,
...
...
src/router.js
View file @
0a0442d1
...
...
@@ -18,10 +18,5 @@ export default new Router({
name
:
'editor'
,
component
:
()
=>
import
(
'./views/Editor.vue'
)
},
{
path
:
'/behavior'
,
name
:
'behavior'
,
component
:
()
=>
import
(
'./views/BehaviorEditorWrapper.vue'
)
},
]
})
src/store/index.js
View file @
0a0442d1
...
...
@@ -8,17 +8,23 @@ import {envStore} from "./modules/env";
import
{
projectsStore
}
from
"./modules/projects"
;
import
{
projectStore
}
from
"./modules/project"
;
import
SaveToLocalPlugin
from
"./save-to-local-plugin"
;
import
{
behaviorStore
}
from
"./modules/behavior"
;
Vue
.
use
(
Vuex
);
export
default
new
Vuex
.
Store
({
state
:
{},
mutations
:
{},
actions
:
{},
mutations
:
{
},
actions
:
{
},
modules
:
{
env
:
envStore
,
projects
:
projectsStore
,
project
:
projectStore
,
behavior
:
behaviorStore
,
},
plugins
:
[
SaveToLocalPlugin
({
...
...
@@ -34,7 +40,8 @@ export default new Vuex.Store({
'addDataMapping'
,
'deleteDataMapping'
,
'modifyDataMapping'
,
'modifyActiveView'
'modifyActiveView'
,
'behavior_save'
,
]
})
]
...
...
src/store/modules/behavior.js
0 → 100644
View file @
0a0442d1
/**
* Created by rockyl on 2019-10-29.
*
* 行为编辑
*/
import
Vue
from
'vue'
;
import
generateUUID
from
"uuid/v4"
;
import
{
metaInUse
,
updateProcesses
}
from
"../../utils"
;
export
const
behaviorStore
=
{
state
:
{
data
:
{},
currentBehavior
:
null
,
processContext
:
[],
originData
:
null
,
behaviors
:
null
,
},
mutations
:
{
behavior_startEdit
(
state
,
{
originData
,
behaviors
,
event
})
{
state
.
originData
=
originData
;
state
.
behaviors
=
behaviors
;
state
.
data
=
JSON
.
parse
(
JSON
.
stringify
(
originData
));
if
(
behaviors
.
length
>
0
)
{
state
.
currentBehavior
=
behaviors
[
0
];
}
else
{
let
metaUUID
=
generateUUID
();
state
.
currentBehavior
=
behaviors
[
0
]
=
{
uuid
:
generateUUID
(),
alias
:
event
,
meta
:
metaUUID
,
};
let
subEntryUUID
=
generateUUID
();
state
.
data
.
processes
.
push
({
id
:
metaUUID
,
name
:
'event'
,
options
:
{},
subEntry
:
subEntryUUID
,
sub
:
{
[
subEntryUUID
]:
{
uuid
:
subEntryUUID
,
alias
:
'Entry'
,
meta
:
'entry'
,
},
}
});
}
},
addCustomProcessMeta
(
state
,
meta
)
{
state
.
data
.
processes
.
push
(
meta
);
return
process
;
},
behavior_save
(
state
)
{
state
.
originData
.
processes
=
state
.
data
.
processes
;
state
.
behaviors
[
0
]
=
state
.
currentBehavior
;
},
updateProcesses
(
state
,
{
targetMetaID
,
replaceMetaID
})
{
for
(
let
process
of
state
.
data
.
processes
)
{
updateProcesses
(
process
,
targetMetaID
,
replaceMetaID
);
}
},
deleteProcessMeta
(
state
,
metaID
)
{
for
(
let
i
=
0
,
li
=
state
.
data
.
processes
.
length
;
i
<
li
;
i
++
)
{
const
process
=
state
.
data
.
processes
[
i
];
if
(
process
.
id
===
metaID
)
{
state
.
data
.
processes
.
splice
(
i
,
1
);
break
;
}
}
}
},
getters
:
{
customProcessMap
:
state
=>
{
let
map
=
{};
for
(
let
process
of
state
.
data
.
processes
)
{
map
[
process
.
id
]
=
process
;
}
return
map
;
},
metaInUse
:
state
=>
targetMetaID
=>
{
let
result
=
false
;
for
(
let
process
of
state
.
data
.
processes
)
{
if
(
metaInUse
(
process
,
targetMetaID
))
{
result
=
true
;
break
;
}
}
return
result
;
},
},
actions
:
{
addCustomProcessMeta
({
commit
,
state
})
{
let
meta
=
{
id
:
generateUUID
(),
name
:
'Custom'
,
script
:
''
,
options
:
{},
output
:
[
'success'
,
'failed'
],
};
commit
(
'addCustomProcessMeta'
,
meta
);
return
meta
;
},
}
};
src/store/modules/env.js
View file @
0a0442d1
...
...
@@ -28,13 +28,31 @@ export const envStore = {
prefabProcessTree
:
state
=>
{
return
groupProcesses
(
state
.
processes
,
process
=>
process
.
isPrefab
);
},
normalProcessTree
:
state
=>
{
return
groupProcesses
(
state
.
processes
,
process
=>
!
process
.
isPrefab
);
builtinProcessTree
:
state
=>
{
const
customProcess
=
{
id
:
'custom'
,
name
:
'Custom'
,
};
const
tree
=
groupProcesses
(
state
.
processes
,
process
=>
!
process
.
isPrefab
);
tree
.
unshift
(
customProcess
);
tree
.
push
({
name
:
'custom'
,
children
:
[],
});
return
tree
;
},
builtinsProcessMap
:
state
=>
{
let
map
=
{};
for
(
let
process
of
state
.
processes
)
{
map
[
process
.
id
]
=
process
;
}
return
map
;
}
},
actions
:
{
async
updateEnv
({
state
,
commit
})
{
if
(
!
state
.
initialized
)
{
if
(
!
state
.
initialized
)
{
const
env
=
await
envApi
.
fetchEnv
();
commit
(
'updateEnv'
,
env
);
}
...
...
src/store/modules/project.js
View file @
0a0442d1
...
...
@@ -18,6 +18,7 @@ export const projectStore = {
views
:
[],
assets
:
[],
dataMapping
:
[],
processMap
:
{},
},
activeComponent
:
{},
activeComponentCopy
:
{},
// 当前选中节点的镜像,用来处理拖拽时数据变化频繁的问题
...
...
@@ -40,20 +41,22 @@ export const projectStore = {
const
localData
=
state
.
data
;
if
(
data
)
{
const
{
views
,
assets
,
dataMapping
}
=
JSON
.
parse
(
data
);
const
{
views
,
assets
,
dataMapping
,
processes
}
=
JSON
.
parse
(
data
);
Vue
.
set
(
localData
,
'views'
,
views
||
[]);
Vue
.
set
(
localData
,
'assets'
,
assets
||
[]);
Vue
.
set
(
localData
,
'dataMapping'
,
dataMapping
||
[]);
Vue
.
set
(
localData
,
'processes'
,
processes
||
[]);
}
else
{
Vue
.
set
(
localData
,
'views'
,
[]);
Vue
.
set
(
localData
,
'assets'
,
[]);
Vue
.
set
(
localData
,
'dataMapping'
,
[]);
Vue
.
set
(
localData
,
'processes'
,
[]);
}
},
/**
* 激活组件
* @param {*} state
* @param {*} i
d
* @param {*} i
tem
*/
activeComponent
(
state
,
item
)
{
if
(
item
!==
state
.
activeComponent
)
{
...
...
@@ -64,8 +67,8 @@ export const projectStore = {
},
/**
* 修改当前选中的节点
* @param {*} state
* @param {*} view
* @param {*} state
* @param {*} view
*/
modifyActiveView
(
state
,
view
)
{
if
(
!
view
)
{
...
...
@@ -121,8 +124,8 @@ export const projectStore = {
},
/**
* 修改当前组件镜像的属性
* @param {*} state
* @param {*} props
* @param {*} state
* @param {*} props
*/
modifyCopyProperties
(
state
,
props
)
{
if
(
!
props
)
{
...
...
@@ -135,7 +138,8 @@ export const projectStore = {
},
/**
* assets拖拽
* @param {*} data
* @param state
* @param {*} data
*/
assetDragStart
(
state
,
data
)
{
state
.
dragUUID
=
data
.
uuid
;
...
...
@@ -327,7 +331,7 @@ export const projectStore = {
},
/**
* 选中节点
* @param {*}
param
* @param {*}
context
* @param {*} data
*/
activeComponent
(
context
,
data
)
{
...
...
@@ -338,7 +342,7 @@ export const projectStore = {
}
else
{
return
getTopView
(
node
.
parent
);
}
}
}
;
let
_view
=
getTopView
(
data
.
node
);
if
(
_view
&&
_view
.
data
)
{
...
...
@@ -382,8 +386,8 @@ export const projectStore = {
},
/**
* 修改镜像的属性
* @param {*} param0
* @param {*} props
* @param {*} param0
* @param {*} props
*/
modifyCopyProperties
({
commit
},
props
)
{
commit
(
'modifyCopyProperties'
,
props
)
...
...
@@ -397,8 +401,8 @@ export const projectStore = {
/**
* 新增节点脚本
* @param {*} param0
* @param {*} data
* @param {*} param0
* @param {*} data
*/
addNodeScript
({
commit
,
state
},
script
)
{
let
_scripts
=
_
.
cloneDeep
(
state
.
activeComponent
.
scripts
||
[]);
...
...
src/themes/light/behavior.scss
View file @
0a0442d1
...
...
@@ -16,15 +16,54 @@ $dock-point-width: 9px;
}
.process-tree
{
.scrollbar
{
height
:
100%
;
.process-tree-node
{
flex
:
1
;
flex-direction
:
row
;
display
:
flex
;
padding-right
:
10px
;
.node-name
{
flex
:
1
;
width
:
0
;
text-overflow
:
ellipsis
;
overflow
:
hidden
;
font-size
:
14px
;
}
.edit-button
{
visibility
:
hidden
;
}
}
}
}
.behavior
{
border
:
1px
solid
$--border-color-base
;
.background
{
.background
{
background-color
:
$--background-color-base
;
}
.center
{
display
:
flex
;
flex-direction
:
column
;
.edit-path
{
padding
:
5px
;
height
:
14px
;
border-bottom
:
1px
solid
$--border-color-light
;
}
}
.board
{
flex
:
1
;
.svg-board
{
.line
{
stroke
:
#979797
;
...
...
@@ -49,21 +88,21 @@ $dock-point-width: 9px;
user-select
:
none
;
margin
:
0
$dock-point-width
;
&
:hover
{
/*
&:hover {
border-color: $block-border-hover-background-color;
& > .header {
background-color: $block-border-hover-background-color;
}
}
}
*/
&
:focus
{
/*
&:focus {
border-color: $block-border-focus-background-color;
& > .header {
background-color: $block-border-focus-background-color;
}
}
}
*/
.header
{
min-height
:
12px
;
...
...
@@ -73,6 +112,20 @@ $dock-point-width: 9px;
padding
:
3px
;
font-size
:
12px
;
color
:
white
;
display
:
flex
;
.title
{
flex
:
1
;
}
.delete-button
{
padding
:
2px
;
color
:
$--border-color-lighter
;
&
:hover
{
color
:
white
;
}
}
}
.body
{
...
...
@@ -85,14 +138,18 @@ $dock-point-width: 9px;
.field-item
{
display
:
flex
;
.key
{
span
{
flex
:
1
;
width
:
0
;
white-space
:
nowrap
;
overflow
:
hidden
;
}
.key
{
}
.value
{
flex
:
1
;
text-align
:
right
;
}
}
...
...
@@ -143,11 +200,99 @@ $dock-point-width: 9px;
right
:
-
$dock-point-width
;
}
}
.active
{
border-color
:
$block-border-focus-background-color
;
&
>
.header
{
background-color
:
$block-border-focus-background-color
;
}
}
}
}
.properties
{
display
:
flex
;
flex-direction
:
column
;
.el-input-group__prepend
{
padding
:
0
5px
;
}
.el-button
{
padding-left
:
5px
;
padding-right
:
5px
;
}
.wrapper
{
padding
:
5px
;
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
.scrollbar
{
padding-top
:
5px
;
flex
:
1
;
.el-form-item__content
{
display
:
flex
;
.el-input-number--mini
{
flex
:
1
;
}
}
}
}
}
}
}
\ No newline at end of file
}
.meta-editor-wrapper
{
height
:
40vh
;
display
:
flex
;
padding
:
5px
;
flex-direction
:
column
;
.info-editor
{
margin-right
:
5px
;
}
.script-editor
{
flex
:
1
;
}
}
.options-editor-dialog
{
.scrollbar
{
width
:
100%
;
height
:
40vh
;
}
.add-button
{
margin-bottom
:
5px
;
}
.default-value
{
width
:
100%
;
}
.operate-bar
{
.el-button
{
padding
:
4px
;
}
.edit-enum-button
{
}
.delete-button
{
margin-left
:
3px
;
}
}
}
.edit-enum-popover
{
.el-select
{
width
:
400px
;
}
}
src/themes/light/editor.scss
View file @
0a0442d1
...
...
@@ -40,7 +40,7 @@
}
}
.
bottom-bar
,
.
toolbar
{
.toolbar
{
background-color
:
$--pane-background-color
;
}
...
...
src/themes/light/index.scss
View file @
0a0442d1
...
...
@@ -27,3 +27,23 @@
padding
:
6px
0
;
}
.el-input__inner
{
padding
:
0
5px
;
}
.el-input--suffix
.el-input__inner
{
padding-right
:
5px
;
}
.el-form-item--mini.el-form-item
{
margin-bottom
:
3px
;
}
.el-textarea__inner
{
height
:
100%
;
}
.el-tabs--border-card
>
.el-tabs__content
{
padding
:
5px
;
}
src/themes/light/inspector.scss
View file @
0a0442d1
.inspector-tabs
{
flex
:
1
;
border
:
0
!
important
;
display
:
flex
;
flex-direction
:
column
;
&
>
:last-child
{
flex
:
1
;
}
.el-tabs__item
{
height
:
25px
;
line-height
:
25px
;
}
.el-tab-pane
{
height
:
100%
;
}
.zero-inspector-props-form
{
height
:
100%
;
.el-input-number.el-input-number--mini
,
.el-select.el-select--mini
{
width
:
100%
;
}
...
...
@@ -23,5 +35,18 @@
.zero-slider
>
.el-slider__input
{
width
:
60px
;
}
.scrollbar
{
height
:
100%
;
}
}
.zero-inspector-behavior-form
{
height
:
100%
;
.scrollbar
{
height
:
100%
;
}
}
}
src/utils/index.js
View file @
0a0442d1
...
...
@@ -59,8 +59,33 @@ export function saveAs(blob, fileName) {
link
.
click
();
document
.
body
.
removeChild
(
link
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
URL
.
revokeObjectURL
(
url
);
},
500
);
}
}
export
function
getEditorDefaultValue
(
property
)
{
return
property
.
hasOwnProperty
(
'default'
)
?
property
.
default
+
''
:
'unset'
;
}
export
function
updateProcesses
(
process
,
targetMetaID
,
replaceMetaID
)
{
for
(
let
key
in
process
.
sub
)
{
let
subProcess
=
process
.
sub
[
key
];
if
(
subProcess
.
meta
===
targetMetaID
)
{
subProcess
.
meta
=
replaceMetaID
;
}
}
}
export
function
metaInUse
(
process
,
targetMetaID
)
{
let
result
=
false
;
for
(
let
key
in
process
.
sub
)
{
let
subProcess
=
process
.
sub
[
key
];
if
(
subProcess
.
meta
===
targetMetaID
)
{
result
=
true
;
break
;
}
}
return
result
;
}
src/views/BehaviorEditorWrapper.vue
deleted
100644 → 0
View file @
bb3df274
<
template
>
<behavior-editor
style=
"width: 100%;height: 100%;display: flex;"
></behavior-editor>
</
template
>
<
script
>
import
BehaviorEditor
from
"./Editor/behavior-editor/BehaviorEditor"
;
export
default
{
name
:
"BehaviorEditorWrapper"
,
components
:
{
BehaviorEditor
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/Inspector/BehaviorTab.vue
View file @
0a0442d1
<
template
>
<div
class=
"zero-inspector-behavior-form"
v-if=
"activeComponent.uuid"
>
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
>
<el-form
ref=
"form"
size=
"mini"
label-width=
"80px"
>
<div
v-for=
"(evn, key) in eventsObj"
:key=
"key"
>
<el-form-item
label=
"触发事件:"
>
...
...
@@ -18,6 +19,7 @@
</el-form-item>
</div>
</el-form>
</el-scrollbar>
<behavior-editor-dialog
:behaviors=
"behaviors"
@
change=
"v => handleBehaviorsChange(v)"
ref=
"behaviorEditorDialog"
></behavior-editor-dialog>
</div>
</
template
>
...
...
@@ -52,7 +54,7 @@ export default {
showBehaviorEditor
(
evn
,
key
)
{
this
.
currentEvent
=
key
;
this
.
behaviors
=
evn
.
behaviors
||
[];
this
.
$refs
.
behaviorEditorDialog
.
show
();
this
.
$refs
.
behaviorEditorDialog
.
show
(
this
.
behaviors
,
key
);
},
/**
* 当前选中组件发生变化时,更新eventsObj的数据
...
...
src/views/Editor/Inspector/PropsTab.vue
View file @
0a0442d1
<
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-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
:component-value=
"getPropValue(p, key)"
:component-props=
"getPropProps(p)"
:component-type=
"getPropCmpType(p)"
@
onChange=
"v => handlePropertiesChange(key, v)"
></dynamic-component>
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
>
<el-form
ref=
"form"
size=
"mini"
:model=
"form"
label-width=
"80px"
>
<el-collapse
v-model=
"configColl"
>
<el-collapse-item
title=
"配置"
name=
"properties"
>
<el-form-item
label=
"名称"
>
<el-input
v-model=
"form.name"
@
input=
"v => handleChange('name', v)"
></el-input>
</el-form-item>
</
template
>
</el-collapse-item>
<el-collapse-item
title=
"脚本"
name=
"scripts"
>
<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>
<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
: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-collapse>
<div
style=
"padding-top: 15px;text-align: center;"
>
<el-popover
placement=
"top"
width=
"300"
v-model=
"scriptDialog"
trigger=
"manual"
>
<div
class=
"script-config-dialog"
>
<el-tree
:data=
"scripts"
:props=
"defaultProps"
@
node-click=
"handleNodeClick"
></el-tree>
</div>
<el-button
slot=
"reference"
@
click=
"scriptDialog = !scriptDialog"
size=
"mini"
>
add script
</el-button>
</el-popover>
</div>
</el-collapse-item>
</el-collapse>
</el-form>
</el-collapse-item>
<el-collapse-item
title=
"脚本"
name=
"scripts"
>
<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"
v-model=
"scriptDialog"
trigger=
"manual"
>
<div
class=
"script-config-dialog"
>
<el-tree
:data=
"scripts"
:props=
"defaultProps"
@
node-click=
"handleNodeClick"
></el-tree>
</div>
<el-button
slot=
"reference"
@
click=
"scriptDialog = !scriptDialog"
size=
"mini"
>
add script
</el-button>
</el-popover>
</div>
</el-collapse-item>
</el-collapse>
</el-form>
</el-scrollbar>
<!-- <div class="script-config-dialog" v-show="scriptDialog">
<el-tree :data="scripts" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div> -->
...
...
src/views/Editor/behavior-editor/BehaviorEditor.vue
View file @
0a0442d1
...
...
@@ -2,198 +2,139 @@
<div
class=
"behavior"
>
<split-panes>
<split-panes
splitpanes-min=
"20"
:splitpanes-size=
"20"
horizontal
>
<process-list
:data=
"prefabProcessTree"
class=
"background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"50"
/>
<process-list
:data=
"normalProcessTree"
class=
"background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"50"
/>
<process-list
@
edit-meta=
"onEditMeta"
@
delete-meta=
"onDeleteMeta"
:data=
"prefabProcessTree"
class=
"background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"30"
/>
<process-list
@
edit-meta=
"onEditMeta"
@
delete-meta=
"onDeleteMeta"
:data=
"normalProcessTree"
class=
"background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"70"
/>
</split-panes>
<board
ref=
"board"
class=
"background full-size"
:builtins=
"builtins"
:mainProcess=
"mainProcess"
splitpanes-min=
"20"
:splitpanes-size=
"60"
/>
<properties
class=
"background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"20"
/>
<div
class=
"center full-size background"
splitpanes-min=
"20"
:splitpanes-size=
"70"
>
<edit-path
:processStack=
"processStack"
@
pop=
"onPop"
/>
<board
ref=
"board"
@
select-process-node=
"onSelectProcessNode"
@
edit-process=
"editProcess"
/>
</div>
<div
class=
"properties background full-size"
splitpanes-min=
"20"
:splitpanes-size=
"30"
>
<properties-editor
ref=
"properties"
/>
</div>
</split-panes>
<meta-editor-dialog
ref=
"metaEditorDialog"
@
input=
"onSaveMeta"
/>
</div>
</
template
>
<
script
>
import
{
mapState
,
mapMutations
,
mapGetters
}
from
'vuex'
import
{
mapState
,
mapMutations
,
mapGetters
,
mapActions
}
from
'vuex'
import
Board
from
"./Board"
;
import
SplitPanes
from
'splitpanes'
import
ProcessList
from
"./ProcessList"
;
import
Properties
from
"./Properties"
;
const
builtins
=
{
entry
:
{
id
:
'entry'
,
name
:
'Entry'
,
options
:
{},
script
:
"resolve({type: 'success'});"
,
output
:
[
'success'
],
},
wait
:
{
id
:
'wait'
,
name
:
'Wait'
,
options
:
{
duration
:
{
type
:
'number'
,
default
:
1000
},
},
script
:
"setTimeout(function(){resolve({type: 'complete'})}, options.duration || 0);"
,
output
:
[
'complete'
],
},
};
const
mainProcess
=
{
uuid
:
'1'
,
alias
:
'主过程'
,
meta
:
{
id
:
'main'
,
name
:
'Main'
,
options
:
{},
metas
:
{
compare
:
{
id
:
'compare'
,
name
:
'Compare'
,
options
:
{
left
:
{
type
:
'any'
,
default
:
''
},
right
:
{
type
:
'any'
,
default
:
''
},
operator
:
{
type
:
'string'
,
default
:
'=='
},
},
script
:
`
let leftValue = typeof options.left === 'object' ? args[options.left.path] : options.left;
let rightValue = typeof options.right === 'object' ? args[options.right.path] : options.right;
let func = new Function('return '+leftValue+args.operator+rightValue);
let result = func();
resolve({type: result ? 'equal' : 'unequal'});
`
,
output
:
[
'complete'
],
},
nestProc
:
{
id
:
'nestProc'
,
name
:
'NestProc'
,
metas
:
{
print
:
{
id
:
'print'
,
name
:
'Print'
,
options
:
{
text
:
{
type
:
'string'
,
default
:
''
},
},
script
:
"console.log(options.text);resolve({type: 'success'});"
,
output
:
[
'success'
],
}
},
options
:
{},
subEntry
:
'1'
,
sub
:
{
1
:
{
uuid
:
'1'
,
meta
:
'wait'
,
alias
:
'等待'
,
options
:
{
duration
:
500
,
},
output
:
[
'2'
],
},
2
:
{
uuid
:
'2'
,
alias
:
'打印'
,
meta
:
'print'
,
options
:
{
text
:
'hello'
,
},
output
:
[],
},
},
},
test
:
{
options
:
{
text
:
{
type
:
'string'
,
default
:
''
},
},
script
:
"console.log(args, options);resolve({type: 'success'});"
,
output
:
[
'success'
,
'failed'
],
},
},
subEntry
:
'1'
,
sub
:
{
1
:
{
uuid
:
'1'
,
alias
:
'入口'
,
meta
:
'entry'
,
output
:
{
success
:
[
'2'
],
},
design
:
{
x
:
10
,
y
:
10
,
},
},
2
:
{
uuid
:
'2'
,
alias
:
'test'
,
meta
:
'test'
,
options
:
{
text
:
'hello'
,
},
output
:
{
success
:
[
'3'
],
failed
:
[],
},
design
:
{
x
:
20
,
y
:
100
,
},
},
3
:
{
uuid
:
'3'
,
alias
:
'等待'
,
meta
:
'wait'
,
options
:
{
duration
:
500
,
},
output
:
{
complete
:
[
'4'
]
},
design
:
{
x
:
200
,
y
:
50
,
},
},
4
:
{
uuid
:
'4'
,
alias
:
'nestProc'
,
meta
:
'nestProc'
,
options
:
{
text
:
'hello'
,
},
output
:
[],
design
:
{
x
:
150
,
y
:
200
,
},
},
}
}
};
import
PropertiesEditor
from
"./PropertiesEditor"
;
import
EditPath
from
"./Board/EditPath"
;
import
Process
from
"./Board/Process"
;
import
MetaEditorDialog
from
"./MetaEditorDialog"
;
export
default
{
name
:
"BehaviorEditor"
,
components
:
{
Properties
,
ProcessList
,
Board
,
SplitPanes
,},
components
:
{
MetaEditorDialog
,
PropertiesEditor
,
EditPath
,
ProcessList
,
Board
,
SplitPanes
,},
props
:
[],
data
()
{
return
{
builtins
,
m
ainProcess
,
processStack
:
[]
,
m
etaInEditing
:
null
,
}
},
computed
:
{
processContext
()
{
const
{
builtinsProcessMap
,
customProcessMap
}
=
this
.
$store
.
getters
;
return
[
builtinsProcessMap
,
customProcessMap
,
]
},
normalProcessTree
()
{
const
tree
=
this
.
builtinProcessTree
;
const
group
=
tree
.
find
(
item
=>
item
.
name
===
'custom'
);
group
.
children
=
this
.
$store
.
state
.
behavior
.
data
.
processes
;
return
tree
;
},
...
mapState
({
processes
:
state
=>
state
.
env
.
processes
,
behavior
:
state
=>
state
.
behavior
.
currentBehavior
,
}),
...
mapGetters
([
'prefabProcessTree'
,
'
normal
ProcessTree'
'
builtin
ProcessTree'
])
},
mounted
()
{
},
methods
:
{
measure
()
{
this
.
$refs
.
board
.
measure
();
}
resolveProcess
(
id
)
{
for
(
let
context
of
this
.
processContext
)
{
if
(
context
[
id
])
{
return
context
[
id
];
}
}
},
edit
()
{
this
.
processStack
.
splice
(
0
);
let
process
=
new
Process
(
null
,
this
.
behavior
,
this
.
resolveProcess
);
this
.
editProcess
(
process
);
},
onSelectProcessNode
(
process
)
{
this
.
$refs
.
properties
.
edit
(
process
);
},
editProcess
(
process
)
{
this
.
processStack
.
push
(
process
);
this
.
$refs
.
board
.
edit
(
process
,
this
.
resolveProcess
);
this
.
$refs
.
properties
.
edit
();
},
onPop
(
index
)
{
this
.
processStack
.
splice
(
index
+
1
);
let
process
=
this
.
processStack
[
this
.
processStack
.
length
-
1
];
this
.
$refs
.
board
.
edit
(
process
,
this
.
resolveProcess
);
this
.
$refs
.
properties
.
edit
();
},
onEditMeta
(
meta
)
{
this
.
metaInEditing
=
meta
;
this
.
$refs
.
metaEditorDialog
.
edit
(
meta
);
},
onDeleteMeta
(
meta
)
{
const
inUse
=
this
.
$store
.
getters
.
metaInUse
(
meta
.
id
);
if
(
inUse
)
{
this
.
$alert
(
this
.
$t
(
'Meta is in use, can not delete'
),
this
.
$t
(
'Alert'
))
.
catch
((
e
)
=>
{
});
}
else
{
this
.
$confirm
(
this
.
$t
(
'Are you sure to delete this meta'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Delete'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
type
:
'warning'
}).
then
(()
=>
{
this
.
deleteProcessMeta
(
meta
.
id
);
}).
catch
((
e
)
=>
{
});
}
},
onSaveMeta
(
meta
)
{
let
oldMetaID
=
this
.
metaInEditing
.
id
;
for
(
let
key
in
meta
)
{
this
.
metaInEditing
[
key
]
=
meta
[
key
];
}
this
.
metaInEditing
=
null
;
if
(
oldMetaID
!==
meta
.
id
)
{
this
.
updateProcesses
({
targetMetaID
:
oldMetaID
,
replaceMetaID
:
meta
.
id
,
});
}
this
.
$refs
.
board
.
updateProcessNode
();
},
...
mapMutations
([
'updateProcesses'
,
'deleteProcessMeta'
,
]),
...
mapGetters
([
'metaInUse'
,
]),
}
}
</
script
>
...
...
src/views/Editor/behavior-editor/Board.vue
View file @
0a0442d1
<
template
>
<div
class=
"board"
>
<svg
class=
"svg-board full-size"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<div
class=
"board"
@
dragover=
"onDragOver"
@
drop=
"onDrop"
>
<svg
class=
"svg-board full-size"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<g
id=
"layer"
stroke-width=
"2"
fill=
"none"
fill-rule=
"evenodd"
>
<link-line
v-for=
"(line, key, index) in lines"
:data=
"line"
:key=
"index"
@
dblclick=
"onDeleteLine"
></link-line>
<path
v-show=
"lineDrawing.visible"
class=
"line hover"
:d=
"lineDrawing.path"
></path>
</g>
<g
id=
"nodes"
>
<process-node
v-for=
"(process, key, index) of processMap"
:process=
"process"
:key=
"index"
<process-node
v-for=
"(process, key, index) of subProcessMap"
:ref=
"'pn_' + key"
:process=
"process"
:key=
"index"
@
click=
"onClickProcessNode(process, key)"
@
hover-point=
"onPointHover"
@
leave-point=
"onPointLeave"
@
down-point=
"onPointDown"
@
delete=
"onPointDelete"
@
dblclick=
"editSubProcess(process)"
/>
</g>
</svg>
...
...
@@ -18,6 +22,7 @@
</
template
>
<
script
>
import
{
mapState
,
mapMutations
,
mapGetters
,
mapActions
}
from
'vuex'
import
ProcessNode
from
"./Board/ProcessNode"
;
import
Process
from
"./Board/Process"
;
import
LinkLine
from
"./Board/LinkLine"
;
...
...
@@ -25,46 +30,117 @@
import
{
DOCK_POINT_OFFSET
}
from
"../../../config"
;
import
{
state
}
from
"./Board/state"
;
import
events
from
"../../../global-events"
;
import
generateUUID
from
"uuid/v4"
;
export
default
{
name
:
"Board"
,
components
:
{
ToolTip
,
LinkLine
,
ProcessNode
,},
props
:
[
'builtins'
,
'mainProcess'
],
props
:
[],
data
()
{
let
processMap
=
{};
let
currentProcess
=
new
Process
(
null
,
this
.
mainProcess
,
this
.
builtins
);
for
(
let
id
in
currentProcess
.
meta
.
sub
)
{
const
subData
=
currentProcess
.
meta
.
sub
[
id
];
processMap
[
id
]
=
new
Process
(
currentProcess
,
subData
,
this
.
builtins
)
}
return
{
processMap
,
process
:
null
,
subProcessMap
:
null
,
selectedProcessNode
:
null
,
lines
:
{},
lineDrawing
:
{
visible
:
false
,
path
:
''
path
:
''
,
process
:
null
,
}
}
},
mounted
()
{
},
computed
:
{},
methods
:
{
measure
(){
...
mapActions
([
'addCustomProcessMeta'
,
]),
async
edit
(
process
,
resolveProcess
)
{
this
.
selectedProcessNode
=
null
;
this
.
process
=
process
;
this
.
resolveProcess
=
resolveProcess
;
if
(
!
this
.
process
.
meta
.
subEntry
)
{
const
subProcessData
=
await
this
.
addSubProcessData
(
'entry'
,
{
x
:
10
,
y
:
10
,});
this
.
$set
(
this
.
process
.
meta
,
'subEntry'
,
subProcessData
.
uuid
);
}
this
.
updateSubProcess
();
this
.
measure
();
},
updateSubProcess
()
{
this
.
subProcessMap
=
{};
for
(
let
uuid
in
this
.
process
.
meta
.
sub
)
{
const
subData
=
this
.
process
.
meta
.
sub
[
uuid
];
this
.
addSubProcess
(
uuid
,
subData
);
}
},
addSubProcess
(
uuid
,
data
)
{
const
process
=
new
Process
(
this
.
process
,
data
,
this
.
resolveProcess
);
this
.
$set
(
this
.
subProcessMap
,
uuid
,
process
);
},
async
addSubProcessData
(
processId
,
pos
)
{
let
process
;
if
(
processId
===
'custom'
)
{
const
processMeta
=
await
this
.
addCustomProcessMeta
();
processId
=
processMeta
.
id
;
}
process
=
this
.
resolveProcess
(
processId
);
let
data
=
{
uuid
:
generateUUID
(),
meta
:
process
.
id
,
design
:
{
x
:
pos
.
x
,
y
:
pos
.
y
,
},
};
if
(
!
this
.
process
.
meta
.
hasOwnProperty
(
'sub'
))
{
this
.
$set
(
this
.
process
.
meta
,
'sub'
,
{});
}
this
.
$set
(
this
.
process
.
meta
.
sub
,
data
.
uuid
,
data
);
return
data
;
},
onDragOver
(
e
)
{
let
{
types
}
=
e
.
dataTransfer
;
if
(
types
.
includes
(
'process'
))
{
e
.
preventDefault
();
}
},
async
onDrop
(
e
)
{
const
processId
=
e
.
dataTransfer
.
getData
(
'process'
);
if
(
processId
===
'entry'
)
{
return
;
}
const
data
=
await
this
.
addSubProcessData
(
processId
,
{
x
:
e
.
offsetX
-
9
,
y
:
e
.
offsetY
,
});
this
.
addSubProcess
(
data
.
uuid
,
data
);
this
.
$nextTick
(()
=>
{
events
.
$emit
(
'update-dock-point-pos'
);
});
},
measure
()
{
const
{
x
,
y
}
=
this
.
$el
.
getBoundingClientRect
();
console
.
log
(
x
,
y
);
state
.
boardOffset
.
x
=
x
;
state
.
boardOffset
.
y
=
y
;
events
.
$emit
(
'update-dock-point-pos'
);
this
.
updateLines
();
this
.
$nextTick
(()
=>
{
events
.
$emit
(
'update-dock-point-pos'
);
this
.
updateLines
();
});
},
updateLines
()
{
this
.
lines
=
{};
for
(
let
id
in
this
.
p
rocessMap
)
{
const
process
=
this
.
processMap
[
id
];
for
(
let
uuid
in
this
.
subP
rocessMap
)
{
const
process
=
this
.
subProcessMap
[
uu
id
];
const
{
output
}
=
process
.
data
;
for
(
let
outputType
in
output
)
{
...
...
@@ -77,7 +153,7 @@
}
},
addLine
(
process
,
outputID
,
outputType
,
outputIndex
)
{
const
nextProcess
=
this
.
p
rocessMap
[
outputID
];
const
nextProcess
=
this
.
subP
rocessMap
[
outputID
];
if
(
nextProcess
)
{
this
.
$set
(
this
.
lines
,
state
.
lineID
,
{
id
:
state
.
lineID
,
...
...
@@ -120,7 +196,7 @@
this
.
lineDrawing
.
visible
=
false
;
state
.
drawing
=
false
;
if
(
state
.
targetUUID
)
{
if
(
state
.
targetUUID
&&
state
.
targetUUID
!==
this
.
processDrawing
.
uuid
)
{
this
.
processDrawing
.
output
[
this
.
pointDrawing
]
=
[
state
.
targetUUID
];
this
.
addLine
(
this
.
processDrawing
,
state
.
targetUUID
,
this
.
pointDrawing
,
0
);
...
...
@@ -131,6 +207,48 @@
const
{
prev
,
outputType
,
outputIndex
,
id
}
=
line
;
prev
.
output
[
outputType
].
splice
(
outputIndex
,
1
);
this
.
$delete
(
this
.
lines
,
id
);
},
onPointDelete
(
process
)
{
this
.
$delete
(
this
.
subProcessMap
,
process
.
uuid
);
this
.
$delete
(
this
.
process
.
meta
.
sub
,
process
.
uuid
);
for
(
let
id
in
this
.
lines
)
{
const
line
=
this
.
lines
[
id
];
const
{
prev
,
next
}
=
line
;
if
(
prev
===
process
||
next
===
process
)
{
this
.
onDeleteLine
(
line
);
}
}
},
editSubProcess
(
process
)
{
if
(
process
.
meta
.
type
!==
'builtin'
||
process
.
meta
.
sub
&&
Object
.
keys
(
process
.
meta
.
sub
).
length
>
0
)
{
this
.
$emit
(
'edit-process'
,
process
);
}
},
onClickProcessNode
(
process
,
uuid
)
{
for
(
let
key
in
this
.
$refs
)
{
if
(
key
.
startsWith
(
'pn_'
))
{
const
processNode
=
this
.
$refs
[
key
][
0
];
if
(
processNode
)
{
let
hint
=
'pn_'
+
uuid
===
key
;
processNode
.
setActive
(
hint
);
if
(
hint
&&
this
.
selectedProcessNode
!==
processNode
)
{
this
.
selectedProcessNode
=
processNode
;
this
.
$emit
(
'select-process-node'
,
process
);
}
}
}
}
},
updateProcessNode
()
{
if
(
this
.
selectedProcessNode
)
{
this
.
$nextTick
(()
=>
{
this
.
selectedProcessNode
.
updateSize
();
this
.
selectedProcessNode
.
updateDockPointPos
();
});
}
}
}
}
...
...
src/views/Editor/behavior-editor/Board/EditPath.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-breadcrumb
class=
"edit-path"
separator-class=
"el-icon-arrow-right"
>
<el-breadcrumb-item
v-for=
"(process, index) in processStack"
:key=
"index"
>
<span
v-if=
"index === processStack.length - 1"
>
{{
parseName
(
process
)
}}
</span>
<el-link
v-else
@
click=
"onClickItem(process, index)"
>
{{
parseName
(
process
)
}}
</el-link>
</el-breadcrumb-item>
</el-breadcrumb>
</
template
>
<
script
>
export
default
{
name
:
"EditPath"
,
props
:
[
'processStack'
],
watch
:
{
processStack
(
v
){
//console.log(v);
}
},
methods
:
{
parseName
(
process
){
return
process
.
data
.
alias
||
process
.
meta
.
name
;
},
onClickItem
(
process
,
index
){
this
.
$emit
(
'pop'
,
index
);
},
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/Board/Process.js
View file @
0a0442d1
...
...
@@ -3,28 +3,24 @@
*/
export
default
class
Process
{
constructor
(
parent
,
data
,
builtin
s
)
{
this
.
_
builtins
=
builtin
s
;
constructor
(
parent
,
data
,
resolveProces
s
)
{
this
.
_
resolveProcess
=
resolveProces
s
;
this
.
_parent
=
parent
;
this
.
_data
=
data
;
this
.
_
meta
=
typeof
data
.
meta
===
'string'
?
this
.
resolveMeta
(
data
.
meta
)
:
data
.
meta
;
this
.
meta
=
typeof
data
.
meta
===
'string'
?
this
.
resolveMeta
(
data
.
meta
)
:
data
.
meta
;
}
get
data
(){
return
this
.
_data
;
}
get
meta
(){
return
this
.
_meta
;
}
resolveMeta
(
name
)
{
let
meta
=
this
.
_meta
?
this
.
_meta
.
metas
[
name
]
:
null
;
resolveMeta
(
id
)
{
let
meta
=
this
.
meta
&&
this
.
meta
.
metas
?
this
.
meta
.
metas
[
id
]
:
null
;
if
(
!
meta
&&
this
.
_parent
)
{
meta
=
this
.
_parent
.
resolveMeta
(
name
);
meta
=
this
.
_parent
.
resolveMeta
(
id
);
}
if
(
!
meta
){
meta
=
this
.
_
builtins
[
name
]
;
meta
=
this
.
_
resolveProcess
(
id
)
;
}
return
meta
;
...
...
src/views/Editor/behavior-editor/Board/ProcessNode.vue
View file @
0a0442d1
<
template
>
<foreignObject
:x=
"data.design.x"
:y=
"data.design.y"
:width=
"width"
:height=
"height"
>
<div
ref=
"node"
class=
"node"
tabindex=
"0"
@
mousedown=
"onMouseDown"
@
mouseenter=
"onMouseEnter"
@
mouseleave=
"onMouseLeave"
>
<div
ref=
"node"
:class=
"
{active: active}" class="node" @mousedown="onMouseDown" @mouseenter="onMouseEnter"
@mouseleave="onMouseLeave" @click="onClick" @dblclick="onDblclick">
<div
class=
"header"
>
<span>
{{
data
.
alias
||
meta
.
name
}}
</span>
<span
class=
"title"
>
{{
data
.
alias
||
meta
.
name
}}
</span>
<i
v-if=
"meta.id !== 'entry'"
class=
"delete-button el-icon-delete"
@
click
.
stop=
"onClickDelete"
@
mousedown
.
stop
.
prevent
></i>
</div>
<div
class=
"body"
>
<div
class=
"field-item"
v-for=
"(param, key, index) in meta.options"
:key=
"index"
>
<span
class=
"key"
>
{{
key
}}
</span>
:
<span
class=
"value"
>
{{
data
.
options
[
key
]
}}
</span>
<span
class=
"key"
>
{{
param
.
alias
||
key
}}
</span>
:
<span
class=
"value"
>
{{
data
.
options
[
key
]
||
meta
.
options
[
key
].
default
}}
</span>
</div>
</div>
<div
ref=
"inputDock"
class=
"dock input"
>
...
...
@@ -28,30 +30,29 @@
import
DockPoint
from
"./DockPoint"
;
import
{
state
}
from
"./state"
;
import
events
from
"../../../../global-events"
;
//todo 容器坐标改变影响节点坐标
export
default
{
name
:
"ProcessNode"
,
components
:
{
DockPoint
},
props
:
[
'process'
],
data
()
{
this
.
prepare
();
const
inputMeta
=
this
.
process
.
meta
.
name
===
'E
ntry'
?
[]
:
[
'default'
];
const
inputMeta
=
this
.
process
.
meta
.
id
===
'e
ntry'
?
[]
:
[
'default'
];
return
{
width
:
130
,
height
:
100
,
inputMeta
,
active
:
false
,
}
},
created
()
{
},
mounted
()
{
let
bounds
=
this
.
$refs
.
node
.
getBoundingClientRect
();
this
.
width
=
bounds
.
width
+
9
;
this
.
height
=
bounds
.
height
;
this
.
updateSize
();
events
.
$on
(
'update-dock-point-pos'
,
this
.
updateDockPointPos
);
},
destroyed
()
{
events
.
$off
(
'update-dock-point-pos'
,
this
.
updateDockPointPos
);
},
computed
:
{
meta
()
{
return
this
.
process
.
meta
;
...
...
@@ -62,26 +63,39 @@
},
watch
:
{
process
(
v
)
{
}
this
.
active
=
false
;
this
.
prepare
();
this
.
updateSize
();
},
},
methods
:
{
prepare
()
{
let
{
design
,
options
}
=
this
.
process
.
data
;
let
{
design
,
options
,
output
}
=
this
.
process
.
data
;
if
(
!
design
)
{
this
.
$set
(
this
.
process
.
data
,
'design'
,
{});
design
=
this
.
process
.
data
.
design
;
}
if
(
!
options
)
{
this
.
$set
(
this
.
process
.
data
,
'options'
,
{});
options
=
this
.
process
.
data
.
options
;
}
if
(
!
design
.
x
)
{
this
.
$set
(
design
,
'x'
,
0
);
}
if
(
!
design
.
y
)
{
this
.
$set
(
design
,
'y'
,
0
);
}
if
(
!
options
)
{
this
.
$set
(
this
.
process
.
data
,
'options'
,
{});
}
if
(
!
output
)
{
this
.
$set
(
this
.
process
.
data
,
'output'
,
{});
}
},
onClick
(
e
)
{
this
.
$emit
(
'click'
,
e
);
},
onDblclick
(
e
)
{
this
.
$emit
(
'dblclick'
,
e
);
},
setActive
(
active
){
this
.
active
=
active
;
},
onMouseEnter
(
e
)
{
if
(
state
.
drawing
&&
this
.
meta
.
id
!==
'entry'
)
{
...
...
@@ -121,6 +135,13 @@
this
.
$emit
(
'change-position'
,
this
,
this
);
}
},
updateSize
(){
this
.
$nextTick
(()
=>
{
let
bounds
=
this
.
$refs
.
node
.
getBoundingClientRect
();
this
.
width
=
bounds
.
width
+
18
;
this
.
height
=
bounds
.
height
;
});
},
updateDockPointPos
()
{
const
{
x
:
dx
,
y
:
dy
}
=
this
.
process
.
data
.
design
;
const
{
x
:
offX
,
y
:
offY
}
=
state
.
boardOffset
;
...
...
@@ -138,7 +159,7 @@
let
dockPoint
=
container
.
children
[
i
];
const
{
x
,
y
}
=
dockPoint
.
getBoundingClientRect
();
posArr
.
push
({
x
:
x
-
dx
-
offX
,
x
:
x
-
dx
-
offX
+
4.5
,
y
:
y
-
dy
-
offY
,
});
}
...
...
@@ -160,6 +181,9 @@
this
.
$emit
(
'down-point'
,
e
,
this
.
data
,
point
);
}
},
onClickDelete
()
{
this
.
$emit
(
'delete'
,
this
.
data
);
},
}
}
</
script
>
...
...
src/views/Editor/behavior-editor/Board/ToolTip.vue
View file @
0a0442d1
...
...
@@ -52,5 +52,6 @@
padding
:
5px
;
border-radius
:
5px
;
pointer-events
:
none
;
z-index
:
2
;
}
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/MetaEditorDialog.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-dialog
:title=
"$t('Meta Editor')"
width=
"80%"
:visible
.
sync=
"visible"
:close-on-click-modal=
"false"
:append-to-body=
"true"
>
<div
class=
"meta-editor-wrapper"
>
<el-form
:inline=
"true"
class=
"info-editor"
size=
"mini"
>
<template
v-if=
"meta"
>
<el-form-item
label=
"ID"
>
<el-input
v-model=
"meta.id"
placeholder=
"ID"
:readonly=
"!editable"
/>
</el-form-item>
<el-form-item
label=
"Name"
>
<el-input
v-model=
"meta.name"
placeholder=
"Name"
:readonly=
"!editable"
/>
</el-form-item>
</
template
>
</el-form>
<el-form
class=
"info-editor"
size=
"mini"
>
<
template
v-if=
"meta"
>
<el-form-item
label=
"Options"
>
<el-link
:underline=
"false"
@
click=
"onClickEditOptions"
:disabled=
"!editable"
>
<template
v-if=
"Object.keys(meta.options).length"
>
<el-tag
type=
"success"
size=
"mini"
v-for=
"(option, key) in meta.options"
:key=
"key"
>
{{
key
}}
</el-tag>
</
template
>
<
template
v-else
>
Nothing
</
template
>
</el-link>
</el-form-item>
<el-form-item
label=
"Output"
>
<div
style=
"display: flex;flex: 1;"
>
<el-select
style=
"flex: 1;"
v-model=
"meta.output"
:disabled=
"!editable"
allow-create
filterable
multiple
placeholder=
"Output"
/>
</div>
</el-form-item>
</template>
</el-form>
<el-input
v-if=
"meta"
class=
"script-editor"
:readonly=
" !editable"
type=
"textarea"
v-model=
"meta.script"
></el-input>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<div
class=
"button-bar"
>
<el-button
size=
"mini"
plain
@
click=
"cancel"
>
Cancel
</el-button>
<el-button
size=
"mini"
plain
@
click=
"save"
>
Save
</el-button>
</div>
</div>
<options-editor-dialog
ref=
"optionsEditorDialog"
/>
</el-dialog>
</template>
<
script
>
import
ElFormItem
from
"./editors/form-item"
;
import
OptionsEditorDialog
from
"./OptionsEditorDialog"
;
export
default
{
name
:
"MetaEditorDialog"
,
components
:
{
OptionsEditorDialog
,
ElFormItem
},
data
()
{
return
{
visible
:
false
,
meta
:
null
,
optionsEditorVisible
:
false
,
}
},
computed
:
{
editable
()
{
return
this
.
meta
&&
this
.
meta
.
type
!==
'builtin'
;
},
options
()
{
return
Object
.
keys
(
this
.
meta
.
options
).
join
(
','
)
},
},
methods
:
{
edit
(
meta
)
{
this
.
visible
=
true
;
this
.
meta
=
JSON
.
parse
(
JSON
.
stringify
(
meta
));
},
onClickEditOptions
()
{
this
.
$refs
.
optionsEditorDialog
.
edit
(
this
.
meta
.
options
);
},
save
()
{
this
.
$emit
(
'input'
,
this
.
meta
);
this
.
visible
=
false
;
},
cancel
(){
this
.
visible
=
false
;
}
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/OptionsEditorDialog.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-dialog
:title=
"$t('Options Editor')"
width=
"80%"
:visible
.
sync=
"visible"
:close-on-click-modal=
"false"
:append-to-body=
"true"
>
<div
class=
"options-editor-dialog"
>
<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"
view-class=
"scrollbar-view"
>
<div
class=
"wrapper"
>
<el-table
:data=
"options"
style=
"width: 100%"
>
<el-table-column
label=
"Type"
width=
"100"
>
<template
slot-scope=
"scope"
>
<el-select
v-model=
"scope.row.option.type"
size=
"mini"
>
<el-option
v-for=
"type in types"
:key=
"type"
:label=
"type"
:value=
"type"
>
</el-option>
</el-select>
</
template
>
</el-table-column>
<el-table-column
label=
"Key"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<el-input
v-model=
"scope.row.key"
size=
"mini"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"Alias"
width=
"100"
>
<
template
slot-scope=
"scope"
>
<el-input
v-model=
"scope.row.option.alias"
size=
"mini"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"Default"
>
<
template
slot-scope=
"scope"
>
<el-input
v-if=
"scope.row.option.type === 'string' || scope.row.option.type === 'enum'"
class=
"default-value"
v-model=
"scope.row.option.default"
size=
"mini"
placeholder=
"Default"
/>
<el-input-number
v-if=
"scope.row.option.type === 'number'"
controls-position=
"right"
class=
"default-value"
v-model=
"scope.row.option.default"
size=
"mini"
placeholder=
"Default"
/>
<el-switch
v-if=
"scope.row.option.type === 'boolean'"
class=
"default-value"
v-model=
"scope.row.option.default"
size=
"mini"
/>
</
template
>
</el-table-column>
<el-table-column
label=
""
width=
"70"
>
<
template
slot-scope=
"scope"
>
<div
class=
"operate-bar"
>
<el-popover
class=
"edit-enum-button"
trigger=
"click"
>
<div
class=
"edit-enum-popover"
>
<el-select
size=
"mini"
allow-create
multiple
filterable
v-model=
"scope.row.option.enum"
/>
</div>
<el-button
slot=
"reference"
class=
"edit-button"
size=
"mini"
circle
icon=
"el-icon-edit"
plain
:disabled=
"scope.row.option.type!=='enum'"
@
click=
"editEnum(scope)"
/>
</el-popover>
<el-button
class=
"delete-button"
size=
"mini"
circle
icon=
"el-icon-minus"
type=
"danger"
plain
@
click=
"deleteItem(scope.$index)"
/>
</div>
</
template
>
</el-table-column>
</el-table>
</div>
</el-scrollbar>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<div
class=
"button-bar"
>
<el-button
size=
"mini"
plain
@
click=
"cancel"
>
Cancel
</el-button>
<el-button
size=
"mini"
plain
@
click=
"save"
>
Save
</el-button>
</div>
</div>
</el-dialog>
</template>
<
script
>
export
default
{
name
:
"OptionsEditorDialog"
,
data
()
{
return
{
visible
:
false
,
originOptions
:
null
,
copiedOptions
:
null
,
options
:
[],
types
:
[
'boolean'
,
'string'
,
'number'
,
'enum'
,
],
}
},
methods
:
{
edit
(
options
)
{
this
.
visible
=
true
;
this
.
originOptions
=
options
;
this
.
copiedOptions
=
JSON
.
parse
(
JSON
.
stringify
(
options
));
this
.
options
.
splice
(
0
);
for
(
let
key
in
this
.
copiedOptions
)
{
let
option
=
this
.
copiedOptions
[
key
];
this
.
options
.
push
({
key
,
option
,
})
}
},
save
(){
let
keys
=
Object
.
keys
(
this
.
originOptions
);
for
(
let
key
of
keys
)
{
this
.
$delete
(
this
.
originOptions
,
key
);
}
for
(
let
item
of
this
.
options
){
if
(
item
.
key
){
this
.
$set
(
this
.
originOptions
,
item
.
key
,
item
.
option
);
}
}
this
.
visible
=
false
;
},
cancel
(){
this
.
visible
=
false
;
},
editEnum
(
item
){
},
addItem
(){
this
.
options
.
push
({
option
:
{
type
:
'string'
,
}
})
},
deleteItem
(
index
){
this
.
options
.
splice
(
index
,
1
);
},
},
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/ProcessList.vue
View file @
0a0442d1
<
template
>
<div>
<el-tree
v-model=
"data"
>
<div
class=
"process-tree"
>
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
>
<el-tree
:data=
"data"
:props=
"defaultProps"
empty-text=
""
>
<div
slot-scope=
"
{ node, data }" class="process-tree-node">
<div
class=
"node-name"
>
<span
:draggable=
"draggable(data)"
@
dragstart
.
stop=
"dragProcessStart(data, $event)"
>
{{
data
.
name
}}
</span>
</div>
</el-tree>
<el-dropdown
v-if=
"data.type !== 'builtin' && !data.hasOwnProperty('children') && data.id !== 'custom'"
class=
"more-button"
size=
"mini"
trigger=
"click"
@
command=
"(command)=>
{onMoreMenu(command, data, node)}">
<el-link
icon=
"el-icon-more"
:underline=
"false"
@
click
.
stop
/>
<el-dropdown-menu
slot=
"dropdown"
>
<el-dropdown-item
command=
"edit"
>
{{
$t
(
'Edit'
)
}}
</el-dropdown-item>
<el-dropdown-item
command=
"delete"
>
{{
$t
(
'Delete'
)
}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-tree>
</el-scrollbar>
</div>
</
template
>
<
script
>
...
...
@@ -14,6 +32,32 @@
props
:
[
'data'
,
],
data
()
{
return
{
defaultProps
:
{
children
:
'children'
,
label
:
'name'
}
}
},
methods
:
{
draggable
(
data
)
{
return
!
data
.
hasOwnProperty
(
'children'
);
},
dragProcessStart
(
data
,
event
)
{
event
.
dataTransfer
.
setData
(
'process'
,
data
.
id
);
},
onMoreMenu
(
command
,
data
,
node
)
{
switch
(
command
)
{
case
'edit'
:
this
.
$emit
(
'edit-meta'
,
data
);
break
;
case
'delete'
:
this
.
$emit
(
'delete-meta'
,
data
);
break
;
}
}
},
}
</
script
>
...
...
src/views/Editor/behavior-editor/Properties.vue
deleted
100644 → 0
View file @
bb3df274
<
template
>
<div
class=
"properties"
>
<span>
Properties
</span>
</div>
</
template
>
<
script
>
export
default
{
name
:
"Properties"
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/PropertiesEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<div
class=
"wrapper"
v-if=
"process"
>
<el-input
v-model=
"process.data.alias"
clearable
:placeholder=
"process.meta.name"
size=
"mini"
>
<template
slot=
"prepend"
>
{{
$t
(
'Name'
)
}}
</
template
>
</el-input>
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
view-class=
"scrollbar-view"
>
<el-form
v-model=
"process"
size=
"mini"
label-width=
"80px"
label-position=
"left"
@
submit
.
prevent
>
<component
v-for=
"(property, key) in process.meta.options"
:is=
"getEditor(property)"
v-model=
"process.data.options[key]"
:propertyName=
"key"
:property=
"property"
:container=
"process"
:key=
"key"
/>
</el-form>
</el-scrollbar>
</div>
</template>
<
script
>
import
NumberEditor
from
"./editors/NumberEditor"
;
import
StringEditor
from
"./editors/StringEditor"
;
import
EnumEditor
from
"./editors/EnumEditor"
;
import
BooleanEditor
from
"./editors/BooleanEditor"
;
const
editorMapping
=
{
number
:
'NumberEditor'
,
string
:
'StringEditor'
,
enum
:
'EnumEditor'
,
boolean
:
'BooleanEditor'
,
};
export
default
{
name
:
"PropertiesEditor"
,
components
:
{
BooleanEditor
,
EnumEditor
,
NumberEditor
,
StringEditor
},
data
()
{
return
{
process
:
null
,
}
},
methods
:
{
edit
(
process
)
{
this
.
process
=
process
;
},
getEditor
(
property
)
{
return
editorMapping
[
property
.
type
];
},
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/editors/BooleanEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<editor-wrapper
:property=
"property"
:propertyName=
"propertyName"
>
<el-switch
:value=
"editValue"
@
input=
"onInput"
class=
"picker"
></el-switch>
</editor-wrapper>
</
template
>
<
script
>
import
EditorWrapper
from
"./EditorWrapper"
;
export
default
{
name
:
"BooleanEditor"
,
components
:
{
EditorWrapper
},
props
:
[
'value'
,
'container'
,
'property'
,
'propertyName'
],
data
()
{
return
{}
},
computed
:
{
editValue
()
{
return
this
.
value
===
undefined
?
this
.
property
.
default
:
this
.
value
;
},
},
methods
:
{
onInput
(
v
)
{
if
(
v
!==
this
.
value
)
{
this
.
$emit
(
'input'
,
v
,
this
.
container
,
this
.
propertyName
,
this
.
value
);
}
}
},
}
</
script
>
<
style
scoped
>
.picker
{
float
:
right
;
margin-top
:
4px
;
}
</
style
>
src/views/Editor/behavior-editor/editors/ColorEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<editor-wrapper
:property=
"property"
class=
"color-editor-container"
>
<el-color-picker
class=
"picker"
:value=
"editValue"
@
input=
"onInput"
show-alpha
:predefine=
"predefineColors"
>
</el-color-picker>
</editor-wrapper>
</
template
>
<
script
>
import
EditorWrapper
from
"./EditorWrapper"
;
export
default
{
name
:
"ColorEditor"
,
components
:
{
EditorWrapper
,},
props
:
[
'component'
,
'value'
,
'property'
],
data
()
{
return
{
predefineColors
:
[
'#ff4500'
,
'#ff8c00'
,
'#ffd700'
,
'#90ee90'
,
'#00ced1'
,
'#1e90ff'
,
'#c71585'
,
'rgba(255, 69, 0, 0.68)'
,
'rgb(255, 120, 0)'
,
'hsv(51, 100, 98)'
,
'hsva(120, 40, 94, 0.5)'
,
'hsl(181, 100%, 37%)'
,
'hsla(209, 100%, 56%, 0.73)'
,
'#c7158577'
]
}
},
computed
:
{
editValue
()
{
return
this
.
value
===
undefined
?
this
.
property
.
defaultValue
:
this
.
value
;
},
},
methods
:
{
onInput
(
v
)
{
if
(
v
!==
this
.
value
)
{
this
.
$emit
(
'input'
,
v
,
this
.
component
,
this
.
property
.
name
,
this
.
value
);
}
}
},
}
</
script
>
<
style
scoped
>
.color-editor-container
{
height
:
29px
;
overflow
:
hidden
;
}
.picker
{
float
:
right
;
}
</
style
>
src/views/Editor/behavior-editor/editors/EditorWrapper.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-form-item
class=
"editor-wrapper"
:label=
"property.alias || propertyName"
content-float=
"right"
:content-width=
"contentWidth"
:labelOffsetTop=
"labelOffsetTop"
>
<slot></slot>
</el-form-item>
</
template
>
<
script
>
import
camelcase
from
'camelcase'
import
ElFormItem
from
"./form-item"
;
export
default
{
name
:
"EditorWrapper"
,
components
:
{
ElFormItem
},
props
:
{
property
:
Object
,
propertyName
:
String
,
contentWidth
:
{
type
:
String
,
default
:
'65%'
,
},
labelOffsetTop
:
{
type
:
Number
,
default
:
0
,
},
},
computed
:
{
},
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/editors/EnumEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<editor-wrapper
:property=
"property"
:propertyName=
"propertyName"
>
<enum-select
:value=
"value"
@
input=
"onInput"
:property=
"property"
></enum-select>
</editor-wrapper>
</
template
>
<
script
>
import
EnumSelect
from
"./EnumEditor/EnumSelect"
;
import
EditorWrapper
from
"./EditorWrapper"
;
export
default
{
name
:
"EnumEditor"
,
components
:
{
EnumSelect
,
EditorWrapper
,},
props
:
[
'value'
,
'container'
,
'property'
,
'propertyName'
],
methods
:
{
onInput
(
v
,
oldValue
){
if
(
v
!==
this
.
value
){
this
.
$emit
(
'input'
,
v
,
this
.
container
,
this
.
propertyName
,
oldValue
);
}
}
},
}
</
script
>
<
style
scoped
>
</
style
>
src/views/Editor/behavior-editor/editors/EnumEditor/EnumSelect.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-select
:value=
"editValue"
@
input=
"onInput"
:placeholder=
"property.default"
class=
"el-select"
>
<el-option
v-for=
"(item, key) in property.enum"
:key=
"item"
:label=
"item"
:value=
"item"
>
<span>
{{
item
}}
</span>
<span
class=
"comment"
></span>
</el-option>
</el-select>
</
template
>
<
script
>
export
default
{
name
:
"EnumSelect"
,
props
:
[
'value'
,
'property'
],
data
(){
return
{
}
},
computed
:
{
editValue
(){
return
this
.
value
||
this
.
property
.
default
;
},
},
methods
:
{
onInput
(
v
){
if
(
v
!==
this
.
value
){
this
.
$emit
(
'input'
,
v
,
this
.
value
);
}
}
},
}
</
script
>
<
style
scoped
>
.el-select
{
width
:
100%
;
}
.comment
{
float
:
right
;
color
:
darkgray
;
font-size
:
12px
;
}
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/editors/EventEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<el-form-item
class=
"wrapper editor-event-wrapper"
label-width=
"0"
>
<div
class=
"header"
>
<span
class=
"event-name"
>
{{
property
.
name
}}
</span>
<el-button
icon=
"el-icon-plus"
circle
plain
type=
"primary"
class=
"mini-button"
@
click=
"onClickAdd"
></el-button>
</div>
<div
class=
"list"
v-if=
"editValue"
>
<div
class=
"event-item"
v-for=
"(item, index) in editValue"
>
<div
class=
"method-path"
>
<entity-linker
class=
"entity-linker"
v-model=
"item.entity"
@
input=
"onEntityChange(item, index)"
></entity-linker>
<el-popover
popper-class=
"tooltip-popover"
class=
"method-name-container"
placement=
"top"
trigger=
"hover"
:disabled=
"getMethodName(item, index).length === 0"
:open-delay=
"400"
:content=
"getMethodName(item, index)"
>
<div
slot=
"reference"
class=
"method-menu editor-event-method-menu"
@
click=
"onShowMethodMenu(item, index)"
>
{{
getMethodName
(
item
,
index
)
}}
</div>
</el-popover>
</div>
<div
class=
"params-box"
>
<el-form-item
class=
"param-input"
label=
"param"
label-width=
"45px"
>
<el-input
v-model=
"item.param"
></el-input>
</el-form-item>
<el-button
icon=
"el-icon-close"
@
click=
"onClickDelete(item, index)"
circle
plain
class=
"mini-button"
type=
"danger"
></el-button>
</div>
</div>
</div>
</el-form-item>
</
template
>
<
script
>
import
ElFormItem
from
"./form-item"
;
import
EntityLinker
from
"./EntityEditor/EntityLinker"
;
import
{
getUUIDFromLink
}
from
"../../../../../utils"
;
import
{
getCurrentProject
,
getCurrentScene
}
from
"../../../../../editor"
;
import
{
showMethodMenu
}
from
"../../../../../menus/index"
;
import
{
getClassDeclare
}
from
"../../../../../components-manager"
;
export
default
{
name
:
"EventEditor"
,
components
:
{
EntityLinker
,
ElFormItem
},
props
:
[
'component'
,
'value'
,
'property'
],
data
()
{
this
.
storeOldValue
(
this
.
value
);
return
{
methodName
:
''
,
editValue
:
this
.
value
,
}
},
watch
:
{
value
()
{
this
.
editValue
=
this
.
value
;
this
.
storeOldValue
();
},
},
methods
:
{
storeOldValue
(
v
){
let
value
=
v
||
this
.
editValue
;
this
.
oldValue
=
value
===
undefined
?
undefined
:
JSON
.
parse
(
JSON
.
stringify
(
value
));
},
onShowMethodMenu
(
item
,
index
)
{
let
entity
=
this
.
getEntity
(
item
.
entity
);
showMethodMenu
(
entity
,
event
.
x
,
event
.
y
,
index
,
this
.
onSelectMethod
);
},
onSelectMethod
(
index
,
componentIndex
,
method
)
{
let
item
=
this
.
editValue
[
index
];
if
(
componentIndex
<
0
){
item
.
component
=
null
;
item
.
method
=
null
;
}
else
{
item
.
component
=
componentIndex
;
item
.
method
=
method
;
}
this
.
emitInput
();
},
onEntityChange
(
item
,
index
)
{
item
.
component
=
null
;
item
.
method
=
null
;
this
.
emitInput
();
},
onClickAdd
()
{
if
(
this
.
editValue
===
undefined
)
{
this
.
editValue
=
[];
}
this
.
editValue
.
push
({
entity
:
null
,
component
:
null
,
method
:
null
,
});
this
.
emitInput
();
},
onClickDelete
(
item
,
index
)
{
this
.
editValue
.
splice
(
index
,
1
);
this
.
emitInput
();
},
emitInput
()
{
this
.
$emit
(
'input'
,
this
.
editValue
.
length
>
0
?
this
.
editValue
:
undefined
,
this
.
component
,
this
.
property
.
name
,
this
.
oldValue
);
},
getEntity
(
link
)
{
if
(
link
)
{
let
{
type
,
uuid
}
=
getUUIDFromLink
(
link
);
if
(
type
===
'entity'
)
{
let
_entity
=
getCurrentScene
().
findEntityByUUID
(
uuid
);
if
(
_entity
)
{
return
_entity
;
}
}
}
},
getMethodName
({
entity
:
entityLink
,
component
,
method
},
index
)
{
let
entity
=
this
.
getEntity
(
entityLink
);
if
(
entity
)
{
let
comp
=
entity
.
components
[
component
];
if
(
comp
)
{
let
declare
=
getClassDeclare
(
comp
.
script
);
return
declare
.
className
+
'.'
+
method
;
}
return
''
;
}
else
{
return
''
;
}
}
}
}
</
script
>
<
style
scoped
>
.wrapper
{
border-radius
:
3px
;
width
:
100%
;
height
:
100%
;
padding
:
5px
;
}
.header
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
}
.event-name
{
}
.list
{
}
.event-item
{
display
:
flex
;
flex-direction
:
column
;
margin
:
3px
0
;
}
.method-path
{
display
:
flex
;
align-items
:
flex-end
;
margin-bottom
:
5px
;
}
.params-box
{
display
:
flex
;
align-items
:
center
;
}
.param-input
{
flex
:
1
;
margin-right
:
5px
;
}
.entity-linker
{
flex
:
1
;
}
.method-menu
{
height
:
28px
;
padding
:
0
3px
;
border-radius
:
3px
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
overflow
:
hidden
;
}
.method-menu
:focus
{
outline
:
none
;
}
.method-name-container
{
width
:
120px
;
margin
:
0
5px
;
}
.mini-button
{
padding
:
3px
!important
;
}
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/editors/NumberEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<editor-wrapper
:property=
"property"
:propertyName=
"propertyName"
>
<el-input-number
:value=
"editValue"
@
input=
"onInput"
controls-position=
"right"
:placeholder=
"defaultValue"
></el-input-number>
</editor-wrapper>
</
template
>
<
script
>
import
EditorWrapper
from
"./EditorWrapper"
;
import
{
getEditorDefaultValue
}
from
"../../../../utils"
;
export
default
{
name
:
"NumberEditor"
,
components
:
{
EditorWrapper
,},
props
:
[
'value'
,
'container'
,
'property'
,
'propertyName'
],
computed
:
{
editValue
()
{
return
this
.
value
===
undefined
?
this
.
property
.
default
:
this
.
value
;
},
defaultValue
(){
return
getEditorDefaultValue
(
this
.
property
);
},
},
methods
:
{
onInput
(
v
)
{
if
(
v
!==
this
.
value
){
this
.
$emit
(
'input'
,
v
,
this
.
container
,
this
.
propertyName
,
this
.
value
);
}
}
},
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/editors/RawEditor.vue
0 → 100644
View file @
0a0442d1
<
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
>
src/views/Editor/behavior-editor/editors/StringEditor.vue
0 → 100644
View file @
0a0442d1
<
template
>
<editor-wrapper
:property=
"property"
:propertyName=
"propertyName"
>
<div
style=
"display: flex;flex: 1;"
>
<el-popover
placement=
"top"
popper-class=
"input-area-popover"
class=
"string-name-container"
trigger=
"manual"
width=
"400"
v-model=
"popoverVisible"
>
<div>
<el-input
type=
"textarea"
v-model=
"popoverEditValue"
:placeholder=
"defaultValue"
:rows=
"6"
>
</el-input>
<div
class=
"bottom-bar"
>
<el-button
@
click=
"onClean"
type=
"danger"
plain
>
Clean
</el-button>
<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=
"onChange"
:placeholder=
"defaultValue"
/>
</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
EditorWrapper
from
"./EditorWrapper"
;
import
{
getEditorDefaultValue
}
from
"../../../../utils"
;
export
default
{
name
:
"StringEditor"
,
components
:
{
EditorWrapper
,},
props
:
[
'value'
,
'container'
,
'property'
,
'propertyName'
],
data
()
{
return
{
editValue
:
this
.
value
,
popoverEditValue
:
this
.
value
,
popoverVisible
:
false
,
}
},
computed
:
{
editButtonIcon
()
{
return
this
.
popoverVisible
?
'el-icon-check'
:
'el-icon-edit'
;
},
defaultValue
()
{
return
getEditorDefaultValue
(
this
.
property
);
}
},
watch
:
{
value
(
v
)
{
this
.
editValue
=
v
;
},
popoverVisible
(
v
)
{
if
(
v
)
{
this
.
popoverEditValue
=
this
.
editValue
;
}
}
},
methods
:
{
onClickEdit
()
{
this
.
popoverVisible
=
!
this
.
popoverVisible
;
},
onClickClean
()
{
this
.
$emit
(
'input'
,
undefined
,
this
.
container
,
this
.
propertyName
,
this
.
value
);
},
onChange
()
{
this
.
$emit
(
'input'
,
this
.
editValue
,
this
.
container
,
this
.
propertyName
,
this
.
value
);
},
onConfirm
()
{
this
.
editValue
=
this
.
popoverEditValue
;
this
.
onChange
();
this
.
popoverVisible
=
false
;
},
onCancel
()
{
this
.
$emit
(
'cancel'
);
this
.
popoverVisible
=
false
;
},
onClean
()
{
this
.
popoverEditValue
=
''
;
},
},
}
</
script
>
<
style
scoped
>
.bottom-bar
{
margin-top
:
5px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
}
.string-name-container
{
flex
:
1
;
}
</
style
>
src/views/Editor/behavior-editor/editors/form-item.vue
0 → 100644
View file @
0a0442d1
<
template
>
<div
class=
"el-form-item"
:class=
"[
{
'el-form-item--feedback': elForm
&&
elForm.statusIcon,
'is-error': validateState === 'error',
'is-validating': validateState === 'validating',
'is-success': validateState === 'success',
'is-required': isRequired || required,
'is-no-asterisk': elForm
&&
elForm.hideRequiredAsterisk
},
sizeClass ? 'el-form-item--' + sizeClass : ''
]">
<label
:for=
"labelFor"
class=
"el-form-item__label"
:style=
"labelStyle"
v-if=
"label || $slots.label"
>
<slot
name=
"label"
>
{{
label
+
form
.
labelSuffix
}}
</slot>
</label>
<div
class=
"el-form-item__content"
:style=
"contentStyle"
>
<slot></slot>
<transition
name=
"el-zoom-in-top"
>
<slot
v-if=
"validateState === 'error' && showMessage && form.showMessage"
name=
"error"
:error=
"validateMessage"
>
<div
class=
"el-form-item__error"
:class=
"
{
'el-form-item__error--inline': typeof inlineMessage === 'boolean'
? inlineMessage
: (elForm
&&
elForm.inlineMessage || false)
}"
>
{{
validateMessage
}}
</div>
</slot>
</transition>
</div>
</div>
</
template
>
<
script
>
import
AsyncValidator
from
'async-validator'
;
import
emitter
from
'element-ui/src/mixins/emitter'
;
import
objectAssign
from
'element-ui/src/utils/merge'
;
import
{
noop
,
getPropByPath
}
from
'element-ui/src/utils/util'
;
export
default
{
name
:
'ElFormItem'
,
componentName
:
'ElFormItem'
,
mixins
:
[
emitter
],
provide
()
{
return
{
elFormItem
:
this
};
},
inject
:
[
'elForm'
],
props
:
{
label
:
String
,
labelWidth
:
String
,
prop
:
String
,
required
:
{
type
:
Boolean
,
default
:
undefined
},
rules
:
[
Object
,
Array
],
error
:
String
,
validateStatus
:
String
,
for
:
String
,
inlineMessage
:
{
type
:
[
String
,
Boolean
],
default
:
''
},
showMessage
:
{
type
:
Boolean
,
default
:
true
},
size
:
String
,
labelOffsetTop
:
{
type
:
Number
,
default
:
0
,
},
},
watch
:
{
error
:
{
immediate
:
true
,
handler
(
value
)
{
this
.
validateMessage
=
value
;
this
.
validateState
=
value
?
'error'
:
''
;
}
},
validateStatus
(
value
)
{
this
.
validateState
=
value
;
}
},
computed
:
{
labelFor
()
{
return
this
.
for
||
this
.
prop
;
},
labelStyle
()
{
const
ret
=
{
marginTop
:
this
.
labelOffsetTop
+
'px'
};
if
(
this
.
form
.
labelPosition
===
'top'
)
return
ret
;
const
labelWidth
=
this
.
labelWidth
||
this
.
form
.
labelWidth
;
if
(
labelWidth
)
{
ret
.
width
=
labelWidth
;
}
return
ret
;
},
contentStyle
()
{
const
ret
=
{};
const
label
=
this
.
label
;
if
(
this
.
form
.
labelPosition
===
'top'
||
this
.
form
.
inline
)
return
ret
;
if
(
!
label
&&
!
this
.
labelWidth
&&
this
.
isNested
)
return
ret
;
const
labelWidth
=
this
.
labelWidth
||
this
.
form
.
labelWidth
;
if
(
labelWidth
)
{
ret
.
marginLeft
=
labelWidth
;
}
return
ret
;
},
form
()
{
let
parent
=
this
.
$parent
;
let
parentName
=
parent
.
$options
.
componentName
;
while
(
parentName
!==
'ElForm'
)
{
if
(
parentName
===
'ElFormItem'
)
{
this
.
isNested
=
true
;
}
parent
=
parent
.
$parent
;
parentName
=
parent
.
$options
.
componentName
;
}
return
parent
;
},
fieldValue
()
{
const
model
=
this
.
form
.
model
;
if
(
!
model
||
!
this
.
prop
)
{
return
;
}
let
path
=
this
.
prop
;
if
(
path
.
indexOf
(
':'
)
!==
-
1
)
{
path
=
path
.
replace
(
/:/
,
'.'
);
}
return
getPropByPath
(
model
,
path
,
true
).
v
;
},
isRequired
()
{
let
rules
=
this
.
getRules
();
let
isRequired
=
false
;
if
(
rules
&&
rules
.
length
)
{
rules
.
every
(
rule
=>
{
if
(
rule
.
required
)
{
isRequired
=
true
;
return
false
;
}
return
true
;
});
}
return
isRequired
;
},
_formSize
()
{
return
this
.
elForm
.
size
;
},
elFormItemSize
()
{
return
this
.
size
||
this
.
_formSize
;
},
sizeClass
()
{
return
this
.
elFormItemSize
||
(
this
.
$ELEMENT
||
{}).
size
;
}
},
data
()
{
return
{
validateState
:
''
,
validateMessage
:
''
,
validateDisabled
:
false
,
validator
:
{},
isNested
:
false
};
},
methods
:
{
validate
(
trigger
,
callback
=
noop
)
{
this
.
validateDisabled
=
false
;
const
rules
=
this
.
getFilteredRule
(
trigger
);
if
((
!
rules
||
rules
.
length
===
0
)
&&
this
.
required
===
undefined
)
{
callback
();
return
true
;
}
this
.
validateState
=
'validating'
;
const
descriptor
=
{};
if
(
rules
&&
rules
.
length
>
0
)
{
rules
.
forEach
(
rule
=>
{
delete
rule
.
trigger
;
});
}
descriptor
[
this
.
prop
]
=
rules
;
const
validator
=
new
AsyncValidator
(
descriptor
);
const
model
=
{};
model
[
this
.
prop
]
=
this
.
fieldValue
;
validator
.
validate
(
model
,
{
firstFields
:
true
},
(
errors
,
invalidFields
)
=>
{
this
.
validateState
=
!
errors
?
'success'
:
'error'
;
this
.
validateMessage
=
errors
?
errors
[
0
].
message
:
''
;
callback
(
this
.
validateMessage
,
invalidFields
);
this
.
elForm
&&
this
.
elForm
.
$emit
(
'validate'
,
this
.
prop
,
!
errors
,
this
.
validateMessage
||
null
);
});
},
clearValidate
()
{
this
.
validateState
=
''
;
this
.
validateMessage
=
''
;
this
.
validateDisabled
=
false
;
},
resetField
()
{
this
.
validateState
=
''
;
this
.
validateMessage
=
''
;
let
model
=
this
.
form
.
model
;
let
value
=
this
.
fieldValue
;
let
path
=
this
.
prop
;
if
(
path
.
indexOf
(
':'
)
!==
-
1
)
{
path
=
path
.
replace
(
/:/
,
'.'
);
}
let
prop
=
getPropByPath
(
model
,
path
,
true
);
this
.
validateDisabled
=
true
;
if
(
Array
.
isArray
(
value
))
{
prop
.
o
[
prop
.
k
]
=
[].
concat
(
this
.
initialValue
);
}
else
{
prop
.
o
[
prop
.
k
]
=
this
.
initialValue
;
}
this
.
broadcast
(
'ElTimeSelect'
,
'fieldReset'
,
this
.
initialValue
);
},
getRules
()
{
let
formRules
=
this
.
form
.
rules
;
const
selfRules
=
this
.
rules
;
const
requiredRule
=
this
.
required
!==
undefined
?
{
required
:
!!
this
.
required
}
:
[];
const
prop
=
getPropByPath
(
formRules
,
this
.
prop
||
''
);
formRules
=
formRules
?
(
prop
.
o
[
this
.
prop
||
''
]
||
prop
.
v
)
:
[];
return
[].
concat
(
selfRules
||
formRules
||
[]).
concat
(
requiredRule
);
},
getFilteredRule
(
trigger
)
{
const
rules
=
this
.
getRules
();
return
rules
.
filter
(
rule
=>
{
if
(
!
rule
.
trigger
||
trigger
===
''
)
return
true
;
if
(
Array
.
isArray
(
rule
.
trigger
))
{
return
rule
.
trigger
.
indexOf
(
trigger
)
>
-
1
;
}
else
{
return
rule
.
trigger
===
trigger
;
}
}).
map
(
rule
=>
objectAssign
({},
rule
));
},
onFieldBlur
()
{
this
.
validate
(
'blur'
);
},
onFieldChange
()
{
if
(
this
.
validateDisabled
)
{
this
.
validateDisabled
=
false
;
return
;
}
this
.
validate
(
'change'
);
}
},
mounted
()
{
if
(
this
.
prop
)
{
this
.
dispatch
(
'ElForm'
,
'el.form.addField'
,
[
this
]);
let
initialValue
=
this
.
fieldValue
;
if
(
Array
.
isArray
(
initialValue
))
{
initialValue
=
[].
concat
(
initialValue
);
}
Object
.
defineProperty
(
this
,
'initialValue'
,
{
value
:
initialValue
});
let
rules
=
this
.
getRules
();
if
(
rules
.
length
||
this
.
required
!==
undefined
)
{
this
.
$on
(
'el.form.blur'
,
this
.
onFieldBlur
);
this
.
$on
(
'el.form.change'
,
this
.
onFieldChange
);
}
}
},
beforeDestroy
()
{
this
.
dispatch
(
'ElForm'
,
'el.form.removeField'
,
[
this
]);
}
};
</
script
>
src/views/Editor/dialogs/BehaviorEditorDialog.vue
View file @
0a0442d1
...
...
@@ -22,22 +22,29 @@
},
computed
:
{
...
mapState
({
data
:
state
=>
state
.
project
.
data
,
}),
},
methods
:
{
show
()
{
show
(
behaviors
,
event
)
{
this
.
behavior_startEdit
({
originData
:
this
.
data
,
behaviors
,
event
,
});
this
.
visible
=
true
;
},
onSave
()
{
this
.
behavior_save
();
this
.
visible
=
false
;
this
.
$emit
(
'change'
)
this
.
$emit
(
'change'
)
;
},
onOpened
()
{
this
.
$refs
.
behaviorEditor
.
measure
();
this
.
$refs
.
behaviorEditor
.
edit
();
},
...
mapMutations
([
'behavior_startEdit'
,
'behavior_save'
,
]),
}
}
...
...
yarn.lock
View file @
0a0442d1
...
...
@@ -2845,13 +2845,6 @@ dotenv@^7.0.0:
resolved "https://registry.npm.taobao.org/dotenv/download/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
integrity sha1-or481Sc2ZzIG6KhftSEO6ilijnw=
duiba-draggable-resizable@^1.0.9:
version "1.0.9"
resolved "https://registry.npm.taobao.org/duiba-draggable-resizable/download/duiba-draggable-resizable-1.0.9.tgz#9df1bec8b7c8ddde10ecc593a5246a268cdd19e3"
integrity sha1-nfG+yLfI3d4Q7MWTpSRqJozdGeM=
dependencies:
vue "^2.5.13"
duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
...
...
@@ -7885,6 +7878,11 @@ vue-cli-plugin-i18n@^0.6.0:
vue-i18n "^8.0.0"
vue-i18n-extract "^0.4.13"
vue-draggable-resizable@^2.0.1:
version "2.0.1"
resolved "https://registry.npm.taobao.org/vue-draggable-resizable/download/vue-draggable-resizable-2.0.1.tgz#fb98d0997b1cfa8e3ba90f723cf8b605012cd96d"
integrity sha1-+5jQmXsc+o47qQ9yPPi2BQEs2W0=
vue-hot-reload-api@^2.3.0:
version "2.3.3"
resolved "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.3.tgz#2756f46cb3258054c5f4723de8ae7e87302a1ccf"
...
...
@@ -7944,7 +7942,7 @@ vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=
vue@^2.5.1
3, vue@^2.5.1
6, vue@^2.6.10:
vue@^2.5.16, vue@^2.6.10:
version "2.6.10"
resolved "https://registry.npm.taobao.org/vue/download/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha1-pysaQqTYKnIepDjRtr9V5mGVxjc=
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment