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
cf25f3fb
Commit
cf25f3fb
authored
Apr 21, 2020
by
rockyl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
版本比对
parent
0b5f668e
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
290 additions
and
20 deletions
+290
-20
zh-CN.json
src/locales/zh-CN.json
+6
-1
editor.scss
src/themes/light/editor.scss
+16
-0
Editor.vue
src/views/Editor.vue
+1
-1
ProjectConflictResolveDialog.vue
src/views/Editor/dialogs/ProjectConflictResolveDialog.vue
+267
-18
No files found.
src/locales/zh-CN.json
View file @
cf25f3fb
...
@@ -158,7 +158,7 @@
...
@@ -158,7 +158,7 @@
"Failed to save project"
:
"保存项目失败"
,
"Failed to save project"
:
"保存项目失败"
,
"Save project successfully"
:
"保存项目成功"
,
"Save project successfully"
:
"保存项目成功"
,
"There are conflicts in the project"
:
"项目有冲突,请先解决冲突"
,
"There are conflicts in the project"
:
"项目有冲突,请先解决冲突"
,
"Input version remark"
:
"输入版本备注"
,
"Input version remark"
:
"
请务必认真
输入版本备注"
,
"Input view name"
:
"输入视图名"
,
"Input view name"
:
"输入视图名"
,
"Invalid view name"
:
"无效的视图名"
,
"Invalid view name"
:
"无效的视图名"
,
"Unsaved version found locally"
:
"本地发现了未保存保本,请选择版本打开"
,
"Unsaved version found locally"
:
"本地发现了未保存保本,请选择版本打开"
,
...
@@ -238,6 +238,11 @@
...
@@ -238,6 +238,11 @@
"Failed to update operator"
:
"更新权限列表失败"
,
"Failed to update operator"
:
"更新权限列表失败"
,
"Error delete self"
:
"连自己都删? 不可以!"
,
"Error delete self"
:
"连自己都删? 不可以!"
,
"No permission"
:
"没有权限喔!"
,
"No permission"
:
"没有权限喔!"
,
"Accept Remote"
:
"远程版本"
,
"Accept Local"
:
"本地版本"
,
"Accept Both"
:
"兼并"
,
"Previous Conflict"
:
"上一个冲突"
,
"Next Conflict"
:
"下一个冲突"
,
"eventGroup"
:
{
"eventGroup"
:
{
"in"
:
"接收"
,
"in"
:
"接收"
,
"out"
:
"派发"
"out"
:
"派发"
...
...
src/themes/light/editor.scss
View file @
cf25f3fb
...
@@ -544,3 +544,19 @@
...
@@ -544,3 +544,19 @@
}
}
}
}
}
}
.remote-change-class
{
background-color
:
rgba
(
64
,
200
,
174
,
0
.2
);
}
.remote-change-marker-class
{
background-color
:
rgba
(
64
,
200
,
174
,
0
.5
);
}
.local-change-class
{
background-color
:
rgba
(
64
,
166
,
255
,
0
.2
);
}
.local-change-marker-class
{
background-color
:
rgba
(
64
,
166
,
255
,
0
.5
);
}
src/views/Editor.vue
View file @
cf25f3fb
...
@@ -200,7 +200,7 @@
...
@@ -200,7 +200,7 @@
await
this
.
$prompt
(
this
.
$t
(
'Input version remark'
),
this
.
$t
(
'Alert'
),
{
await
this
.
$prompt
(
this
.
$t
(
'Input version remark'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
confirmButtonText
:
this
.
$t
(
'Confirm'
),
showClose
:
false
,
showClose
:
false
,
inputPattern
:
/^.
{
0
,256}
$/
,
inputPattern
:
/^.
{
1
,256}
$/
,
}).
then
(
}).
then
(
({
value
})
=>
{
({
value
})
=>
{
remark
=
this
.
lastSaveRemark
=
value
;
remark
=
this
.
lastSaveRemark
=
value
;
...
...
src/views/Editor/dialogs/ProjectConflictResolveDialog.vue
View file @
cf25f3fb
<
template
>
<
template
>
<el-dialog
:title=
"$t('Project conflict resolver')"
width=
"70%"
:visible
.
sync=
"visible"
@
opened=
"onOpen"
<el-dialog
:title=
"$t('Project conflict resolver')"
width=
"70%"
:visible
.
sync=
"visible"
@
opened=
"onOpen"
@
close=
"onClose"
:close-on-click-modal=
"false"
:close-on-click-modal=
"false"
:append-to-body=
"true"
:append-to-body=
"true"
fullscreen
fullscreen
...
@@ -7,17 +8,27 @@
...
@@ -7,17 +8,27 @@
>
>
<div
class=
"wrapper"
>
<div
class=
"wrapper"
>
<el-steps
:active=
"step"
finish-status=
"success"
align-center
>
<el-steps
:active=
"step"
finish-status=
"success"
align-center
>
<el-step
v-for=
"
item in steps"
:title=
"item
"
></el-step>
<el-step
v-for=
"
(item, index) in steps"
:title=
"item"
:key=
"index
"
></el-step>
</el-steps>
</el-steps>
<div
class=
"container"
>
<div
class=
"container"
>
<monaco-editor
<monaco-editor
ref=
"
e
ditor"
ref=
"
diffE
ditor"
class=
"editor"
class=
"editor"
v-model=
"localData"
v-model=
"localData"
language=
"json"
language=
"json"
:options=
"monacoEditorOptions"
:options=
"monacoEditorOptions"
diff-editor
diff-editor
:original=
"remoteData"
:original=
"remoteData"
v-show=
"step===0"
/>
<monaco-editor
ref=
"editor"
class=
"editor"
v-model=
"localData"
language=
"json"
:options=
"monacoEditorOptions"
v-show=
"step===1"
@
change=
"onChange"
/>
/>
</div>
</div>
</div>
</div>
...
@@ -25,9 +36,14 @@
...
@@ -25,9 +36,14 @@
<div>
<div>
<el-button
size=
"mini"
@
click=
"mergeConflicts"
type=
"success"
v-show=
"step===0"
>
{{
$t
(
'Merge conflicts'
)
}}
<el-button
size=
"mini"
@
click=
"mergeConflicts"
type=
"success"
v-show=
"step===0"
>
{{
$t
(
'Merge conflicts'
)
}}
</el-button>
</el-button>
<el-button-group
v-show=
"step===1"
>
<el-button
size=
"mini"
@
click=
"revealPreviousConflict(-1)"
type=
"success"
>
{{
$t
(
'Previous Conflict'
)
}}
</el-button>
<el-button
size=
"mini"
@
click=
"revealPreviousConflict(1)"
type=
"success"
>
{{
$t
(
'Next Conflict'
)
}}
</el-button>
</el-button-group>
</div>
</div>
<div>
<div>
<el-button
size=
"mini"
@
click=
"onC
lose"
>
{{
$t
(
'Close
'
)
}}
</el-button>
<el-button
size=
"mini"
@
click=
"onC
ancel"
>
{{
$t
(
'Cancel
'
)
}}
</el-button>
<el-button
size=
"mini"
@
click=
"onSave"
type=
"primary"
:disabled=
"step===0"
>
{{
$t
(
'Save'
)
}}
</el-button>
<el-button
size=
"mini"
@
click=
"onSave"
type=
"primary"
:disabled=
"step===0"
>
{{
$t
(
'Save'
)
}}
</el-button>
</div>
</div>
</div>
</div>
...
@@ -39,8 +55,14 @@
...
@@ -39,8 +55,14 @@
import
MonacoEditor
from
"vue-monaco"
;
import
MonacoEditor
from
"vue-monaco"
;
import
{
formatJson
,
monacoEditorOptions
}
from
"../../../utils"
;
import
{
formatJson
,
monacoEditorOptions
}
from
"../../../utils"
;
import
SplitPanes
from
'splitpanes'
import
SplitPanes
from
'splitpanes'
import
i18n
from
"@/i18n"
;
const
conflictFlags
=
[
'<<<<<<< REMOTE'
,
'======='
,
'>>>>>>> LOCAL'
];
const
startHeaderMarker
=
'<<<<<<< REMOTE'
;
const
splitterMarker
=
'======='
;
const
endFooterMarker
=
'>>>>>>> LOCAL'
;
const
conflictMarkers
=
[
startHeaderMarker
,
splitterMarker
,
endFooterMarker
];
const
lensTitles
=
[
i18n
.
t
(
'Accept Remote'
),
i18n
.
t
(
'Accept Local'
),
i18n
.
t
(
'Accept Both'
)];
const
delayTrackDuration
=
500
;
export
default
{
export
default
{
name
:
"ProjectConflictResolveDialog"
,
name
:
"ProjectConflictResolveDialog"
,
...
@@ -59,6 +81,12 @@
...
@@ -59,6 +81,12 @@
}
}
},
},
mounted
()
{
mounted
()
{
this
.
codeLensProviders
=
[];
this
.
conflicts
=
[];
this
.
conflictIndex
=
0
;
this
.
decrations
=
[];
},
destroyed
()
{
},
},
methods
:
{
methods
:
{
...
@@ -79,23 +107,25 @@
...
@@ -79,23 +107,25 @@
if
(
!
this
.
inited
)
{
if
(
!
this
.
inited
)
{
this
.
inited
=
true
;
this
.
inited
=
true
;
let
modifiedEditor
=
this
.
$refs
.
editor
.
getModifiedEditor
()
;
let
diffEditor
=
this
.
$refs
.
diffEditor
;
let
editor
=
this
.
$refs
.
e
ditor
.
getEditor
();
let
editor
=
diffE
ditor
.
getEditor
();
editor
.
onDidUpdateDiff
(()
=>
{
editor
.
onDidUpdateDiff
(()
=>
{
if
(
!
this
.
diff
)
{
if
(
!
this
.
diff
)
{
this
.
diff
=
editor
.
getLineChanges
();
this
.
diff
=
editor
.
getLineChanges
();
}
}
});
});
modifiedEditor
.
onDidChangeModelDecorations
(()
=>
{
});
let
resolveEditorIns
=
this
.
$refs
.
editor
.
getEditor
();
this
.
mergeConflictCommand
=
resolveEditorIns
.
addCommand
(
0
,
(
getService
,
action
,
conflict
)
=>
{
this
.
resolveConflict
(
action
,
conflict
);
},
''
);
}
}
});
});
});
});
},
},
async
onSave
()
{
async
onSave
()
{
let
resolved
=
true
;
let
resolved
=
true
;
for
(
let
conflictFlag
of
conflict
Flag
s
)
{
for
(
let
conflictFlag
of
conflict
Marker
s
)
{
if
(
this
.
localData
.
includes
(
conflictFlag
))
{
if
(
this
.
localData
.
includes
(
conflictFlag
))
{
resolved
=
false
;
resolved
=
false
;
break
;
break
;
...
@@ -125,20 +155,172 @@
...
@@ -125,20 +155,172 @@
});
});
}
}
},
},
onC
lose
()
{
onC
ancel
()
{
this
.
visible
=
false
;
this
.
visible
=
false
;
},
},
onClose
()
{
this
.
removeAllCodeLensProviders
();
this
.
removeAllDecorations
();
},
onOpen
()
{
onOpen
()
{
},
},
...
mapMutations
([
'modifyProjectDetails'
,
]),
formatJson
(
source
)
{
formatJson
(
source
)
{
return
formatJson
(
source
);
return
formatJson
(
source
);
},
},
onChange
(
t
)
{
if
(
this
.
timerTrack
)
{
clearTimeout
(
this
.
timerTrack
);
this
.
timerTrack
=
null
;
}
this
.
timerTrack
=
setTimeout
(()
=>
{
this
.
delayTrack
()
},
delayTrackDuration
);
},
removeAllCodeLensProviders
()
{
while
(
this
.
codeLensProviders
.
length
>
0
)
{
let
codeLensProvider
=
this
.
codeLensProviders
.
pop
();
codeLensProvider
.
dispose
();
}
},
removeAllDecorations
()
{
let
editor
=
this
.
$refs
.
editor
;
let
resolveEditor
=
editor
.
getEditor
();
resolveEditor
.
deltaDecorations
(
this
.
decrations
,
[]);
this
.
decrations
.
splice
(
0
);
},
delayTrack
()
{
console
.
log
(
'delayTrack'
);
let
lines
=
this
.
localData
.
split
(
'
\
n'
);
this
.
conflicts
.
splice
(
0
);
let
currentConflict
=
null
;
let
conflicts
=
this
.
conflicts
;
for
(
let
i
=
0
,
li
=
lines
.
length
;
i
<
li
;
i
++
)
{
const
line
=
lines
[
i
];
if
(
!
line
)
{
continue
;
}
if
(
line
.
startsWith
(
startHeaderMarker
))
{
if
(
currentConflict
!==
null
)
{
currentConflict
=
null
;
break
;
}
currentConflict
=
{
remoteLine
:
i
};
}
else
if
(
currentConflict
&&
!
currentConflict
.
splitLine
&&
line
.
startsWith
(
splitterMarker
))
{
currentConflict
.
splitLine
=
i
;
}
else
if
(
currentConflict
&&
currentConflict
.
splitLine
&&
line
.
startsWith
(
endFooterMarker
))
{
currentConflict
.
localLine
=
i
;
conflicts
.
push
(
currentConflict
);
currentConflict
=
null
;
}
}
this
.
removeAllCodeLensProviders
();
this
.
removeAllDecorations
();
for
(
let
conflict
of
conflicts
)
{
const
{
remoteLine
,
splitLine
,
localLine
}
=
conflict
;
let
line
=
remoteLine
+
1
;
let
range
=
{
startLineNumber
:
line
,
startColumn
:
line
,
endLineNumber
:
line
,
endColumn
:
line
};
let
id
=
line
.
toString
();
let
lenses
=
[];
for
(
let
i
=
0
,
li
=
lensTitles
.
length
;
i
<
li
;
i
++
)
{
const
lensTitle
=
lensTitles
[
i
];
lenses
.
push
({
range
,
id
,
command
:
{
id
:
this
.
mergeConflictCommand
,
title
:
lensTitle
,
arguments
:
[
i
,
conflict
],
}
})
}
let
editor
=
this
.
$refs
.
editor
;
let
resolveEditor
=
editor
.
getEditor
();
let
codeLensProvider
=
editor
.
monaco
.
languages
.
registerCodeLensProvider
(
'json'
,
{
provideCodeLenses
:
function
(
model
,
token
)
{
return
{
lenses
,
dispose
()
{
}
};
},
resolveCodeLens
:
function
(
model
,
codeLens
,
token
)
{
return
codeLens
;
}
});
this
.
codeLensProviders
.
push
(
codeLensProvider
);
this
.
revealPreviousConflict
();
this
.
$nextTick
(()
=>
{
let
deltaDecorations
=
[
{
range
:
{
startLineNumber
:
remoteLine
+
1
,
endLineNumber
:
remoteLine
+
1
,
},
options
:
{
isWholeLine
:
true
,
className
:
'remote-change-marker-class'
}
},
];
if
(
splitLine
-
remoteLine
>
1
)
{
deltaDecorations
.
push
({
range
:
{
startLineNumber
:
remoteLine
+
2
,
endLineNumber
:
splitLine
,
},
options
:
{
isWholeLine
:
true
,
className
:
'remote-change-class'
}
},)
}
if
(
localLine
-
splitLine
>
1
)
{
deltaDecorations
.
push
({
range
:
{
startLineNumber
:
splitLine
+
2
,
endLineNumber
:
localLine
,
},
options
:
{
isWholeLine
:
true
,
className
:
'local-change-class'
}
},)
}
deltaDecorations
.
push
({
range
:
{
startLineNumber
:
localLine
+
1
,
endLineNumber
:
localLine
+
1
,
},
options
:
{
isWholeLine
:
true
,
className
:
'local-change-marker-class'
}
});
let
decorations
=
resolveEditor
.
deltaDecorations
([],
deltaDecorations
);
this
.
decrations
.
push
(...
decorations
);
});
}
},
revealPreviousConflict
(
dir
=
0
)
{
this
.
conflictIndex
+=
dir
;
if
(
this
.
conflictIndex
<
0
)
{
this
.
conflictIndex
+=
this
.
conflicts
.
length
;
}
this
.
conflictIndex
=
this
.
conflictIndex
%
this
.
conflicts
.
length
;
let
conflict
=
this
.
conflicts
[
this
.
conflictIndex
];
let
resolveEditorIns
=
this
.
$refs
.
editor
.
getEditor
();
resolveEditorIns
.
revealLineInCenter
(
conflict
.
remoteLine
);
},
mergeConflicts
()
{
mergeConflicts
()
{
this
.
monacoEditorOptions
.
readOnly
=
false
;
this
.
monacoEditorOptions
.
readOnly
=
false
;
this
.
$nextTick
(()
=>
{
this
.
step
++
;
this
.
step
++
;
});
let
remoteCodeLines
=
this
.
remoteData
.
split
(
'
\
n'
);
let
remoteCodeLines
=
this
.
remoteData
.
split
(
'
\
n'
);
let
localCodeLines
=
this
.
localData
.
split
(
'
\
n'
);
let
localCodeLines
=
this
.
localData
.
split
(
'
\
n'
);
...
@@ -158,20 +340,87 @@
...
@@ -158,20 +340,87 @@
}
}
let
merged
=
[];
let
merged
=
[];
merged
.
push
(
conflict
Flag
s
[
0
]);
merged
.
push
(
conflict
Marker
s
[
0
]);
merged
.
push
(...
remotePart
);
merged
.
push
(...
remotePart
);
merged
.
push
(
conflict
Flag
s
[
1
]);
merged
.
push
(
conflict
Marker
s
[
1
]);
merged
.
push
(...
localPart
);
merged
.
push
(...
localPart
);
merged
.
push
(
conflict
Flag
s
[
2
]);
merged
.
push
(
conflict
Marker
s
[
2
]);
//console.log(merged);
//console.log(merged);
mergedCodeLines
.
splice
(
modifiedStartLineNumber
-
1
+
offset
,
modifiedEndLineNumber
-
modifiedStartLineNumber
+
1
,
...
merged
);
let
startLine
=
modifiedStartLineNumber
+
offset
;
mergedCodeLines
.
splice
(
startLine
-
1
,
modifiedEndLineNumber
-
modifiedStartLineNumber
+
1
,
...
merged
);
offset
+=
3
+
remotePart
.
length
;
offset
+=
3
+
remotePart
.
length
;
}
}
this
.
localData
=
mergedCodeLines
.
join
(
'
\
n'
);
this
.
localData
=
mergedCodeLines
.
join
(
'
\
n'
);
this
.
delayTrack
();
},
},
resolveConflict
(
action
,
conflict
)
{
let
resolveEditorIns
=
this
.
$refs
.
editor
.
getEditor
();
let
model
=
resolveEditorIns
.
getModel
();
let
lines
=
this
.
localData
.
split
(
'
\
n'
);
let
replacer
;
switch
(
action
)
{
case
0
:
replacer
=
getTextWithRange
(
conflict
.
remoteLine
,
conflict
.
splitLine
);
break
;
case
1
:
replacer
=
getTextWithRange
(
conflict
.
splitLine
,
conflict
.
localLine
);
break
;
case
2
:
let
remoteReplacer
=
getTextWithRange
(
conflict
.
remoteLine
,
conflict
.
splitLine
);
let
localReplacer
=
getTextWithRange
(
conflict
.
splitLine
,
conflict
.
localLine
);
if
(
remoteReplacer
===
undefined
)
{
if
(
localReplacer
!==
undefined
)
{
replacer
=
localReplacer
;
}
}
else
{
if
(
localReplacer
===
undefined
)
{
replacer
=
remoteReplacer
;
}
else
{
replacer
=
remoteReplacer
+
'
\
n'
+
localReplacer
;
}
}
break
;
}
if
(
replacer
!==
undefined
)
{
replaceText
(
replacer
);
//this.localData = lines.join('\n');
}
this
.
delayTrack
();
this
.
conflictIndex
--
;
this
.
conflictIndex
=
Math
.
max
(
this
.
conflictIndex
,
0
);
function
getTextWithRange
(
start
,
end
)
{
if
(
end
-
start
>
1
)
{
let
resultLines
=
[];
for
(
let
i
=
start
+
1
;
i
<
end
;
i
++
)
{
resultLines
.
push
(
lines
[
i
]);
}
return
resultLines
.
join
(
'
\
n'
);
}
}
function
replaceText
(
replacer
)
{
model
.
pushEditOperations
([],
[{
range
:
{
startLineNumber
:
conflict
.
remoteLine
+
1
,
startColumn
:
0
,
endLineNumber
:
conflict
.
localLine
+
1
,
endColumn
:
Number
.
MAX_VALUE
,
},
text
:
replacer
,
}],
()
=>
[]);
}
},
...
mapMutations
([
'modifyProjectDetails'
,
]),
}
}
}
}
</
script
>
</
script
>
...
...
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