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
01406053
Commit
01406053
authored
Apr 16, 2020
by
rockyl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
版本冲突功能
parent
7e600024
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
285 additions
and
33 deletions
+285
-33
common.js
src/api/common.js
+16
-11
zh-CN.json
src/locales/zh-CN.json
+6
-0
project.js
src/store/modules/project.js
+27
-14
editor.scss
src/themes/light/editor.scss
+25
-0
index.js
src/utils/index.js
+6
-1
Editor.vue
src/views/Editor.vue
+24
-7
ProjectConflictResolveDialog.vue
src/views/Editor/dialogs/ProjectConflictResolveDialog.vue
+181
-0
No files found.
src/api/common.js
View file @
01406053
...
...
@@ -66,19 +66,24 @@ export async function fetchApi(uri, {host = '', params, method = 'get', auth = t
}
const
response
=
await
fetch
(
url
,
options
);
if
(
response
.
status
===
401
)
{
location
.
href
=
'/admin/permission'
;
const
respText
=
await
response
.
text
();
if
(
response
.
status
===
310
)
{
//客户端重定向,用于跨域重定向
location
.
href
=
respText
;
}
const
jsonObj
=
await
response
.
json
();
//console.log(jsonObj);
if
(
judgeSuccess
)
{
if
(
jsonObj
.
success
)
{
return
jsonObj
[
dataField
];
try
{
let
jsonObj
=
JSON
.
parse
(
respText
);
if
(
judgeSuccess
)
{
if
(
jsonObj
.
success
)
{
return
jsonObj
.
data
;
}
}
else
{
return
jsonObj
;
}
}
else
{
return
jsonObj
;
}
throw
new
ApiError
(
'call api failed'
,
jsonObj
.
code
,
errMessage
,
jsonObj
.
details
);
return
Promise
.
reject
(
new
ApiError
(
'call api failed'
,
jsonObj
.
code
,
errMessage
,
jsonObj
.
details
));
}
catch
(
e
)
{
return
Promise
.
reject
(
e
);
}
}
src/locales/zh-CN.json
View file @
01406053
...
...
@@ -155,6 +155,7 @@
"Failed to get project"
:
"获取项目失败"
,
"Failed to save project"
:
"保存项目失败"
,
"Save project successfully"
:
"保存项目成功"
,
"There are conflicts in the project"
:
"项目有冲突,请先解决冲突"
,
"Input version remark"
:
"输入版本备注"
,
"Input view name"
:
"输入视图名"
,
"Invalid view name"
:
"无效的视图名"
,
...
...
@@ -226,6 +227,11 @@
"Operate"
:
"操作"
,
"Computed"
:
"计算属性"
,
"Are you sure to close?"
:
"确定关闭吗?"
,
"Project conflict resolver"
:
"项目冲突解决"
,
"Merge conflicts"
:
"合并冲突"
,
"There are still unresolved conflicts"
:
"还有冲突未解决,不能保存!"
,
"The format of the JSON document is wrong"
:
"JSON文档格式有误,请先更正!"
,
"The conflict has been resolved"
:
"冲突已解决,确定保存吗?"
,
"eventGroup"
:
{
"in"
:
"接收"
,
"out"
:
"派发"
...
...
src/store/modules/project.js
View file @
01406053
...
...
@@ -91,6 +91,9 @@ export const projectStore = {
},
makeProjectDirty
()
{
},
updateProjectUpdateTime
(
state
,
updateTime
)
{
state
.
update_time
=
updateTime
;
},
updateProject
(
state
,
project
)
{
const
{
id
,
name
,
creator
,
data
,
operators
,
update_time
}
=
project
;
...
...
@@ -352,11 +355,11 @@ export const projectStore = {
copyNode
(
state
,
{
node
,
parentNode
,
copyState
})
{
let
_node1
=
node
;
console
.
log
(
_node1
)
copyNodeCatch
=
clonePureObj
(
_node1
)
if
(
copyState
==
1
)
{
copyNodeCatch
=
clonePureObj
(
_node1
)
if
(
copyState
==
1
)
{
//复制行为
copyNodeCatch
.
events
}
else
if
(
copyState
==
2
)
{
}
else
if
(
copyState
==
2
)
{
//不复制行为
delete
copyNodeCatch
.
events
}
...
...
@@ -453,17 +456,17 @@ export const projectStore = {
state
.
mockServeEnabled
=
enabled
;
},
modifyViewStore
(
state
,
{
view
,
store
}){
modifyViewStore
(
state
,
{
view
,
store
})
{
view
.
store
=
store
;
this
.
commit
(
'makeProjectDirty'
);
},
addCmd
(
state
,
cmd
){
addCmd
(
state
,
cmd
)
{
Vue
.
set
(
state
.
activeComponent
.
properties
,
cmd
,
''
);
this
.
commit
(
'makeProjectDirty'
);
},
deleteCmd
(
state
,
cmd
){
deleteCmd
(
state
,
cmd
)
{
Vue
.
delete
(
state
.
activeComponent
.
properties
,
cmd
);
this
.
commit
(
'makeProjectDirty'
);
},
...
...
@@ -566,7 +569,7 @@ export const projectStore = {
let
index
=
entries
.
indexOf
(
behavior
.
meta
);
if
(
index
>=
0
)
{
let
path
=
paths
.
splice
(
index
,
1
,
null
)[
0
];
if
(
!
path
)
{
if
(
!
path
)
{
continue
;
}
path
[
0
]
=
{
...
...
@@ -641,9 +644,19 @@ export const projectStore = {
throw
new
Error
(
'Project does not exist'
)
}
},
async
saveToRemote
({
state
,
dispatch
,
getters
},
{
remark
})
{
await
projectApi
.
saveOne
(
getters
.
project
,
remark
);
dispatch
(
'deleteLocalVersion'
,
state
.
id
);
async
saveToRemote
({
state
,
dispatch
,
getters
,
commit
},
{
remark
,
data
})
{
let
project
=
Object
.
assign
({},
getters
.
project
);
if
(
data
)
{
project
.
data
=
data
;
project
.
force
=
true
;
}
let
resp
=
await
projectApi
.
saveOne
(
project
,
remark
);
if
(
resp
.
result
)
{
commit
(
'updateProjectUpdateTime'
,
resp
.
project
.
update_time
);
dispatch
(
'deleteLocalVersion'
,
state
.
id
);
}
resp
.
localData
=
project
.
data
;
return
resp
;
},
async
updateProject
({
commit
},
projectID
)
{
const
project
=
await
projectApi
.
getData
(
projectID
);
...
...
@@ -673,10 +686,10 @@ export const projectStore = {
}
}
if
(
_view
.
data
===
data
.
data
)
{
if
(
!
data
.
data
.
hasOwnProperty
(
'$isRootView'
))
{
if
(
_view
.
data
===
data
.
data
)
{
if
(
!
data
.
data
.
hasOwnProperty
(
'$isRootView'
))
{
Object
.
defineProperty
(
data
.
data
,
'$isRootView'
,
{
get
(){
get
()
{
return
true
;
}
})
...
...
@@ -810,7 +823,7 @@ export const projectStore = {
let
debug
=
params
.
debug
;
let
packedAssets
;
//if (!debug) {
packedAssets
=
await
packAssets
(
state
.
data
.
assets
);
packedAssets
=
await
packAssets
(
state
.
data
.
assets
);
//}
const
packResult
=
await
projectApi
.
pack
(
state
.
id
,
debug
,
packedAssets
);
...
...
src/themes/light/editor.scss
View file @
01406053
...
...
@@ -219,11 +219,13 @@
.tpl-editor
{
flex
:
1
;
height
:
0
;
.el-form-item__content
{
height
:
100%
;
.editor
{
width
:
100%
;
height
:
100%
;
}
}
...
...
@@ -269,6 +271,7 @@
}
.editor
{
width
:
100%
;
height
:
300px
;
}
}
...
...
@@ -322,11 +325,13 @@
.editor-form-item
{
flex
:
1
;
height
:
0
;
.el-form-item__content
{
height
:
100%
;
.editor
{
width
:
100%
;
height
:
100%
;
}
}
...
...
@@ -359,11 +364,13 @@
}
.editor
{
width
:
100%
;
height
:
100%
;
}
.computed-editor
{
.editor
{
width
:
100%
;
height
:
200px
;
}
}
...
...
@@ -519,3 +526,21 @@
.pack-failed-details
{
width
:
80vw
!
important
;
}
.project-conflict-resolve-editor
{
.wrapper
{
height
:
100%
;
padding
:
10px
;
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
.container
{
flex
:
1
;
.editor
{
height
:
100%
;
}
}
}
}
src/utils/index.js
View file @
01406053
...
...
@@ -34,7 +34,8 @@ export const pxHostMapping = {
export
const
monacoEditorOptions
=
{
tabSize
:
2
,
insertSpaces
:
false
insertSpaces
:
false
,
automaticLayout
:
true
,
};
export
const
cmdPrefix
=
'z-'
;
...
...
@@ -424,3 +425,7 @@ export function deleteAssetsDepConfig(data) {
delete
asset
[
'dep'
];
}
}
export
function
formatJson
(
source
){
return
JSON
.
stringify
(
JSON
.
parse
(
source
),
null
,
'
\
t'
)
}
src/views/Editor.vue
View file @
01406053
...
...
@@ -20,6 +20,7 @@
<px-skin-editor-dialog
ref=
"pxSkinEditorDialog"
/>
<process-search-dialog
ref=
"processSearchDialog"
/>
<behavior-editor-dialog
@
change=
"handleBehaviorsChange"
ref=
"behaviorEditorDialog"
></behavior-editor-dialog>
<project-conflict-resolve-dialog
ref=
"projectConflictResolveDialog"
@
resolved=
"onConflictResolved"
/>
</div>
</
template
>
...
...
@@ -45,10 +46,12 @@
import
PxSkinEditorDialog
from
"./Editor/dialogs/PxSkinEditorDialog"
;
import
BehaviorEditorDialog
from
"./Editor/dialogs/BehaviorEditorDialog"
;
import
ProcessSearchDialog
from
"./Editor/dialogs/ProcessSearchDialog"
;
import
ProjectConflictResolveDialog
from
"./Editor/dialogs/ProjectConflictResolveDialog"
;
export
default
{
name
:
'Editor'
,
components
:
{
ProjectConflictResolveDialog
,
ProcessSearchDialog
,
BehaviorEditorDialog
,
PxSkinEditorDialog
,
...
...
@@ -190,7 +193,7 @@
this
.
panesConfig
[
id
]
=
configs
[
0
].
width
/
100
;
localStorage
.
panesConfig
=
JSON
.
stringify
(
this
.
panesConfig
);
},
async
saveProject
(
closeLoading
)
{
async
saveProject
(
closeLoading
,
data
)
{
let
remark
,
cancel
;
await
this
.
$prompt
(
this
.
$t
(
'Input version remark'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
...
...
@@ -204,15 +207,29 @@
cancel
=
true
;
});
if
(
!
cancel
)
{
await
playWaiting
(
this
.
saveToRemote
({
remark
}),
this
.
$t
(
'Saving'
),
closeLoading
);
this
.
$message
({
message
:
i18n
.
t
(
'Save project successfully'
),
//因为message是异步出现,但是当路由回退的时候,this.i18n的实例已经置空,所以要用全局的i18n实例
type
:
'success'
});
let
resp
=
await
playWaiting
(
this
.
saveToRemote
({
remark
,
data
}),
this
.
$t
(
'Saving'
),
closeLoading
);
if
(
resp
.
result
)
{
this
.
$message
({
message
:
i18n
.
t
(
'Save project successfully'
),
//因为message是异步出现,但是当路由回退的时候,this.i18n的实例已经置空,所以要用全局的i18n实例
type
:
'success'
});
}
else
{
await
this
.
$confirm
(
i18n
.
t
(
'There are conflicts in the project'
),
i18n
.
t
(
'Alert'
),
{
confirmButtonText
:
i18n
.
t
(
'Confirm'
),
cancelButtonText
:
i18n
.
t
(
'Cancel'
),
type
:
'warning'
}).
then
(()
=>
{
this
.
$refs
.
projectConflictResolveDialog
.
show
(
resp
.
remoteData
,
resp
.
localData
);
}).
catch
((
e
)
=>
{
});
}
}
return
cancel
;
},
async
onConflictResolved
(
data
)
{
this
.
saveProject
(
true
,
data
);
},
async
clickMenu
(
menuItem
)
{
switch
(
menuItem
)
{
case
'save'
:
...
...
@@ -306,7 +323,7 @@
type
:
'error'
,
duration
:
1000
,
});
if
(
e
.
details
)
{
if
(
e
.
details
)
{
let
details
=
e
.
details
.
split
(
'
\
n'
).
join
(
'
\
n'
);
this
.
$alert
(
`<p>Compile error</p><pre style="color:red;">
${
details
}
</pre>`
,
this
.
$t
(
'Alert'
),
{
dangerouslyUseHTMLString
:
true
,
...
...
src/views/Editor/dialogs/ProjectConflictResolveDialog.vue
0 → 100644
View file @
01406053
<
template
>
<el-dialog
:title=
"$t('Project conflict resolver')"
width=
"70%"
:visible
.
sync=
"visible"
@
opened=
"onOpen"
:close-on-click-modal=
"false"
:append-to-body=
"true"
fullscreen
custom-class=
"flex-dialog project-conflict-resolve-editor"
>
<div
class=
"wrapper"
>
<el-steps
:active=
"step"
finish-status=
"success"
align-center
>
<el-step
title=
"查看冲突"
></el-step>
<el-step
title=
"手动合并"
></el-step>
<el-step
title=
"完成"
></el-step>
</el-steps>
<div
class=
"container"
>
<monaco-editor
ref=
"editor"
class=
"editor"
v-model=
"localData"
language=
"json"
:options=
"monacoEditorOptions"
diff-editor
:original=
"remoteData"
/>
</div>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<div>
<el-button
size=
"mini"
@
click=
"mergeConflicts"
type=
"success"
v-show=
"step===0"
>
{{
$t
(
'Merge conflicts'
)
}}
</el-button>
</div>
<div>
<el-button
size=
"mini"
@
click=
"onClose"
>
{{
$t
(
'Close'
)
}}
</el-button>
<el-button
size=
"mini"
@
click=
"onSave"
type=
"primary"
:disabled=
"step===0"
>
{{
$t
(
'Save'
)
}}
</el-button>
</div>
</div>
</el-dialog>
</
template
>
<
script
>
import
{
mapMutations
}
from
'vuex'
;
import
MonacoEditor
from
"vue-monaco"
;
import
{
formatJson
,
monacoEditorOptions
}
from
"../../../utils"
;
import
SplitPanes
from
'splitpanes'
const
conflictFlags
=
[
'<<<<<<< REMOTE'
,
'======='
,
'>>>>>>> LOCAL'
];
export
default
{
name
:
"ProjectConflictResolveDialog"
,
components
:
{
MonacoEditor
,
SplitPanes
},
data
()
{
let
monacoEditorOptionsSelf
=
Object
.
assign
({
readOnly
:
true
,
},
monacoEditorOptions
);
return
{
monacoEditorOptions
:
monacoEditorOptionsSelf
,
visible
:
false
,
step
:
0
,
remoteData
:
''
,
localData
:
''
,
}
},
mounted
()
{
},
methods
:
{
show
(
remoteData
,
localData
)
{
this
.
remoteData
=
''
;
this
.
localData
=
''
;
this
.
$nextTick
(()
=>
{
this
.
remoteData
=
this
.
formatJson
(
remoteData
);
this
.
localData
=
this
.
formatJson
(
localData
);
this
.
step
=
0
;
this
.
visible
=
true
;
this
.
monacoEditorOptions
.
readOnly
=
true
;
this
.
diff
=
null
;
this
.
$nextTick
(()
=>
{
if
(
!
this
.
inited
)
{
this
.
inited
=
true
;
let
modifiedEditor
=
this
.
$refs
.
editor
.
getModifiedEditor
();
let
editor
=
this
.
$refs
.
editor
.
getEditor
();
editor
.
onDidUpdateDiff
(()
=>
{
if
(
!
this
.
diff
)
{
this
.
diff
=
editor
.
getLineChanges
();
}
});
modifiedEditor
.
onDidChangeModelDecorations
(()
=>
{
});
}
});
});
},
async
onSave
()
{
let
resolved
=
true
;
for
(
let
conflictFlag
of
conflictFlags
)
{
if
(
this
.
localData
.
includes
(
conflictFlag
))
{
resolved
=
false
;
break
;
}
}
if
(
resolved
)
{
try
{
JSON
.
parse
(
this
.
localData
);
await
this
.
$confirm
(
this
.
$t
(
'The conflict has been resolved'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
type
:
'warning'
}).
then
(()
=>
{
this
.
visible
=
false
;
this
.
$emit
(
'resolved'
,
this
.
localData
);
}).
catch
((
e
)
=>
{
});
}
catch
(
e
)
{
this
.
$alert
(
this
.
$t
(
'The format of the JSON document is wrong'
),
{
type
:
'warning'
});
}
}
else
{
this
.
$alert
(
this
.
$t
(
'There are still unresolved conflicts'
),
{
type
:
'warning'
});
}
},
onClose
()
{
this
.
visible
=
false
;
},
onOpen
()
{
},
...
mapMutations
([
'modifyProjectDetails'
,
]),
formatJson
(
source
)
{
return
formatJson
(
source
);
},
mergeConflicts
()
{
this
.
monacoEditorOptions
.
readOnly
=
false
;
this
.
step
++
;
let
remoteCodeLines
=
this
.
remoteData
.
split
(
'
\
n'
);
let
localCodeLines
=
this
.
localData
.
split
(
'
\
n'
);
let
mergedCodeLines
=
localCodeLines
.
concat
();
//console.log(this.diff);
let
offset
=
0
;
for
(
let
{
modifiedStartLineNumber
,
modifiedEndLineNumber
,
originalStartLineNumber
,
originalEndLineNumber
}
of
this
.
diff
)
{
let
remotePart
=
[];
for
(
let
i
=
originalStartLineNumber
,
li
=
originalEndLineNumber
;
i
<=
li
;
i
++
)
{
remotePart
.
push
(
remoteCodeLines
[
i
-
1
]);
}
let
localPart
=
[];
for
(
let
i
=
modifiedStartLineNumber
,
li
=
modifiedEndLineNumber
;
i
<=
li
;
i
++
)
{
localPart
.
push
(
localCodeLines
[
i
-
1
]);
}
let
merged
=
[];
merged
.
push
(
conflictFlags
[
0
]);
merged
.
push
(...
remotePart
);
merged
.
push
(
conflictFlags
[
1
]);
merged
.
push
(...
localPart
);
merged
.
push
(
conflictFlags
[
2
]);
//console.log(merged);
mergedCodeLines
.
splice
(
modifiedStartLineNumber
-
1
+
offset
,
modifiedEndLineNumber
-
modifiedStartLineNumber
+
1
,
...
merged
);
offset
+=
3
+
remotePart
.
length
;
}
this
.
localData
=
mergedCodeLines
.
join
(
'
\
n'
);
},
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
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