Commit c0c6b795 authored by 张晨辰's avatar 张晨辰

Merge branch 'dev' into feature/20190923-feature

parents 45b15e27 f3422756
/**
* Created by rockyl on 2019-09-19.
*/
export let API_HOST;
if (process.env.NODE_ENV === 'development') {
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://localhost:3002';
API_HOST = window.__data.apiHost;
<<<<<<< HEAD
=======
//API_HOST = '';
>>>>>>> 4be75099e23b6946a0ba4a754861b69a32bad830
} else {
API_HOST = window.__data.apiHost;
}
if (API_HOST[API_HOST.length - 1] === '/') {
API_HOST = API_HOST.substr(0, API_HOST.length - 1);
}
export const SSO_VERIFY_PAGE_URL = '/sso/logout';
export const DOCK_POINT_OFFSET = 4;
//文件类型图标 t表示展示缩略图
export const fileTypeIcon = {
'': 'file-empty',
'.txt': 'file-text',
'.json': 'file-text',
'.zip': 'file-zip',
'.fnt': 'file-font',
'.jpg': 't',
'.jpeg': 't',
'.png': 't',
'.gif': 't',
'.svg': 't',
};
/**
* Created by rockyl on 2019-09-19.
*/
export let API_HOST;
if (process.env.NODE_ENV === 'development') {
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://localhost:3002';
API_HOST = window.__data.apiHost;
//API_HOST = '';
} else {
API_HOST = window.__data.apiHost;
}
if (API_HOST[API_HOST.length - 1] === '/') {
API_HOST = API_HOST.substr(0, API_HOST.length - 1);
}
export const SSO_VERIFY_PAGE_URL = '/sso/logout';
export const DOCK_POINT_OFFSET = 4;
//文件类型图标 t表示展示缩略图
export const fileTypeIcon = {
'': 'file-empty',
'.txt': 'file-text',
'.json': 'file-text',
'.zip': 'file-zip',
'.fnt': 'file-font',
'.jpg': 't',
'.jpeg': 't',
'.png': 't',
'.gif': 't',
'.svg': 't',
};
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"string-width": "^4.1.0", "string-width": "^4.1.0",
"uuid": "^3.3.3", "uuid": "^3.3.3",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-codemirror": "^4.0.6",
"vue-i18n": "^8.0.0", "vue-i18n": "^8.0.0",
"vue-router": "^3.0.3", "vue-router": "^3.0.3",
"vuex": "^3.0.1" "vuex": "^3.0.1"
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
</noscript> </noscript>
<script> <script>
window.__data = { window.__data = {
token : "<%= process.env.NODE_ENV === 'development' ? 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjQ1LCJuYW1lIjoi5byg5pmo6L6wIiwiYWNjb3VudCI6InpjYyIsImVtYWlsIjoiemNjQGR1aWJhLmNvbS5jbiIsIm1vYmlsZSI6IjE4NzU3MTU1NzUxIiwiZGluZ1VzZXJJZCI6IjAyMDcxMTUyNjgyNDI1MTc1MiIsIm1vZGVsQXV0aG9yaXplIjpmYWxzZSwibG9naW5UaW1lb3V0Ijo4NjMxMCwiZ210Q3JlYXRlIjoxNTM0NDEyMDA4MDAwLCJnbXRNb2RpZmllZCI6MTU3NDA0OTAwODAwMCwic3lzdGVtSWRTZXQiOlswLDEsMzQsMzYsMzcsMjMxLDIwMywxOSwyMSwyNDYsMjMsMjQ5LDI1LDI3LDMwXSwiaWF0IjoxNTc0ODU5OTA5fQ.OIOZDSSdJRPHeDI_YPY6lBFWvNoRZZ2O4uByG6rDOxk' : '$TOKEN$' %>", token : "<%= process.env.NODE_ENV === 'development' ? 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjA4NSwibmFtZSI6IuWKs-eQquWzsCIsImFjY291bnQiOiJsYW9xaWZlbmciLCJlbWFpbCI6Imxhb3FpZmVuZ0BkdWliYS5jb20uY24iLCJtb2JpbGUiOiIxMzQ1Njc3NDE1MyIsImRpbmdVc2VySWQiOiI1MDY5MDYyOTIxMjkxMDAxIiwibW9kZWxBdXRob3JpemUiOmZhbHNlLCJsb2dpblRpbWVvdXQiOjE0ODA5LCJnbXRDcmVhdGUiOjE1MzQ0MTIwMTUwMDAsImdtdE1vZGlmaWVkIjoxNTczODgyMDk2MDAwLCJzeXN0ZW1JZFNldCI6WzAsMSwzNCwyMjcsMzYsMzcsMjMxLDIwMywxOSwyMSwyNDYsMjMsMjUsMjQ5LDI3LDMwXSwiaWF0IjoxNTc1MzQwMzg2fQ.2JEYMRx6wbJsMIMh3quyM14OsoMz_iJRq4Az_xz-WTc' : '$TOKEN$' %>",
apiHost : "<%= process.env.NODE_ENV === 'development' ? 'http://beacon.duibadev.com.cn' : '$API_HOST$' %>" apiHost : "<%= process.env.NODE_ENV === 'development' ? 'http://beacon.duibadev.com.cn' : '$API_HOST$' %>"
} }
</script> </script>
......
...@@ -52,9 +52,9 @@ export async function saveOne(project) { ...@@ -52,9 +52,9 @@ export async function saveOne(project) {
}) })
} }
export async function pack(id) { export async function pack(id, debug) {
return await fetchApi('/api/project/pack', { return await fetchApi('/api/project/pack', {
params: {id}, params: {id, debug},
method: 'post', method: 'post',
errMessage: 'Failed to pack project', errMessage: 'Failed to pack project',
}) })
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
export let API_HOST; export let API_HOST;
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
//API_HOST = 'http://10.10.95.74:7777'; //API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.94.134:7777'; //API_HOST = 'http://192.168.1.16:7777';
//API_HOST = 'http://10.10.92.33:7777';
//API_HOST = 'http://localhost:3002'; //API_HOST = 'http://localhost:3002';
API_HOST = window.__data.apiHost; API_HOST = window.__data.apiHost;
//API_HOST = ''; //API_HOST = '';
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"Close": "Close", "Close": "Close",
"Still Close": "Still Close", "Still Close": "Still Close",
"Save": "Save", "Save": "Save",
"Save And Preview": "Save And Preview",
"Reset": "Reset", "Reset": "Reset",
"Copy": "Copy", "Copy": "Copy",
"Exit": "Exit", "Exit": "Exit",
...@@ -78,6 +79,7 @@ ...@@ -78,6 +79,7 @@
"Env constant": "Env constant", "Env constant": "Env constant",
"Custom module": "Custom module", "Custom module": "Custom module",
"Copy template to clipboard": "Copy template to clipboard", "Copy template to clipboard": "Copy template to clipboard",
"Copied process to clipboard": "Copied process to clipboard",
"Link to parent": "Link to parent", "Link to parent": "Link to parent",
"Input project name": "Input project name", "Input project name": "Input project name",
"Invalid project name": "Invalid project name", "Invalid project name": "Invalid project name",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"Close": "关闭", "Close": "关闭",
"Still Close": "仍然关闭", "Still Close": "仍然关闭",
"Save": "保存", "Save": "保存",
"Save And Preview": "保存并预览",
"Reset": "重置", "Reset": "重置",
"Copy": "复制", "Copy": "复制",
"Exit": "退出", "Exit": "退出",
...@@ -78,6 +79,7 @@ ...@@ -78,6 +79,7 @@
"Env constant": "自定义常量", "Env constant": "自定义常量",
"Custom module": "自定义模块", "Custom module": "自定义模块",
"Copy template to clipboard": "复制模板到粘贴板", "Copy template to clipboard": "复制模板到粘贴板",
"Copied process to clipboard": "复制过程到粘贴板",
"Link to parent": "连接到父节点", "Link to parent": "连接到父节点",
"Input project name": "输入项目名", "Input project name": "输入项目名",
"Invalid project name": "无效的项目名", "Invalid project name": "无效的项目名",
......
...@@ -73,9 +73,7 @@ export const behaviorStore = { ...@@ -73,9 +73,7 @@ export const behaviorStore = {
state.originBehaviors[0] = state.currentBehavior; state.originBehaviors[0] = state.currentBehavior;
}, },
updateProcesses(state, {targetMetaID, replaceMetaID}) { updateProcesses(state, {targetMetaID, replaceMetaID}) {
for (let process of state.data.processes) { updateProcesses(state.data.processes, targetMetaID, replaceMetaID);
updateProcesses(process, targetMetaID, replaceMetaID);
}
}, },
deleteProcessMeta(state, {meta, process}) { deleteProcessMeta(state, {meta, process}) {
let container; let container;
......
...@@ -598,8 +598,8 @@ export const projectStore = { ...@@ -598,8 +598,8 @@ export const projectStore = {
}*/ }*/
return failedList; return failedList;
}, },
async packProject({state}) { async packProject({state}, debug) {
const result = await projectApi.pack(state.id); const result = await projectApi.pack(state.id, debug);
console.log(result); console.log(result);
return result; return result;
} }
......
...@@ -34,10 +34,13 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u ...@@ -34,10 +34,13 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u
<body> <body>
<div id="$CONTAINER_ID$" style="line-height:0;font-size:0"></div> <div id="$CONTAINER_ID$" style="line-height:0;font-size:0"></div>
<script src="http://10.10.94.134:4002/dist/index.js"></script> <script src="${process.env.NODE_ENV === 'development' ? 'http://10.10.94.134:4002/dist/index.js' : 'http://yun.duiba.com.cn/editor/zeroing/libs/engine.a913456caee2ee40c20108a1c4571f61479e54a1.js'}"></script>
<script src="$PROCESSES_URL$"></script>
<script src="$SCRIPTS_URL$"></script>
<script src="$CUSTOMS_URL$"></script>
<script> <script>
engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json'); engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json');
</script> </script>
</body> </body>
</html> </html>
`; `;
...@@ -9,6 +9,7 @@ $dock-pin-width: 9px; ...@@ -9,6 +9,7 @@ $dock-pin-width: 9px;
.el-dialog__body { .el-dialog__body {
flex: 1; flex: 1;
height: 0;
padding: 5px; padding: 5px;
} }
...@@ -320,8 +321,9 @@ $dock-pin-width: 9px; ...@@ -320,8 +321,9 @@ $dock-pin-width: 9px;
} }
.meta-editor-wrapper { .meta-editor-wrapper {
height: 40vh; //height: 40vh;
display: flex; display: flex;
height: 100%;
padding: 5px; padding: 5px;
flex-direction: column; flex-direction: column;
...@@ -332,6 +334,15 @@ $dock-pin-width: 9px; ...@@ -332,6 +334,15 @@ $dock-pin-width: 9px;
.script-editor { .script-editor {
flex: 1; flex: 1;
} }
.vue-codemirror{
flex: 1;
height: 0;
}
.CodeMirror {
height: 100%;
}
} }
.props-editor-dialog { .props-editor-dialog {
......
...@@ -14,7 +14,7 @@ export function messageError(e) { ...@@ -14,7 +14,7 @@ export function messageError(e) {
}) })
} }
export function playWaiting(promise, text) { export function playWaiting(promise, text, closeLoading = true) {
const loading = Loading.service({ const loading = Loading.service({
lock: true, lock: true,
text: text || i18n.t('In processing'), text: text || i18n.t('In processing'),
...@@ -24,7 +24,9 @@ export function playWaiting(promise, text) { ...@@ -24,7 +24,9 @@ export function playWaiting(promise, text) {
messageError(e); messageError(e);
throw e; throw e;
}).finally(() => { }).finally(() => {
if(closeLoading){
loading.close(); loading.close();
}
}) })
} }
...@@ -69,13 +71,18 @@ export function getInputDefaultValue(property) { ...@@ -69,13 +71,18 @@ export function getInputDefaultValue(property) {
return property ? property.hasOwnProperty('default') ? property.default + '' : 'unset' : 'unset'; return property ? property.hasOwnProperty('default') ? property.default + '' : 'unset' : 'unset';
} }
export function updateProcesses(process, targetMetaID, replaceMetaID) { export function updateProcesses(processes, targetMetaID, replaceMetaID) {
for (let process of processes) {
for (let key in process.sub) { for (let key in process.sub) {
let subProcess = process.sub[key]; let subProcess = process.sub[key];
if (subProcess.meta === targetMetaID) { if (subProcess.meta === targetMetaID) {
subProcess.meta = replaceMetaID; subProcess.meta = replaceMetaID;
} }
} }
if(process.metas){
updateProcesses(process.metas, targetMetaID, replaceMetaID)
}
}
} }
export function metaInUse(process, targetMetaID) { export function metaInUse(process, targetMetaID) {
...@@ -123,3 +130,15 @@ export function selectFile(callback, {accept, multiple} = {}) { ...@@ -123,3 +130,15 @@ export function selectFile(callback, {accept, multiple} = {}) {
} }
input.click(); input.click();
} }
export function openPreview(packResult){
setTimeout(() => {
let url;
if(location.host.startsWith('localhost')){
url = packResult.tplUrl;
}else{
url = '/preview?url=http:' + packResult.tplUrl;
}
window.open(url, 'blank');
}, 500);
}
...@@ -134,6 +134,11 @@ export default { ...@@ -134,6 +134,11 @@ export default {
type: 'textArea', type: 'textArea',
value: '' value: ''
}, },
htmlText: {
title: 'HTML内容',
type: 'input',
value: ''
},
fillColor: { fillColor: {
title: '颜色', title: '颜色',
type: 'colorPicker', type: 'colorPicker',
...@@ -150,10 +155,11 @@ export default { ...@@ -150,10 +155,11 @@ export default {
}, },
size: { size: {
title: '字体大小', title: '字体大小',
type: 'swSelect', type: 'inputNumber',
/*type: 'swSelect',
props: { props: {
optionType: 'fontSize' optionType: 'fontSize'
}, },*/
value: 12 value: 12
}, },
lineHeight: { lineHeight: {
...@@ -273,5 +279,12 @@ export default { ...@@ -273,5 +279,12 @@ export default {
type: 'inputNumber', type: 'inputNumber',
value: 20, value: 20,
}, },
} },
/*htmlView: {
groupName: 'HTML视图',
htmlElement: {
title: 'HTML内容',
type: 'input',
},
}*/
} }
...@@ -25,9 +25,10 @@ ...@@ -25,9 +25,10 @@
import Playground from "./Editor/Playground"; import Playground from "./Editor/Playground";
import Assets from "./Editor/Assets"; import Assets from "./Editor/Assets";
import DetailsDialog from "./Editor/dialogs/DetailsDialog"; import DetailsDialog from "./Editor/dialogs/DetailsDialog";
import {playWaiting} from "../utils"; import {openPreview, playWaiting} from "../utils";
import i18n from "../i18n"; import i18n from "../i18n";
import PackResultDialog from "./Editor/dialogs/PackResultDialog"; import PackResultDialog from "./Editor/dialogs/PackResultDialog";
import events from "@/global-events.js"
export default { export default {
name: 'Editor', name: 'Editor',
...@@ -50,7 +51,7 @@ ...@@ -50,7 +51,7 @@
}, },
watch: { watch: {
$route: { $route: {
handler: function(val, oldVal){ handler: function (val, oldVal) {
console.log('router changed'); console.log('router changed');
this.loadProject(); this.loadProject();
}, },
...@@ -63,29 +64,34 @@ ...@@ -63,29 +64,34 @@
async mounted() { async mounted() {
document.addEventListener('keydown', this.onKeyPress); document.addEventListener('keydown', this.onKeyPress);
await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {}); await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
});
this.loadProject(); this.loadProject();
}, },
destroyed(){ destroyed() {
document.removeEventListener('keydown', this.onKeyPress) document.removeEventListener('keydown', this.onKeyPress)
}, },
created(){
events.$on('saveAndPreview',()=>{
this.clickMenu("preview");
});
},
methods: { methods: {
prepare(){ prepare() {
return Promise.all([ return Promise.all([
this.updateEnv(), this.updateEnv(),
]) ])
}, },
onKeyPress(e){ onKeyPress(e) {
if(e.key === 's' && (e.ctrlKey||e.metaKey)){ if (e.key === 's' && (e.ctrlKey || e.metaKey)) {
e.preventDefault(); e.preventDefault();
this.clickMenu("preview");
this.saveProject();
return false; return false;
} }
}, },
async loadProject(){ async loadProject() {
const {projectID} = this.$route.params; const {projectID} = this.$route.params;
if (await this.localVersionExist(projectID)) { if (await this.localVersionExist(projectID)) {
this.$confirm(this.$t('Unsaved version found locally'), this.$t('Alert'), { this.$confirm(this.$t('Unsaved version found locally'), this.$t('Alert'), {
...@@ -111,7 +117,7 @@ ...@@ -111,7 +117,7 @@
loadLocalVersion(projectID) { loadLocalVersion(projectID) {
this.ready = false; this.ready = false;
this.loadFromLocal(projectID); this.loadFromLocal(projectID);
this.$nextTick(()=>{ this.$nextTick(() => {
this.ready = true; this.ready = true;
}); });
}, },
...@@ -121,7 +127,7 @@ ...@@ -121,7 +127,7 @@
await playWaiting(this.loadFromRemote(projectID), this.$t('Preparing')).catch(e => { await playWaiting(this.loadFromRemote(projectID), this.$t('Preparing')).catch(e => {
this.$alert(this.$t('Project does not exist'), this.$t('Alert'), { this.$alert(this.$t('Project does not exist'), this.$t('Alert'), {
confirmButtonText: this.$t('Confirm'), confirmButtonText: this.$t('Confirm'),
callback: action=>{ callback: action => {
this.$router.replace({name: 'home'}); this.$router.replace({name: 'home'});
} }
}); });
...@@ -139,8 +145,8 @@ ...@@ -139,8 +145,8 @@
this.panesConfig[id] = configs[0].width / 100; this.panesConfig[id] = configs[0].width / 100;
localStorage.panesConfig = JSON.stringify(this.panesConfig); localStorage.panesConfig = JSON.stringify(this.panesConfig);
}, },
async saveProject() { async saveProject(closeLoading) {
await playWaiting(this.saveToRemote(), this.$t('Saving')); await playWaiting(this.saveToRemote(), this.$t('Saving'), closeLoading);
this.$message({ this.$message({
message: i18n.t('Save project successfully'), //因为message是异步出现,但是当路由回退的时候,this.i18n的实例已经置空,所以要用全局的i18n实例 message: i18n.t('Save project successfully'), //因为message是异步出现,但是当路由回退的时候,this.i18n的实例已经置空,所以要用全局的i18n实例
type: 'success' type: 'success'
...@@ -157,6 +163,9 @@ ...@@ -157,6 +163,9 @@
case 'details': case 'details':
this.$refs.dialogsDialog.show(); this.$refs.dialogsDialog.show();
break; break;
case 'preview':
await this.pack(true);
break;
case 'pack': case 'pack':
await this.pack(); await this.pack();
break; break;
...@@ -188,20 +197,24 @@ ...@@ -188,20 +197,24 @@
break; break;
} }
}, },
async pack(){ async pack(debug = false) {
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: this.$t('Packing'), text: this.$t('Packing'),
}); });
try{ try {
await this.saveProject(); await this.saveProject(false);
const packResult = await this.packProject(); const packResult = await this.packProject(debug);
this.$message({ this.$message({
message: this.$t('Pack project successfully'), message: this.$t('Pack project successfully'),
type: 'success', type: 'success',
duration: 1000, duration: 500,
}); });
if (debug) {
openPreview(packResult);
} else {
this.$refs.packResultDialog.show(packResult); this.$refs.packResultDialog.show(packResult);
}
/*this.$confirm(this.$t('Pack project successfully'), this.$t('Alert'), { /*this.$confirm(this.$t('Pack project successfully'), this.$t('Alert'), {
confirmButtonText: this.$t('Open in new tab'), confirmButtonText: this.$t('Open in new tab'),
cancelButtonText: this.$t('Close'), cancelButtonText: this.$t('Close'),
...@@ -213,7 +226,7 @@ ...@@ -213,7 +226,7 @@
}).catch(() => { }).catch(() => {
});*/ });*/
}catch (e) { } catch (e) {
this.$message({ this.$message({
message: this.$t('Pack project failed'), message: this.$t('Pack project failed'),
type: 'error', type: 'error',
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
</div> </div>
</el-form> </el-form>
</el-scrollbar> </el-scrollbar>
<behavior-editor-dialog :behaviors="behaviors" @change="v => handleBehaviorsChange(v)" ref="behaviorEditorDialog"></behavior-editor-dialog> <behavior-editor-dialog :behaviors="behaviors" @change="isPreview => handleBehaviorsChange(isPreview)" ref="behaviorEditorDialog"></behavior-editor-dialog>
</div> </div>
</template> </template>
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import _ from 'lodash'; import _ from 'lodash';
import BehaviorEditorDialog from '../dialogs/BehaviorEditorDialog'; import BehaviorEditorDialog from '../dialogs/BehaviorEditorDialog';
import events from "@/global-events.js"
export default { export default {
name: 'BehaviorTab', name: 'BehaviorTab',
...@@ -93,7 +95,7 @@ export default { ...@@ -93,7 +95,7 @@ export default {
/** /**
* 行为发生变化,同步数据 * 行为发生变化,同步数据
*/ */
handleBehaviorsChange(v) { handleBehaviorsChange(isPreview) {
if (this.currentEvent /* && v && v.length*/) { if (this.currentEvent /* && v && v.length*/) {
let event = {}; let event = {};
let currentEvent = this.eventsObj[this.currentEvent]; let currentEvent = this.eventsObj[this.currentEvent];
...@@ -104,6 +106,10 @@ export default { ...@@ -104,6 +106,10 @@ export default {
}); });
this.updateEventsObj(); this.updateEventsObj();
} }
if(isPreview){
events.$emit('saveAndPreview')
}
}, },
/** /**
* 删除行为 * 删除行为
......
...@@ -42,6 +42,11 @@ ...@@ -42,6 +42,11 @@
return menu; return menu;
} }
}, },
async mounted() {
//监听键盘事件
document.addEventListener('keydown', this.onKeyPress);
},
methods: { methods: {
clickMenu(menuItem) { clickMenu(menuItem) {
this.$emit('click-menu', menuItem); this.$emit('click-menu', menuItem);
...@@ -60,6 +65,25 @@ ...@@ -60,6 +65,25 @@
}).catch(() => { }).catch(() => {
}); });
}, },
onKeyPress(e) {
if (e.key === 'z' && (e.ctrlKey || e.metaKey) && (!e.shiftKey)) {
//快捷键ctrl+z执行撤销
e.preventDefault();
//是否可执行撤销
if(!(!this.project.operateStack.length || this.project.operateStack.length === this.project.stackIndex + 1)){
this.clickMenu("undo");
}
return false;
}else if (e.key === 'z' && (e.ctrlKey || e.metaKey) && (e.shiftKey)) {
//快捷键ctrl+shift+z执行重做
e.preventDefault();
//是否可以执行重做
if(!(this.project.stackIndex === 0)){
this.clickMenu("redo");
}
return false;
}
},
...mapMutations([ ...mapMutations([
'modifyProject' 'modifyProject'
]), ]),
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
import EditPath from "./Board/EditPath"; import EditPath from "./Board/EditPath";
import Process from "./Board/Process"; import Process from "./Board/Process";
import MetaEditorDialog from "./MetaEditorDialog"; import MetaEditorDialog from "./MetaEditorDialog";
import events from "@/global-events.js"
export default { export default {
name: "BehaviorEditor", name: "BehaviorEditor",
...@@ -118,7 +120,7 @@ ...@@ -118,7 +120,7 @@
}); });
} }
}, },
onSaveMeta(meta) { onSaveMeta(meta,isPreview) {
let oldMetaID = this.metaInEditing.id; let oldMetaID = this.metaInEditing.id;
for (let key in meta) { for (let key in meta) {
this.metaInEditing[key] = meta[key]; this.metaInEditing[key] = meta[key];
...@@ -131,6 +133,10 @@ ...@@ -131,6 +133,10 @@
}); });
} }
this.$refs.board.updateProcessNode(meta.id); this.$refs.board.updateProcessNode(meta.id);
//是否预览
if(isPreview){
events.$emit('behaviorSave',isPreview)
}
}, },
...mapMutations([ ...mapMutations([
'updateProcesses', 'updateProcesses',
......
<template> <template>
<div class="board" @dragover="onDragOver" @drop="onDrop" v-resize="onResize"> <div class="board" @dragover="onDragOver" @drop="onDrop" @paste="onPaste" v-resize="onResize">
<div style="height: 1px;"></div>
<!--<el-scrollbar class="full-size">--> <!--<el-scrollbar class="full-size">-->
<svg ref="board" class="svg-board full-size" version="1.1" xmlns="http://www.w3.org/2000/svg" <svg ref="board" class="svg-board full-size" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" @mousedown="onBoardMouseDown"> xmlns:xlink="http://www.w3.org/1999/xlink" @mousedown="onBoardMouseDown">
...@@ -14,8 +15,9 @@ ...@@ -14,8 +15,9 @@
@click="onClickProcessNode(process, key)" @click="onClickProcessNode(process, key)"
@hover-pin="onPinHover" @hover-pin="onPinHover"
@leave-pin="onPinLeave" @leave-pin="onPinLeave"
@down-pin="onPintDown" @down-pin="onPinDown"
@delete="onProcessNodeDelete" @delete="onProcessNodeDelete"
@copy="onProcessNodeCopy"
@edit-meta="onEditMeta" @edit-meta="onEditMeta"
@dblclick="editSubProcess(process)" @dblclick="editSubProcess(process)"
@meta-modified="onProcessMetaModified" @meta-modified="onProcessMetaModified"
...@@ -25,7 +27,6 @@ ...@@ -25,7 +27,6 @@
</svg> </svg>
<!--</el-scrollbar>--> <!--</el-scrollbar>-->
<tool-tip ref="toolTip"/> <tool-tip ref="toolTip"/>
<inline-choose-dialog ref="inlineChooseDialog"/>
</div> </div>
</template> </template>
...@@ -39,13 +40,14 @@ ...@@ -39,13 +40,14 @@
import {DOCK_POINT_OFFSET} from "../../../config"; import {DOCK_POINT_OFFSET} from "../../../config";
import events from "../../../global-events"; import events from "../../../global-events";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
import InlineChooseDialog from "./InlineChooseDialog"; import copy from 'copy-to-clipboard'
import {clonePureObj} from "../../../utils";
const customs = ['custom', 'divider']; const customs = ['custom', 'divider'];
export default { export default {
name: "Board", name: "Board",
components: {InlineChooseDialog, ToolTip, LinkLine, ProcessNode,}, components: {ToolTip, LinkLine, ProcessNode,},
props: [], props: [],
data() { data() {
return { return {
...@@ -115,28 +117,31 @@ ...@@ -115,28 +117,31 @@
const process = new Process(this.process, data, this.resolveProcess); const process = new Process(this.process, data, this.resolveProcess);
this.$set(this.subProcessMap, uuid, process); this.$set(this.subProcessMap, uuid, process);
}, },
showInlineChoose() {
return this.$confirm(this.$t('As inline'));
},
async addSubProcessData(processId, pos) { async addSubProcessData(processId, pos) {
let meta, isInline; let meta, isInline;
if (customs.includes(processId)) { if (customs.includes(processId)) {
try { try {
const result = await this.$refs.inlineChooseDialog.show(); await this.showInlineChoose();
isInline = result.isInline; isInline = true;
} catch (e) { } catch (e) {
return;
} }
meta = await this.addCustomProcessMeta({masterProcess: this.process, isInline, processId}); meta = await this.addCustomProcessMeta({masterProcess: this.process, isInline, processId});
}else{ } else {
meta = this.process.resolveMeta(processId); meta = this.process.resolveMeta(processId);
} }
if(meta.isPrefab){ if (meta.isPrefab) {
try { try {
const result = await this.$refs.inlineChooseDialog.show(); await this.showInlineChoose();
isInline = result.isInline; isInline = true;
} catch (e) { } catch (e) {
return;
} }
meta = await this.addProcessFromPrefab({masterProcess: this.process, isInline, meta}) meta = await this.addProcessFromPrefab({masterProcess: this.process, isInline, meta})
} }
...@@ -170,7 +175,7 @@ ...@@ -170,7 +175,7 @@
const data = await this.addSubProcessData(processId, { const data = await this.addSubProcessData(processId, {
x: e.offsetX - this.boardOffset.x - 9, x: e.offsetX - this.boardOffset.x - 9,
y: e.offsetY - this.boardOffset.y, y: e.offsetY - this.boardOffset.y - 20,
}); });
if (!data) { if (!data) {
return; return;
...@@ -181,6 +186,30 @@ ...@@ -181,6 +186,30 @@
events.$emit('update-dock-pin-pos'); events.$emit('update-dock-pin-pos');
}); });
}, },
onPaste(e) {
let dataStr = e.clipboardData.getData("process-data");
if (dataStr) {
this.addProcessFromCopy(dataStr);
}
},
addProcessFromCopy(avatar){
if(typeof avatar === 'string'){
avatar = JSON.parse(avatar);
}
avatar.uuid = generateUUID();
avatar.design.x += 20;
avatar.design.y += 20;
avatar.output = {};
delete avatar.design['output'];
delete avatar.design['input'];
this.$set(this.process.meta.sub, avatar.uuid, avatar);
this.addSubProcess(avatar.uuid, avatar);
this.$nextTick(() => {
events.$emit('update-dock-pin-pos');
});
},
onResize() { onResize() {
const {x, y} = this.$el.getBoundingClientRect(); const {x, y} = this.$el.getBoundingClientRect();
this.drawState.boardOffset.x = x + this.boardOffset.x; this.drawState.boardOffset.x = x + this.boardOffset.x;
...@@ -228,7 +257,7 @@ ...@@ -228,7 +257,7 @@
onPinLeave(x, y, pin) { onPinLeave(x, y, pin) {
this.$refs.toolTip.hide(); this.$refs.toolTip.hide();
}, },
onPintDown(e, process, pin) { onPinDown(e, process, pin) {
document.addEventListener("mousemove", this.onMouseMove); document.addEventListener("mousemove", this.onMouseMove);
document.addEventListener("mouseup", this.onMouseUp); document.addEventListener("mouseup", this.onMouseUp);
...@@ -286,6 +315,20 @@ ...@@ -286,6 +315,20 @@
}); });
} }
}, },
onProcessNodeCopy(data, meta) {
if(meta.isInline){ //内联直接复制
let avatar = clonePureObj(data);
this.addProcessFromCopy(avatar);
}else{
copy(JSON.stringify(data), {format: 'process-data'});
this.$message({
message: this.$t('Copied process to clipboard'),
type: 'success',
duration: 700,
});
}
},
onEditMeta(data, meta) { onEditMeta(data, meta) {
this.$emit('edit-meta', meta); this.$emit('edit-meta', meta);
}, },
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<div class="top-bar" v-if="meta.id !== 'entry' && editable"> <div class="top-bar" v-if="meta.id !== 'entry' && editable">
<el-link icon="el-icon-delete" :underline="false" @mousedown.stop.prevent @click.stop="onClickDelete"/> <el-link icon="el-icon-delete" :underline="false" @mousedown.stop.prevent @click.stop="onClickDelete"/>
<el-link icon="el-icon-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider" @mousedown.stop.prevent @click.stop="onClickEdit"/> <el-link icon="el-icon-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider" @mousedown.stop.prevent @click.stop="onClickEdit"/>
<el-link icon="el-icon-document-copy" :underline="false" @mousedown.stop.prevent @click.stop="onClickCopy"/>
</div> </div>
<div class="header"> <div class="header">
<i v-if="meta.isInline">i</i> <i v-if="meta.isInline">i</i>
...@@ -231,6 +232,9 @@ ...@@ -231,6 +232,9 @@
onClickEdit() { onClickEdit() {
this.$emit('edit-meta', this.data, this.meta); this.$emit('edit-meta', this.data, this.meta);
}, },
onClickCopy() {
this.$emit('copy', this.data, this.meta);
},
outputPointModify(action) { outputPointModify(action) {
let output = this.meta.output; let output = this.meta.output;
let count = output.length; let count = output.length;
......
<template>
<el-dialog
:title="$t('Alert')"
:visible.sync="dialogVisible"
append-to-body
@close="onClose"
>
<el-checkbox v-model="asInline">{{$t('As inline')}}</el-checkbox>
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="dialogVisible = false">{{$t('Cancel')}}</el-button>
<el-button size="mini" type="primary" @click="onConfirm">{{$t('Confirm')}}</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: "InlineChooseDialog",
data() {
return {
dialogVisible: false,
asInline: false,
}
},
methods: {
show() {
this.dialogVisible = true;
return new Promise((resolve, reject) => {
this.p = {resolve, reject};
});
},
onClose() {
if (this.p) {
this.p.reject();
this.p = null;
}
this.dialogVisible = false;
},
onConfirm() {
if (this.p) {
this.p.resolve({
isInline: this.asInline,
});
this.p = null;
}
this.dialogVisible = false;
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template> <template>
<el-dialog :title="$t('Meta Editor')" width="80%" :visible.sync="visible" <el-dialog :title="$t('Meta Editor')" width="80%" :visible.sync="visible"
:close-on-click-modal="false" :close-on-click-modal="false"
:append-to-body="true"> :close-on-press-escape="false"
:show-close="false"
fullscreen
:append-to-body="true"
custom-class="behavior-editor-dialog"
>
<div class="meta-editor-wrapper"> <div class="meta-editor-wrapper">
<el-form ref="form" v-if="meta" :model="meta" :rules="rules" :show-message="false" class="info-editor" size="mini" label-position="right" label-width="70px" @submit.native.prevent> <el-form ref="form" v-if="meta" :model="meta" :rules="rules" :show-message="false" class="info-editor" size="mini" label-position="right" label-width="70px" @submit.native.prevent>
<template> <template>
...@@ -37,10 +42,17 @@ ...@@ -37,10 +42,17 @@
</template> </template>
</el-form> </el-form>
<div style="margin-top: 5px;"> <div style="margin-top: 5px;">
<el-tag v-for="item in exposeVariables" size="mini">{{item}}</el-tag> <el-tag v-for="(item, key) in exposeVariables" :key="key" size="mini">{{item}}</el-tag>
</div> </div>
<el-input v-if="meta" class="script-editor" :readonly=" !editable" type="textarea" :placeholder="$t('Code')" <!--<el-input v-if="meta" class="script-editor" :readonly=" !editable" type="textarea" :placeholder="$t('Code')"
v-model="meta.script"></el-input> v-model="meta.script"></el-input>-->
<codemirror ref="codeEditor" v-if="meta"
v-model="meta.script"
:options="cmOptions"
@cursorActivity="onCodeChange"
>
</codemirror>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div class="button-bar"> <div class="button-bar">
...@@ -52,7 +64,8 @@ ...@@ -52,7 +64,8 @@
</el-popover> </el-popover>
</el-button-group> </el-button-group>
<el-button size="mini" plain @click="cancel">{{$t('Cancel')}}</el-button> <el-button size="mini" plain @click="cancel">{{$t('Cancel')}}</el-button>
<el-button size="mini" plain @click="save">{{$t('Save')}}</el-button> <el-button size="mini" plain @click="save(true)">{{$t('Save And Preview')}}</el-button>
<el-button size="mini" plain @click="save(false)">{{$t('Save')}}</el-button>
</div> </div>
</div> </div>
<props-editor-dialog ref="propsEditorDialog"/> <props-editor-dialog ref="propsEditorDialog"/>
...@@ -62,14 +75,24 @@ ...@@ -62,14 +75,24 @@
<script> <script>
import ElFormItem from "./inputs/form-item"; import ElFormItem from "./inputs/form-item";
import PropsEditorDialog from "./PropsEditorDialog"; import PropsEditorDialog from "./PropsEditorDialog";
import {codemirror} from "vue-codemirror";
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import {clonePureObj} from "../../../utils"; import {clonePureObj} from "../../../utils";
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/monokai.css'
import 'codemirror/addon/edit/closebrackets.js'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/javascript-hint.js'
import events from "@/global-events.js"
const exposeVariables = ['args', 'props', 'target', 'global', 'vm', 'engine']; const exposeVariables = ['args', 'props', 'target', 'global', 'vm', 'engine'];
export default { export default {
name: "MetaEditorDialog", name: "MetaEditorDialog",
components: {PropsEditorDialog, ElFormItem}, components: {PropsEditorDialog, ElFormItem, codemirror},
data() { data() {
return { return {
visible: false, visible: false,
...@@ -85,7 +108,20 @@ ...@@ -85,7 +108,20 @@
{ required: true, trigger: 'blur' } { required: true, trigger: 'blur' }
], ],
}, },
cmOptions: {
tabSize: 2,
mode: 'text/javascript',
styleActiveLine: true,
theme: 'default',
lineNumbers: true,
line: true,
matchBrackets: true,
autoCloseBrackets: true,
}
} }
},
mounted(){
}, },
computed: { computed: {
editable() { editable() {
...@@ -104,7 +140,7 @@ ...@@ -104,7 +140,7 @@
onClickEditProps() { onClickEditProps() {
this.$refs.propsEditorDialog.edit(this.meta.props); this.$refs.propsEditorDialog.edit(this.meta.props);
}, },
save() { save(isPreview) {
this.$refs.form.validate((valid) => { this.$refs.form.validate((valid) => {
if (valid) { if (valid) {
if (this.oldMetaID !== this.meta.id && this.$store.getters.metaIDExists(this.meta.id)) { if (this.oldMetaID !== this.meta.id && this.$store.getters.metaIDExists(this.meta.id)) {
...@@ -112,8 +148,8 @@ ...@@ -112,8 +148,8 @@
.catch((e) => { .catch((e) => {
}); });
} else { } else {
this.$emit('input', this.meta); this.$emit('input',this.meta,isPreview);
this.visible = false; this.visible=false;
} }
} else { } else {
return false; return false;
...@@ -143,6 +179,10 @@ ...@@ -143,6 +179,10 @@
focusPasteBoard(){ focusPasteBoard(){
this.$refs.pasteBoard.focus(); this.$refs.pasteBoard.focus();
}, },
onCodeChange(codemirror){
//codemirror.showHint();
//console.log(code);
}
} }
} }
</script> </script>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<dynamic-selector style="flex: 1;" v-model="item.value" <dynamic-selector style="flex: 1;" v-model="item.value"
:editable="editable"/> :editable="editable"/>
<el-button class="delete-button" icon="el-icon-minus" size="mini" plain circle type="danger" <el-button class="delete-button" icon="el-icon-minus" size="mini" plain circle type="danger"
@click="addMapItem"/> @click="deleteMapItem(index)"/>
</div> </div>
</div> </div>
<div class="bottom-bar"> <div class="bottom-bar">
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
addMapItem() { addMapItem() {
this.editValue.push({}); this.editValue.push({});
}, },
deleteMapItem(index) {
this.editValue.splice(index, 1);
},
save() { save() {
let v = {type: 'map', value: {}}; let v = {type: 'map', value: {}};
for (let item of this.editValue) { for (let item of this.editValue) {
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
:append-to-body="true" custom-class="behavior-editor-dialog"> :append-to-body="true" custom-class="behavior-editor-dialog">
<behavior-editor v-if="editorReady" ref="behaviorEditor" class="full-size"></behavior-editor> <behavior-editor v-if="editorReady" ref="behaviorEditor" class="full-size"></behavior-editor>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" @click="onSave(false)">{{$t('Save')}}</el-button>
<el-button size="mini" type="primary" @click="onSave(true)">{{$t('Save And Preview')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
...@@ -12,6 +13,8 @@ ...@@ -12,6 +13,8 @@
<script> <script>
import {mapState, mapMutations} from 'vuex' import {mapState, mapMutations} from 'vuex'
import BehaviorEditor from "../behavior-editor/BehaviorEditor"; import BehaviorEditor from "../behavior-editor/BehaviorEditor";
import events from "@/global-events.js"
export default { export default {
name: "BehaviorEditorDialog", name: "BehaviorEditorDialog",
...@@ -28,6 +31,11 @@ ...@@ -28,6 +31,11 @@
}), }),
}, },
created(){
events.$on('behaviorSave',(isPreview)=>{
this.onSave(isPreview)
});
},
methods: { methods: {
show(behaviors, event) { show(behaviors, event) {
this.behavior_startEdit({ this.behavior_startEdit({
...@@ -38,10 +46,9 @@ ...@@ -38,10 +46,9 @@
this.editorReady = false; this.editorReady = false;
this.visible = true; this.visible = true;
}, },
onSave() { onSave(isPreview) {
this.behavior_save(); this.behavior_save();
this.visible = false; this.$emit('change',isPreview);
this.$emit('change');
}, },
beforeClose(done) { beforeClose(done) {
this.$confirm(this.$t('Save this behavior before'), this.$t('Alert'), { this.$confirm(this.$t('Save this behavior before'), this.$t('Alert'), {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
<script> <script>
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import {openPreview} from "../../../utils";
export default { export default {
name: "PackResultDialog", name: "PackResultDialog",
...@@ -40,9 +41,7 @@ ...@@ -40,9 +41,7 @@
openInNewTab() { openInNewTab() {
this.visible = false; this.visible = false;
setTimeout(()=>{ openPreview(this.packResult);
window.open(this.packResult.tplUrl, 'blank');
}, 500);
}, },
copy() { copy() {
this.visible = false; this.visible = false;
......
...@@ -10,7 +10,7 @@ module.exports = { ...@@ -10,7 +10,7 @@ module.exports = {
enableInSFC: true enableInSFC: true
} }
}, },
devServer: { /*devServer: {
host: '0.0.0.0', host: '0.0.0.0',
port: '8080', port: '8080',
proxy: { proxy: {
...@@ -21,7 +21,7 @@ module.exports = { ...@@ -21,7 +21,7 @@ module.exports = {
target: serverHost, target: serverHost,
}, },
} }
}, },*/
configureWebpack: { configureWebpack: {
} }
......
...@@ -2365,6 +2365,11 @@ code-point-at@^1.0.0: ...@@ -2365,6 +2365,11 @@ code-point-at@^1.0.0:
resolved "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" resolved "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
codemirror@^5.41.0:
version "5.49.2"
resolved "https://registry.npm.taobao.org/codemirror/download/codemirror-5.49.2.tgz#c84fdaf11b19803f828b0c67060c7bc6d154ccad"
integrity sha1-yE/a8RsZgD+CiwxnBgx7xtFUzK0=
collection-visit@^1.0.0: collection-visit@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" resolved "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
...@@ -3117,6 +3122,11 @@ detect-node@^2.0.4: ...@@ -3117,6 +3122,11 @@ detect-node@^2.0.4:
resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha1-AU7o+PZpxcWAI9pkuBecCDooxGw= integrity sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=
diff-match-patch@^1.0.0:
version "1.0.4"
resolved "https://registry.npm.taobao.org/diff-match-patch/download/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
integrity sha1-asS1UjdGN2HE2vDcYD64aRJHRLE=
diff@^4.0.1: diff@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.npm.taobao.org/diff/download/diff-4.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdiff%2Fdownload%2Fdiff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" resolved "https://registry.npm.taobao.org/diff/download/diff-4.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdiff%2Fdownload%2Fdiff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
...@@ -9430,6 +9440,14 @@ vue-cli-plugin-i18n@^0.6.0: ...@@ -9430,6 +9440,14 @@ vue-cli-plugin-i18n@^0.6.0:
vue-i18n "^8.0.0" vue-i18n "^8.0.0"
vue-i18n-extract "^0.4.13" vue-i18n-extract "^0.4.13"
vue-codemirror@^4.0.6:
version "4.0.6"
resolved "https://registry.npm.taobao.org/vue-codemirror/download/vue-codemirror-4.0.6.tgz#b786bb80d8d762a93aab8e46f79a81006f0437c4"
integrity sha1-t4a7gNjXYqk6q45G95qBAG8EN8Q=
dependencies:
codemirror "^5.41.0"
diff-match-patch "^1.0.0"
vue-draggable-resizable@^2.0.1: vue-draggable-resizable@^2.0.1:
version "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" resolved "https://registry.npm.taobao.org/vue-draggable-resizable/download/vue-draggable-resizable-2.0.1.tgz#fb98d0997b1cfa8e3ba90f723cf8b605012cd96d"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment