Commit 6456ad0f authored by rockyl's avatar rockyl

提交一下

parent 39f9e6a6
...@@ -62,7 +62,11 @@ function execute(document) { ...@@ -62,7 +62,11 @@ function execute(document) {
} }
return 1; return 1;
} else if (layer.name.match(excludeFlagReg)) { } else if (layer.name.match(excludeFlagReg)) {
layer.remove(); try {
layer.remove();
}catch (e) {
alert('移除图层' + layer.name + '失败,可能含有锁的层');
}
return 2; return 2;
} }
return 0; return 0;
......
{ {
"name": "zeroing-editor", "name": "zeroing-editor",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"upload": "cp dist/index.html ../duiba-aurora-node/src/public/index.html&&ali-oss-publish -c oss.config.js -e dist", "upload": "node scripts/copy-index.js && ali-oss-publish -c oss.config.js -e dist",
"build:upload": "npm run build&&npm run upload", "build:upload": "npm run build&&npm run upload",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'" "i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'"
}, },
"dependencies": { "dependencies": {
"cookie": "^0.4.0", "cookie": "^0.4.0",
"copy-to-clipboard": "^3.2.0", "copy-to-clipboard": "^3.2.0",
"core-js": "^2.6.5", "core-js": "^2.6.5",
"element-ui": "^2.4.5", "element-ui": "^2.4.5",
"jszip": "^3.2.2", "indexdbwrapper": "^1.0.4",
"moment": "^2.24.0", "jszip": "^3.2.2",
"path": "^0.12.7", "moment": "^2.24.0",
"querystringify": "^2.1.1", "path": "^0.12.7",
"splitpanes": "^1.14.5", "querystringify": "^2.1.1",
"string-width": "^4.1.0", "socket.io-client": "^2.3.0",
"uuid": "^3.3.3", "splitpanes": "^1.14.5",
"vue": "^2.6.10", "string-width": "^4.1.0",
"vue-codemirror": "^4.0.6", "uuid": "^3.3.3",
"vue-i18n": "^8.0.0", "vue": "^2.6.10",
"vue-router": "^3.0.3", "vue-codemirror": "^4.0.6",
"vuex": "^3.0.1" "vue-i18n": "^8.0.0",
}, "vue-router": "^3.0.3",
"devDependencies": { "vuex": "^3.0.1",
"@kazupon/vue-i18n-loader": "^0.3.0", "zeroing-code-divider": "http://gitlab2.dui88.com/laoqifeng/zeroing-code-divider.git"
"@vue/cli-plugin-babel": "^3.11.0", },
"@vue/cli-service": "^3.11.0", "devDependencies": {
"ali-oss-publish": "^0.3.0", "@kazupon/vue-i18n-loader": "^0.3.0",
"lodash": "^4.17.15", "@vue/cli-plugin-babel": "^3.11.0",
"node-sass": "^4.9.2", "@vue/cli-service": "^3.11.0",
"sass": "^1.22.9", "ali-oss-publish": "^0.3.0",
"sass-loader": "^7.2.0", "lodash": "^4.17.15",
"vue-cli-plugin-element": "^1.0.1", "node-sass": "^4.9.2",
"vue-cli-plugin-i18n": "^0.6.0", "sass": "^1.22.9",
"vue-draggable-resizable": "^2.0.1", "sass-loader": "^7.2.0",
"vue-template-compiler": "^2.6.10" "vue-cli-plugin-element": "^1.0.1",
}, "vue-cli-plugin-i18n": "^0.6.0",
"appVersion": "0.1.0" "vue-draggable-resizable": "^2.0.1",
"vue-template-compiler": "^2.6.10"
},
"appVersion": "0.1.0"
} }
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>烽火台</title> <title>烽火台</title>
<script src="https://cdn.bootcss.com/jshint/2.10.2/jshint.min.js"></script>
<script src="https://cdn.bootcss.com/jsonlint/1.6.0/jsonlint.min.js"></script>
</head> </head>
<body> <body>
<noscript> <noscript>
......
/**
* Created by rockyl on 2019-12-26.
*/
const fs = require('fs');
fs.copyFileSync('dist/index.html', '../duiba-aurora-node/src/public/index.html');
const now = Date.now();
fs.copyFileSync('dist/index.html', `dist/index.${now}.html`);
console.log('node update-editor.js', now);
/**
* Created by rockyl on 2019-12-25.
*/
import io from 'socket.io-client';
import events from './global-events';
let socket;
export let codeSyncServeEnabled = false;
export function startCodeSyncServe(config) {
if (socket) {
socket.close();
}
socket = io(`http://${config.ip}:${config.port}`);
socket.on('connect', onConnect);
socket.on('disconnect', onDisconnect);
socket.on('edit-save', onEditSave);
events.$on('edit-open', editCode);
}
export function stop() {
}
export function editCode(code) {
socket.emit('edit-open', code);
}
function onConnect() {
codeSyncServeEnabled = true;
events.$emit('code-sync-start');
}
function onDisconnect() {
socket = null;
codeSyncServeEnabled = false;
events.$emit('code-sync-stop');
}
function onEditSave(data) {
events.$emit('edit-save', data)
}
<template>
<div style="width: 100%; height: 100%" ref="container"></div>
</template>
<script>
import * as monaco from 'monaco-editor';
export default {
name: "MonacoEditor",
data() {
return {
}
},
props: {
value: {
type: String,
default: '',
},
language: {
type: String,
default: 'javascript',
},
theme: {
type: String,
default: 'vs',
},
editorOptions: {
type: Object,
default: function(){
return {
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: false, // 只读
cursorStyle: 'line', //光标样式
automaticLayout: false, //自动布局
glyphMargin: true, //字形边缘
useTabStops: false,
fontSize: 28, //字体大小
autoIndent:true,//自动布局
}
},
},
},
mounted() {
this.initEditor();
},
watch: {
value(value){
if(this.editor && value !== this.editor.getValue()){
this.editor.setValue(value);
}
}
},
methods: {
initEditor() {
this.editor = monaco.editor.create(this.$refs.container, {
value: this.value,
language: this.language,
theme: this.theme,
lineNumbers: 'on',
tabSize: 2,
insertSpaces: false,
editorOptions: this.editorOptions,
});
this.editor.onDidChangeModelContent(event => {
const value = this.editor.getValue();
this.$emit('input', value);
});
this.editor.updateOptions({
})
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -30,7 +30,6 @@ export default { ...@@ -30,7 +30,6 @@ export default {
methods: { methods: {
drop(e) { drop(e) {
if (this.$store.state.project.dragUUID) { if (this.$store.state.project.dragUUID) {
// debugger;
console.log('native drop', this.$store.state); console.log('native drop', this.$store.state);
this.swvalue = `asset://${this.$store.state.project.dragUUID}` this.swvalue = `asset://${this.$store.state.project.dragUUID}`
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"Add": "Add", "Add": "Add",
"Delete": "Delete", "Delete": "Delete",
"Delete all": "Delete all", "Delete all": "Delete all",
"Not delete": "Not delete",
"Import": "Import", "Import": "Import",
"Export": "Export", "Export": "Export",
"Importing project": "Importing project", "Importing project": "Importing project",
...@@ -28,13 +29,20 @@ ...@@ -28,13 +29,20 @@
"EditEnv": "EditEnv", "EditEnv": "EditEnv",
"EditCustomModule": "EditCustomModule", "EditCustomModule": "EditCustomModule",
"Script": "Script", "Script": "Script",
"CodeSyncServe": "CodeSyncServe",
"ID": "ID", "ID": "ID",
"Mock Editor": "Mock Editor",
"Enable mock serve": "Enable mock serve",
"Name": "Name", "Name": "Name",
"Alias": "Alias", "Alias": "Alias",
"Output": "Output", "Output": "Output",
"Code": "Code", "Code": "Code",
"Desc": "Desc", "Desc": "Desc",
"Empty": "Empty", "Empty": "Empty",
"Path": "Path",
"Timeout": "Timeout",
"SuccessRatio": "SuccessRatio",
"Data": "Data",
"Key": "Key", "Key": "Key",
"Default": "Default", "Default": "Default",
"Event": "Event", "Event": "Event",
...@@ -147,9 +155,9 @@ ...@@ -147,9 +155,9 @@
"menu": { "menu": {
"save": "Save", "save": "Save",
"details": "Details", "details": "Details",
"preview": "Preview", "preview-fast": "Preview",
"preview2": "Fast-Preview",
"publish": "Publish", "publish": "Publish",
"mock": "Mock",
"exit": "Exit", "exit": "Exit",
"undo": "Undo", "undo": "Undo",
"redo": "Redo" "redo": "Redo"
...@@ -159,7 +167,8 @@ ...@@ -159,7 +167,8 @@
"image": "Image", "image": "Image",
"label": "Label", "label": "Label",
"rect": "Rect", "rect": "Rect",
"scrollView": "ScrollView" "scrollView": "ScrollView",
"svga": "SVGA"
}, },
"panes": { "panes": {
"Assets": "Assets", "Assets": "Assets",
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"Add": "添加", "Add": "添加",
"Delete": "删除", "Delete": "删除",
"Delete all": "删除全部", "Delete all": "删除全部",
"Not delete": "不删除",
"Import": "导入", "Import": "导入",
"Export": "导出", "Export": "导出",
"Importing project": "项目导入中", "Importing project": "项目导入中",
...@@ -28,13 +29,20 @@ ...@@ -28,13 +29,20 @@
"EditEnv": "编辑环境", "EditEnv": "编辑环境",
"EditCustomModule": "编辑自定义模块", "EditCustomModule": "编辑自定义模块",
"Script": "脚本", "Script": "脚本",
"CodeSyncServe": "代码同步服务",
"ID": "ID", "ID": "ID",
"Mock Editor": "Mock编辑器",
"Enable mock serve": "启用Mock服务",
"Name": "名字", "Name": "名字",
"Alias": "别名", "Alias": "别名",
"Output": "输出", "Output": "输出",
"Code": "代码", "Code": "代码",
"Desc": "描述", "Desc": "描述",
"Empty": "空", "Empty": "空",
"Path": "路径",
"Timeout": "超时(ms)",
"SuccessRatio": "成功率",
"Data": "数据",
"Key": "属性名", "Key": "属性名",
"Default": "默认值", "Default": "默认值",
"Event": "事件", "Event": "事件",
...@@ -151,9 +159,9 @@ ...@@ -151,9 +159,9 @@
"menu": { "menu": {
"save": "保存", "save": "保存",
"details": "详情", "details": "详情",
"preview": "预览", "preview-fast": "预览",
"preview2": "快速预览",
"publish": "发布", "publish": "发布",
"mock": "Mock",
"exit": "退出", "exit": "退出",
"undo": "撤销", "undo": "撤销",
"redo": "重做" "redo": "重做"
...@@ -165,7 +173,8 @@ ...@@ -165,7 +173,8 @@
"rect": "矩形", "rect": "矩形",
"circle": "圆形", "circle": "圆形",
"textinput": "输入框", "textinput": "输入框",
"scrollView": "滚动视图" "scrollView": "滚动视图",
"svga": "SVGA"
}, },
"panes": { "panes": {
"Assets": "素材", "Assets": "素材",
......
...@@ -39,15 +39,10 @@ export default new Vuex.Store({ ...@@ -39,15 +39,10 @@ export default new Vuex.Store({
'modifyAsset', 'modifyAsset',
'importView', 'importView',
'importAssets', 'importAssets',
'addDataMapping',
'deleteDataMapping',
'modifyDataMapping',
'addEnvMapping',
'deleteEnvMapping',
'modifyEnvMapping',
'modifyActiveView', 'modifyActiveView',
'behavior_save', 'behavior_save',
'modifyCustoms', 'modifyProjectDetails',
'modifyMocks',
] ]
}) })
] ]
......
...@@ -64,7 +64,6 @@ export const behaviorStore = { ...@@ -64,7 +64,6 @@ export const behaviorStore = {
state.processStack.push(process); state.processStack.push(process);
updatePropsEditable(state); updatePropsEditable(state);
state.currentProcess = process; state.currentProcess = process;
console.log(state.currentProcess);
}, },
popProcessStack(state, index) { popProcessStack(state, index) {
state.processStack.splice(index); state.processStack.splice(index);
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
import {envApi} from "../../api"; import {envApi} from "../../api";
import i18n from "../../i18n"; import i18n from "../../i18n";
const storeKey = 'code-sync-serve-config';
export const envStore = { export const envStore = {
state: { state: {
initialized: false, initialized: false,
...@@ -19,6 +21,10 @@ export const envStore = { ...@@ -19,6 +21,10 @@ export const envStore = {
processes: [], processes: [],
scripts: [], scripts: [],
customs: [], customs: [],
codeSyncServeConfig: {
ip: 'localhost',
port: 7788,
}
}, },
mutations: { mutations: {
updateEnv(state, env) { updateEnv(state, env) {
...@@ -28,6 +34,15 @@ export const envStore = { ...@@ -28,6 +34,15 @@ export const envStore = {
state.customs = parseItem(state.customs); state.customs = parseItem(state.customs);
state.initialized = true; state.initialized = true;
let configStr = localStorage.getItem(storeKey);
if (configStr) {
state.codeSyncServeConfig = JSON.parse(configStr);
}
},
saveCodeSyncServeConfig(state, config) {
state.codeSyncServeConfig = config;
localStorage.setItem(storeKey, JSON.stringify(state.codeSyncServeConfig));
}, },
}, },
getters: { getters: {
...@@ -77,7 +92,7 @@ export const envStore = { ...@@ -77,7 +92,7 @@ export const envStore = {
const env = await envApi.fetchEnv(); const env = await envApi.fetchEnv();
commit('updateEnv', env); commit('updateEnv', env);
} }
} },
} }
}; };
......
This diff is collapsed.
...@@ -16,14 +16,16 @@ export const projectsStore = { ...@@ -16,14 +16,16 @@ export const projectsStore = {
state.projectCount = projectCount; state.projectCount = projectCount;
}, },
addProject(state, project) { addProject(state, project) {
state.unshift(project); state.projects.unshift(project);
}, },
deleteProject(state, projectID) { deleteProject(state, projectID) {
for (let i = 0, li = state.length; i < li; i++) { const {projects} = state;
const item = state[i];
for (let i = 0, li = projects.length; i < li; i++) {
const item = projects[i];
if (item.id === projectID) { if (item.id === projectID) {
state.splice(i, 1); projects.splice(i, 1);
break; break;
} }
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
*/ */
export const template = export const template =
`<!DOCTYPE html> `<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
...@@ -17,24 +17,24 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u ...@@ -17,24 +17,24 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u
<meta name="x5-fullscreen" content="true"/> <meta name="x5-fullscreen" content="true"/>
<meta name="360-fullscreen" content="true"/> <meta name="360-fullscreen" content="true"/>
<style> <style>
html, html,
body { body {
padding: 0; padding: 0;
margin: 0; margin: 0;
border: 0; border: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
background-color: white; background-color: white;
} }
</style> </style>
</head> </head>
<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="${process.env.NODE_ENV === 'development' ? 'http://10.10.94.134:4002/dist/index.js' : 'http://yun.duiba.com.cn/editor/zeroing/libs/engine.d20665eae76962ad21c153fe7a719130b08e292c.js'}"></script> <script src="${process.env.NODE_ENV === 'development' ? 'http://10.10.92.100:4002/debug/engine.js' : 'http://yun.duiba.com.cn/editor/zeroing/libs/engine.269ce0ee2f951a11e004eee2df2fa1d875fa0b62.js'}"></script>
$SCRIPTS$ $SCRIPTS$
<script> <script>
engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json'); engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json');
......
...@@ -2,16 +2,7 @@ ...@@ -2,16 +2,7 @@
$dock-pin-width: 9px; $dock-pin-width: 9px;
.behavior-editor-dialog { .behavior-editor-dialog {
display: flex;
flex-direction: column;
.el-dialog__body {
flex: 1;
height: 0;
padding: 5px;
}
.process-pane { .process-pane {
......
@import "var";
.code-sync-indicator {
padding: 5px;
cursor: pointer;
.indicator {
background-color: red;
width: 10px;
height: 10px;
border-radius: 50%;
}
.indicator.enabled {
background-color: limegreen;
}
}
.bottom-bar{
height: 20px;
display: flex;
align-items: center;
font-size: 12px;
color: $--color-text-secondary;
padding: 0 5px;
.editor-status{
}
.file-upload-indicator {
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
@import "views"; @import "views";
@import "assets"; @import "assets";
@import "behavior"; @import "behavior";
@import "bottom-bar";
.editor { .editor {
display: flex; display: flex;
...@@ -25,10 +26,6 @@ ...@@ -25,10 +26,6 @@
} }
} }
.file-upload-indicator{
color: $--color-text-secondary;
}
.right-part { .right-part {
color: $--color-text-regular; color: $--color-text-regular;
line-height: 15px; line-height: 15px;
...@@ -57,11 +54,11 @@ ...@@ -57,11 +54,11 @@
align-self: flex-start; align-self: flex-start;
} }
.bottom-bar{ .bottom-bar {
align-self: flex-end; align-self: flex-end;
} }
.list{ .list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
...@@ -101,28 +98,76 @@ ...@@ -101,28 +98,76 @@
} }
.details-dialog { .details-dialog {
.operate-bar{ .operate-bar {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
padding: 5px; padding: 5px;
} }
.tabs {
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__content {
flex: 1;
& > div {
height: 100%;
}
}
}
.project-editor {
height: 100%;
display: flex;
flex-direction: column;
.project-scrollbar {
flex: 1;
}
}
.scrollbar { .scrollbar {
height: 40vh; height: 100%;
.view { .view {
padding-right: 10px; padding-right: 10px;
.custom-module-list{ .custom-module-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.item + .item { .item + .item {
margin-top: 5px; margin-top: 5px;
} }
} }
} }
} }
.full-scrollbar{ }
height: 68vh;
.mock-editor-dialog {
.mock-editor-view {
height: 100%;
display: flex;
flex-direction: column;
.enabled-switch {
align-self: flex-end;
}
.add-button {
align-self: flex-start;
}
.mock-table {
flex: 1;
}
}
.dialog-footer {
display: flex;
justify-content: space-between;
} }
} }
/** /**
* Created by rockyl on 2019-09-18. * Created by rockyl on 2019-09-18.
*/ */
@import "./var.scss"; @import "./var.scss";
@import "./base.scss"; @import "./base.scss";
@import "./home.scss"; @import "./home.scss";
@import "./editor.scss"; @import "./editor.scss";
@import "./playground.scss"; @import "./playground.scss";
@import "./inspector.scss"; @import "./inspector.scss";
@import "~element-ui/packages/theme-chalk/src/index.scss"; @import "~element-ui/packages/theme-chalk/src/index.scss";
.flex-dialog {
display: flex;
flex-direction: column;
.el-dialog__body {
flex: 1;
height: 0;
padding: 5px;
}
}
.el-tree { .el-tree {
background: transparent; background: transparent;
} }
...@@ -23,15 +32,18 @@ ...@@ -23,15 +32,18 @@
overflow-y: hidden; overflow-y: hidden;
} }
.el-tree-node__content > .el-tree-node__expand-icon{ .el-tree-node__content > .el-tree-node__expand-icon {
padding: 6px 0; padding: 6px 0;
} }
.el-input-number.is-without-controls .el-input__inner{
padding: 0 5px;
}
.el-input__inner { .el-input__inner {
padding: 0 5px; padding: 0 5px;
} }
.el-input--suffix .el-input__inner{ .el-input--suffix .el-input__inner {
padding-right: 5px; padding-right: 5px;
} }
...@@ -43,13 +55,13 @@ ...@@ -43,13 +55,13 @@
height: 100%; height: 100%;
} }
.el-tabs--border-card > .el-tabs__content{ .el-tabs--border-card > .el-tabs__content {
padding: 5px 0 5px 5px; padding: 5px 0 5px 5px;
} }
.el-input-number.is-controls-right .el-input__inner { .el-input-number.is-controls-right .el-input__inner {
padding-left: 5px; padding-left: 5px;
padding-right: 40px; padding-right: 25px;
} }
.el-input-number--mini .el-input-number__increase, .el-input-number--mini .el-input-number__decrease { .el-input-number--mini .el-input-number__increase, .el-input-number--mini .el-input-number__decrease {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
.el-collapse-item__header{ .el-collapse-item__header{
height: 25px; height: 25px;
line-height: 25px;
} }
.el-tabs__item { .el-tabs__item {
...@@ -67,7 +68,7 @@ ...@@ -67,7 +68,7 @@
} }
.el-button + .el-button { .el-button + .el-button {
margin-left: 2px; margin-left: 5px;
} }
.trigger-list{ .trigger-list{
......
...@@ -30,6 +30,10 @@ export const componentsMap = [ ...@@ -30,6 +30,10 @@ export const componentsMap = [
label: '滚动视图', label: '滚动视图',
value: 'scrollView' value: 'scrollView'
}, },
{
label: 'SVGA',
value: 'svga'
},
]; ];
// 属性的计算方法 // 属性的计算方法
......
/**
* Created by rockyl on 2019-12-18.
*/
const version = 3;
const storeConfigs = [
{name: 'project', key: 'id'},
{name: 'mock', key: 'path'},
{name: 'preview', key: 'id'},
];
export default {
open(databaseName = 'store') {
return new Promise((resolve, reject) => {
let request = window.indexedDB.open(databaseName, version);
request.onerror = function (event) {
reject(event.target.error);
};
request.onsuccess = (event) => {
this.db = event.target.result;
resolve(request.result);
};
request.onupgradeneeded = (event) => {
this.db = event.target.result;
this.createStore(storeConfigs);
}
})
},
createStore(stores) {
for (let {name, key} of stores) {
if (!this.db.objectStoreNames.contains(name)) {
this.db.createObjectStore(name, {keyPath: key || 'id'});
}
}
},
get(storeName, id) {
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName])
.objectStore(storeName)
.get(id);
request.onerror = function (event) {
reject(event.target.error);
};
request.onsuccess = function (event) {
resolve(request.result);
};
})
},
getAll(storeName) {
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName])
.objectStore(storeName)
.getAll();
request.onerror = function (event) {
reject(event.target.error);
};
request.onsuccess = function (event) {
resolve(request.result);
};
})
},
add(storeName, data) {
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName], 'readwrite')
.objectStore(storeName)
.add(data);
request.onsuccess = function (event) {
resolve();
};
request.onerror = function (event) {
reject(event.target.error);
}
});
},
put(storeName, data) {
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName], 'readwrite')
.objectStore(storeName)
.put(data);
request.onsuccess = function (event) {
resolve();
};
request.onerror = function (event) {
reject(event.target.error);
}
});
},
async set(storeName, data) {
try {
await this.add(storeName, data);
} catch (e) {
await this.put(storeName, data);
}
},
remove(storeName, id) {
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName], 'readwrite')
.objectStore(storeName)
.delete(id);
request.onsuccess = function (event) {
resolve();
};
request.onerror = function (event) {
reject(event.target.error);
}
});
},
clear(storeName){
return new Promise((resolve, reject) => {
let request = this.db.transaction([storeName], 'readwrite')
.objectStore(storeName)
.clear();
request.onsuccess = function (event) {
resolve();
};
request.onerror = function (event) {
reject(event.target.error);
}
});
},
}
\ No newline at end of file
...@@ -24,7 +24,7 @@ export function playWaiting(promise, text, closeLoading = true) { ...@@ -24,7 +24,7 @@ export function playWaiting(promise, text, closeLoading = true) {
messageError(e); messageError(e);
throw e; throw e;
}).finally(() => { }).finally(() => {
if(closeLoading){ if (closeLoading) {
loading.close(); loading.close();
} }
}) })
...@@ -59,7 +59,7 @@ export function updateProcesses(processes, targetMetaID, replaceMetaID) { ...@@ -59,7 +59,7 @@ export function updateProcesses(processes, targetMetaID, replaceMetaID) {
subProcess.meta = replaceMetaID; subProcess.meta = replaceMetaID;
} }
} }
if(process.metas){ if (process.metas) {
updateProcesses(process.metas, targetMetaID, replaceMetaID) updateProcesses(process.metas, targetMetaID, replaceMetaID)
} }
} }
...@@ -116,12 +116,39 @@ export function readTextFile(file) { ...@@ -116,12 +116,39 @@ export function readTextFile(file) {
}) })
} }
export function selectFile(callback, {accept, multiple} = {}) { function scanEntries(item){
return new Promise(resolve => {
if (item.isDirectory) {
let directoryReader = item.createReader();
directoryReader.readEntries(function(es){
resolve(es);
});
}else{
resolve();
}
})
}
export async function scanFiles(item, container) {
const entries = await scanEntries(item);
if(entries){
for(let entry of entries){
container.push(entry);
await scanFiles(entry, container);
}
}
}
export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) {
let input = document.createElement('input'); let input = document.createElement('input');
input.type = 'file'; input.type = 'file';
input.onchange = function (e) { input.onchange = function (e) {
callback(input.files); callback(input.files);
}; };
if(acceptDirectory){
input.webkitdirectory = true;
}
if (accept) { if (accept) {
input.accept = accept; input.accept = accept;
} }
...@@ -131,14 +158,26 @@ export function selectFile(callback, {accept, multiple} = {}) { ...@@ -131,14 +158,26 @@ export function selectFile(callback, {accept, multiple} = {}) {
input.click(); input.click();
} }
export function openPreview(packResult){ export function openPreview(packResult) {
setTimeout(() => { setTimeout(() => {
let url; let url;
if(location.host.startsWith('localhost')){ if (location.host.startsWith('localhost')) {
url = packResult.tplUrl; url = packResult.tplUrl;
}else{ } else {
url = '/preview?url=http:' + packResult.tplUrl; url = '/preview?url=http:' + packResult.tplUrl;
} }
window.open(url, 'blank'); window.open(url, 'blank');
}, 500); }, 500);
} }
export function newScriptEl(url) {
return `<script src="${url}"></script>`
}
export function getMockServeEnabled(projectID) {
let enabled = localStorage.getItem('mock-enabled-' + projectID);
if (enabled) {
enabled = JSON.parse(enabled);
}
return !!enabled;
}
...@@ -203,6 +203,20 @@ export default { ...@@ -203,6 +203,20 @@ export default {
type: 'textArea', type: 'textArea',
value: '' value: ''
}, },
type: {
title: '输入类型',
type: 'select',
options: [
{ label: '文本', value: 'text' },
{ label: '密码', value: 'password' },
],
value: 'text'
},
pattern: {
title: '输入模式',
type: 'input',
value: ''
},
fillColor: { fillColor: {
title: '颜色', title: '颜色',
type: 'colorPicker', type: 'colorPicker',
...@@ -234,7 +248,7 @@ export default { ...@@ -234,7 +248,7 @@ export default {
}, },
}, },
image: { image: {
groupName: '来源', groupName: '图片',
source: { source: {
title: '来源', title: '来源',
type: 'source', type: 'source',
...@@ -259,6 +273,30 @@ export default { ...@@ -259,6 +273,30 @@ export default {
} }
} }
}, },
svga: {
groupName: 'SVGA',
source: {
title: '来源',
type: 'source',
value: ''
},
lockStep: {
title: '锁步',
type: 'switch',
props: {
width: 40
},
value: false
},
autoPlay: {
title: '自动播放',
type: 'switch',
props: {
width: 40
},
value: false
},
},
rect: { rect: {
groupName: '矩形', groupName: '矩形',
fillColor: { fillColor: {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
import MaxRectsBinPack from "./MaxRectsBinPack"; import MaxRectsBinPack from "./MaxRectsBinPack";
import {clonePureObj} from "./index";
const packExts = ['.png']; //, '.jpg', '.jpeg', '.bmp' const packExts = ['.png']; //, '.jpg', '.jpeg', '.bmp'
...@@ -83,7 +84,7 @@ export async function packImages(asssts, options = {}) { ...@@ -83,7 +84,7 @@ export async function packImages(asssts, options = {}) {
}; };
for (let asset of rect.assets) { for (let asset of rect.assets) {
frames[asset.uuid] = sprite; frames[asset.uuid] = Object.assign({}, sprite, {name: asset.name});
i++; i++;
} }
} }
......
...@@ -11,13 +11,16 @@ ...@@ -11,13 +11,16 @@
</split-panes> </split-panes>
<inspector splitpanes-min="20" :splitpanes-size="getSize(0, 1)"></inspector> <inspector splitpanes-min="20" :splitpanes-size="getSize(0, 1)"></inspector>
</split-panes> </split-panes>
<bottom-bar/>
<details-dialog ref="dialogsDialog"/> <details-dialog ref="dialogsDialog"/>
<pack-result-dialog ref="packResultDialog"/> <pack-result-dialog ref="packResultDialog"/>
<mock-editor-dialog ref="mockEditorDialog"/>
<code-sync-serve-dialog ref="codeSyncServeDialog"/>
</div> </div>
</template> </template>
<script> <script>
import {mapGetters, mapActions} from 'vuex' import {mapState, mapActions} from 'vuex'
import SplitPanes from 'splitpanes' import SplitPanes from 'splitpanes'
import ToolBar from "./Editor/ToolBar"; import ToolBar from "./Editor/ToolBar";
import Inspector from "./Editor/Inspector"; import Inspector from "./Editor/Inspector";
...@@ -29,10 +32,19 @@ ...@@ -29,10 +32,19 @@
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" import events from "@/global-events.js"
import db from "../utils/db-storage";
import MockEditorDialog from "./Editor/dialogs/MockEditorDialog";
import {startCodeSyncServe} from "../code-sync-serve";
import BottomBar from "./Editor/BottomBar";
import CodeSyncServeDialog from "./Editor/dialogs/CodeSyncServeDialog";
export default { export default {
name: 'Editor', name: 'Editor',
components: { components: {
CodeSyncServeDialog,
BottomBar,
MockEditorDialog,
PackResultDialog, PackResultDialog,
DetailsDialog, DetailsDialog,
Assets, Assets,
...@@ -59,29 +71,39 @@ ...@@ -59,29 +71,39 @@
} }
}, },
computed: { computed: {
...mapGetters([]), ...mapState({
codeSyncServeConfig(state) {
return state.env.codeSyncServeConfig;
},
}),
}, },
async mounted() { async mounted() {
document.addEventListener('keydown', this.onKeyPress); document.addEventListener('keydown', this.onKeyPress);
events.$on('save-and-preview', () => {
this.clickMenu("preview");
});
events.$on('show-code-sync-serve-dialog', () => {
this.$refs.codeSyncServeDialog.show();
});
await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => { await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
}); });
setTimeout(() => {
startCodeSyncServe(this.codeSyncServeConfig);
}, 100);
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(),
db.open('store'),
]) ])
}, },
onKeyPress(e) { onKeyPress(e) {
...@@ -166,14 +188,18 @@ ...@@ -166,14 +188,18 @@
this.$refs.dialogsDialog.show(); this.$refs.dialogsDialog.show();
break; break;
case 'preview': case 'preview':
this.preview();
await this.pack(true); await this.pack(true);
break; break;
case 'preview2': case 'preview-fast':
this.preview(); this.preview();
break; break;
case 'publish': case 'publish':
await this.publish(); await this.publish();
break; break;
case 'mock':
this.$refs.mockEditorDialog.show();
break;
case 'undo': case 'undo':
this.$store.commit('undoRedo', 1); this.$store.commit('undoRedo', 1);
break; break;
...@@ -202,7 +228,7 @@ ...@@ -202,7 +228,7 @@
break; break;
} }
}, },
async publish(){ async publish() {
this.pack(); this.pack();
}, },
async pack(debug = false) { async pack(debug = false) {
...@@ -211,7 +237,7 @@ ...@@ -211,7 +237,7 @@
text: this.$t('Packing'), text: this.$t('Packing'),
}); });
try { try {
if(!debug){ if (!debug) {
await this.saveProject(false); await this.saveProject(false);
} }
const packResult = await this.packProject(debug); const packResult = await this.packProject(debug);
...@@ -257,7 +283,7 @@ ...@@ -257,7 +283,7 @@
let previewUrl = new URL(location.href); let previewUrl = new URL(location.href);
previewUrl.hash = '#/preview/' + projectID; previewUrl.hash = '#/preview/' + projectID;
setTimeout(()=>{ setTimeout(() => {
window.open(previewUrl.href, 'blank'); window.open(previewUrl.href, 'blank');
}, 300); }, 300);
}, },
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<el-scrollbar class="assets-scrollbar" wrap-class="wrap-x-hidden" <el-scrollbar class="assets-scrollbar" wrap-class="wrap-x-hidden"
view-class="scrollbar-view"> view-class="scrollbar-view">
<div class="file-list"> <div class="file-list">
<div class="file-uploader" @click="toUploadFile"> <div class="file-uploader" @click="toUploadFile" @dragover.prevent @drop="onDropFile">
<i class="el-icon-plus file-uploader-icon"></i> <i class="el-icon-plus file-uploader-icon"></i>
</div> </div>
<file-item v-for="(asset, index) in assets" :data="asset" :key="index" @show-file-details="showFileDetails" <file-item v-for="(asset, index) in assets" :data="asset" :key="index" @show-file-details="showFileDetails"
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
import FileItem from "./Assets/FileItem"; import FileItem from "./Assets/FileItem";
import AssetsShow from "./Assets/AssetsShow"; import AssetsShow from "./Assets/AssetsShow";
import SplitPanes from 'splitpanes' import SplitPanes from 'splitpanes'
import {selectFile} from "../../utils"; import {scanFiles, selectFile} from "../../utils";
export default { export default {
name: "Assets", name: "Assets",
...@@ -68,6 +68,23 @@ ...@@ -68,6 +68,23 @@
this.uploadFiles(files); this.uploadFiles(files);
}, {multiple: true}) }, {multiple: true})
}, },
async onDropFile(e) {
const items = e.dataTransfer.items;
let allFiles = [];
let allEntries = [];
for (let item of items) {
await scanFiles(item.webkitGetAsEntry(), allEntries);
}
for (let entry of allEntries) {
await new Promise(resolve => {
entry.file(function (file) {
allFiles.push(file);
resolve();
});
})
}
this.uploadFiles(allFiles);
},
showFileDetails(file) { showFileDetails(file) {
this.$refs.assetsShow.show(file); this.$refs.assetsShow.show(file);
}, },
......
<template> <template>
<div class="file-item" @click="$emit('click', $event)"> <div class="file-item" @click="$emit('click', $event)">
<div class="icon"> <div class="icon">
<i v-if="!showThumbnail" draggable="true" class="file-icon" :class="fileIcon"></i> <i @dragstart="assetDragStart(data)" v-if="!showThumbnail" draggable="true" class="file-icon" :class="fileIcon"></i>
<img @dragstart="assetDragStart(data)" v-if="showThumbnail" draggable="true" class="thumbnail" :src="thumbnailUrl" <img @dragstart="assetDragStart(data)" v-if="showThumbnail" draggable="true" class="thumbnail" :src="thumbnailUrl"
alt="thumb" @dblclick="onDbclick()"> alt="thumb" @dblclick="onDbclick()">
<div class="operate-bar"> <div class="operate-bar">
......
<template>
<div class="bottom-bar">
<div class="editor-status">Ready</div>
<code-sync-indicator/>
<upload-indicator/>
</div>
</template>
<script>
import UploadIndicator from "./BottomBar/UploadIndicator";
import CodeSyncIndicator from "./BottomBar/CodeSyncIndicator";
export default {
name: "BottomBar",
components: {CodeSyncIndicator, UploadIndicator},
}
</script>
<style scoped>
</style>
<template>
<div class="code-sync-indicator">
<div class="indicator" :class="{enabled: enabled}" @click="onClick"></div>
</div>
</template>
<script>
import events from "../../../global-events";
import {codeSyncServeEnabled} from "../../../code-sync-serve";
export default {
name: "CodeSyncIndicator",
data() {
return {
enabled: codeSyncServeEnabled,
}
},
mounted() {
events.$on('code-sync-start', this.onCodeSyncStart);
events.$on('code-sync-stop', this.onCodeSyncStop);
},
destroyed() {
events.$off('code-sync-start', this.onCodeSyncStart);
events.$off('code-sync-stop', this.onCodeSyncStop);
},
methods: {
onCodeSyncStart() {
this.enabled = true;
},
onCodeSyncStop() {
this.enabled = false;
},
onClick() {
events.$emit('show-code-sync-serve-dialog');
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
<el-tab-pane :label="$t('Props')" name="properties"> <el-tab-pane :label="$t('Props')" name="properties">
<props-tab/> <props-tab/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('Script')" name="script">
<scripts-tab/>
</el-tab-pane>
<el-tab-pane :label="$t('Behavior')" name="behavior"> <el-tab-pane :label="$t('Behavior')" name="behavior">
<behavior-tab/> <behavior-tab/>
</el-tab-pane> </el-tab-pane>
...@@ -15,10 +18,11 @@ ...@@ -15,10 +18,11 @@
import Pane from '../../components/Pane'; import Pane from '../../components/Pane';
import BehaviorTab from "./Inspector/BehaviorTab"; import BehaviorTab from "./Inspector/BehaviorTab";
import PropsTab from "./Inspector/PropsTab"; import PropsTab from "./Inspector/PropsTab";
import ScriptsTab from "./Inspector/ScriptsTab";
export default { export default {
name: 'Inspector', name: 'Inspector',
components: {BehaviorTab, PropsTab, Pane}, components: {ScriptsTab, BehaviorTab, PropsTab, Pane},
data() { data() {
return { return {
tab: 'properties' tab: 'properties'
......
...@@ -147,28 +147,32 @@ ...@@ -147,28 +147,32 @@
}, },
handleBehaviorsChange(isPreview) { handleBehaviorsChange(isPreview) {
if (isPreview) { if (isPreview) {
events.$emit('saveAndPreview') events.$emit('save-and-preview')
} }
}, },
async deleteBehavior(index, behaviors) { async deleteBehavior(index, behaviors) {
let deleteMeta = false; let deleteMeta = false;
let close;
await this.$confirm(this.$t('Are you sure to delete it\'s process'), this.$t('Alert'), { await this.$confirm(this.$t('Are you sure to delete it\'s process'), this.$t('Alert'), {
showClose: false, confirmButtonText: this.$t('Delete'),
closeOnClickModal: false, cancelButtonText: this.$t('Not delete'),
closeOnPressEscape: false, distinguishCancelAndClose: true,
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
deleteMeta = true; deleteMeta = true;
}).catch((e) => { }).catch(action => {
if(action === 'close'){
close = true;
}
}); });
this.deleteBehaviorDirect({ if(!close){
behaviors, this.deleteBehaviorDirect({
index, behaviors,
deleteMeta, index,
}) deleteMeta,
})
}
}, },
...mapActions([ ...mapActions([
'modifyActiveView', 'modifyActiveView',
......
...@@ -2,53 +2,25 @@ ...@@ -2,53 +2,25 @@
<div class="zero-inspector-props-form" v-if="activeComponent.uuid"> <div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"> <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-form ref="form" size="mini" :model="form" label-width="80px" @submit.native.prevent> <el-form ref="form" size="mini" :model="form" label-width="80px" @submit.native.prevent>
<el-collapse v-model="configColl"> <el-form-item label="名称">
<el-collapse-item :title="$t('Props')" name="properties"> <el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
<el-form-item label="名称"> </el-form-item>
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input> <el-form-item label="类型">
</el-form-item> <el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型">
<el-form-item label="类型"> <el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option>
<el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型"> </el-select>
<el-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option> </el-form-item>
</el-select> <template v-for="(p, key) in cmpProps">
</el-form-item> <el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title">
<template v-for="(p, key) in cmpProps"> <!-- {{key}} -->
<el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title"> <el-tooltip :disabled="!p.desc" placement="top-start">
<!-- {{key}} --> <div slot="content">{{p.desc}}</div>
<el-tooltip :disabled="!p.desc" placement="top-start"> <div>
<div slot="content">{{p.desc}}</div> <dynamic-component :component-value="getPropValue(p, key)" :component-props="getPropProps(p)" :component-type="getPropCmpType(p)" @onChange="v => handlePropertiesChange(key, v)"></dynamic-component>
<div> </div>
<dynamic-component :component-value="getPropValue(p, key)" :component-props="getPropProps(p)" :component-type="getPropCmpType(p)" @onChange="v => handlePropertiesChange(key, v)"></dynamic-component> </el-tooltip>
</div> </el-form-item>
</el-tooltip> </template>
</el-form-item>
</template>
</el-collapse-item>
<el-collapse-item :title="$t('Script')" 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="p.alias|| 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-form-item label="">
<el-button @click="deleteNodeScript(index)">删除</el-button>
</el-form-item>
</el-collapse-item>
</template>
</el-collapse>
<div style="padding-top: 15px;text-align: center;">
<el-dropdown trigger="click" @command="handleAddScript" placement="top" size="small">
<el-button size="mini">{{$t('Add')}}</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(script, key) of scripts" :command="script.id" :key="key">{{script.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-collapse-item>
</el-collapse>
</el-form> </el-form>
</el-scrollbar> </el-scrollbar>
</div> </div>
...@@ -110,36 +82,6 @@ const componentMapper = { ...@@ -110,36 +82,6 @@ const componentMapper = {
} }
}; };
const scriptTypeMap = {
number: {
component: 'el-input-number',
props: {
size: 'mini'
}
},
string: {
component: 'el-input'
},
boolean: {
component: 'el-switch',
props: {
width: 40
}
},
color: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
}
};
export default { export default {
name: 'PropsTab', name: 'PropsTab',
components: { 'dynamic-component': dynamicComponent }, components: { 'dynamic-component': dynamicComponent },
...@@ -150,18 +92,11 @@ export default { ...@@ -150,18 +92,11 @@ export default {
name: '', name: '',
type: '', type: '',
properties: {}, properties: {},
scripts: []
}, },
configColl: ['properties']
}; };
}, },
computed: { computed: {
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']), ...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']),
...mapState({
scripts(state){
return state.env.scripts;
}
}),
cmpProps: function() { cmpProps: function() {
// 获取properties.js中的默认配置 // 获取properties.js中的默认配置
return getCmpProps(this.activeComponent.type); return getCmpProps(this.activeComponent.type);
...@@ -183,13 +118,6 @@ export default { ...@@ -183,13 +118,6 @@ export default {
_view[label] = v; _view[label] = v;
this.$store.dispatch('modifyActiveView', _view); this.$store.dispatch('modifyActiveView', _view);
}, },
/**
* 脚本预设对象选中
*/
handleAddScript(command) {
console.log('handleAddScript', command);
this.$store.dispatch('addNodeScript', command);
},
/** /**
* 基础属性发生改变 * 基础属性发生改变
*/ */
...@@ -200,20 +128,6 @@ export default { ...@@ -200,20 +128,6 @@ export default {
_prop[key] = v; _prop[key] = v;
this.$store.dispatch('modifyProperties', _prop); this.$store.dispatch('modifyProperties', _prop);
}, },
/**
* 事件属性发生改变
*/
handleScriptChange(index, key, v) {
let _props = {};
_props[key] = v;
let _scripts = _.cloneDeep(this.activeComponent.scripts);
let _script = _scripts[index];
_script.props = _.assign(_script.props, _props);
_scripts[index] = _script;
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
});
},
/** /**
* 获取动态组件的类型 * 获取动态组件的类型
*/ */
...@@ -239,61 +153,6 @@ export default { ...@@ -239,61 +153,6 @@ export default {
let _properties = this.activeComponentCopy.properties; let _properties = this.activeComponentCopy.properties;
return _properties[key] === undefined || _properties[key] === null ? item.value : _properties[key]; return _properties[key] === undefined || _properties[key] === null ? item.value : _properties[key];
}, },
getScriptValue(item, key, index) {
let _script = this.activeComponent.scripts[index];
// let result =
return _script.props[key] || item.default;
},
getScriptProps(item, index) {
let _type = item.type;
let _options = [];
if (_type === 'enum') {
// 如果脚本选项对应的类型是数组,说明是枚举类型
_options = item.enum.map(i => {
return {
label: i,
value: i
};
});
_type = 'select';
}
let _cmp = scriptTypeMap[_type];
return {
size: 'mini',
...(_cmp.props || {}),
options: _options
};
},
getScriptType(item, index) {
// 如果脚本选项对应的类型是数组,说明是枚举类型
let _type = item.type;
if (_type === 'enum') {
_type = 'select';
}
return scriptTypeMap[_type].component;
},
getScriptName(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.name : '';
},
getScriptOptions(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.props : {};
},
/**
* 删除节点脚本
*/
deleteNodeScript(index) {
let _scripts = _.cloneDeep(this.activeComponent.scripts);
_.remove(_scripts, (s, sindex) => {
return sindex === index;
});
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
});
}
} }
}; };
</script> </script>
......
<template> <template>
<div class="zero-inspector-script-form" v-if="activeComponent.uuid"> <div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<el-collapse v-model="configColl"> <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-collapse-item title="配置" name="properties"> <el-form ref="form" size="mini" :model="form" label-width="80px" @submit.native.prevent>
<el-form ref="form" size="mini" :model="form" label-width="80px" @submit.native.prevent> <el-collapse accordion v-if="activeComponent.scripts && activeComponent.scripts.length">
<el-form-item label="名称"> <template v-for="(script, index) in activeComponent.scripts">
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input> <el-collapse-item :title="getScriptName(script.script)" :key="script + index">
</el-form-item> <template v-for="(p, key) in getScriptOptions(script.script)">
<el-form-item label="类型"> <el-form-item :key="activeComponent.uuid + index + key" :label="p.alias|| key">
<el-select v-model="form.type" @change="v => handleChange('type', v)" placeholder="请选择类型"> <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-option v-for="cmp in componentsMap" :key="cmp.value" :label="cmp.label" :value="cmp.value"></el-option> </el-form-item>
</el-select> </template>
</el-form-item> <el-form-item label="">
<template v-for="(p, key) in cmpProps"> <el-button @click="deleteNodeScript(index)">删除</el-button>
<el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title"> </el-form-item>
<!-- {{key}} --> </el-collapse-item>
<dynamic-component :label="key" :item="p" :properties="activeComponent.properties"></dynamic-component>
</el-form-item>
</template> </template>
</el-form> </el-collapse>
</el-collapse-item> <div style="padding-top: 15px;text-align: center;">
<el-collapse-item title="脚本" name="scripts"> <el-dropdown trigger="click" @command="handleAddScript" placement="top" size="small">
</el-collapse-item> <el-button size="mini">{{$t('Add')}}</el-button>
</el-collapse> <el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(script, key) of scripts" :command="script.id" :key="key">{{script.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-form>
</el-scrollbar>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters, mapState } from 'vuex';
import _ from 'lodash';
import { componentsMap, getCmpProps } from '../../../utils/common'; import { componentsMap, getCmpProps } from '../../../utils/common';
import dynamicComponent from '../components/dynamicComponent'; import dynamicComponent from '../components/dynamicComponent';
const scriptTypeMap = {
number: {
component: 'el-input-number',
props: {
size: 'mini'
}
},
string: {
component: 'el-input'
},
boolean: {
component: 'el-switch',
props: {
width: 40
}
},
color: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
}
};
export default { export default {
name: 'PropsTab', name: 'ScriptsTab',
components: { 'dynamic-component': dynamicComponent }, components: { 'dynamic-component': dynamicComponent },
data() { data() {
return { return {
componentsMap, componentsMap,
form: { form: {
name: '', scripts: []
type: '',
properties: {}
}, },
configColl: ['properties'] configColl: ['properties']
}; };
}, },
computed: { computed: {
...mapGetters(['activeComponent', 'componentList']), ...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']),
cmpProps: function() { ...mapState({
return getCmpProps(this.activeComponent.type); scripts(state){
} return state.env.scripts;
},
watch: {
activeComponent: {
deep: true,
handler: function(val) {
this.form.name = val.name || '';
this.form.type = val.type || '';
this.form.properties = val.properties || {};
} }
} }),
}, },
methods: { methods: {
handleChange(label, v) { /**
this.$store.dispatch('modifyComponent', { * 脚本预设对象选中
label: label, */
value: v handleAddScript(command) {
console.log('handleAddScript', command);
this.$store.dispatch('addNodeScript', command);
},
/**
* 事件属性发生改变
*/
handleScriptChange(index, key, v) {
let _props = {};
_props[key] = v;
let _scripts = _.cloneDeep(this.activeComponent.scripts);
let _script = _scripts[index];
_script.props = _.assign(_script.props, _props);
_scripts[index] = _script;
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
});
},
getScriptValue(item, key, index) {
let _script = this.activeComponent.scripts[index];
let v = _script.props[key];
return v === undefined ? item.default : v;
},
getScriptProps(item, index) {
let _type = item.type;
let _options = [];
if (_type === 'enum') {
// 如果脚本选项对应的类型是数组,说明是枚举类型
_options = item.enum.map(i => {
return {
label: i,
value: i
};
});
_type = 'select';
}
let _cmp = scriptTypeMap[_type];
return {
size: 'mini',
...(_cmp.props || {}),
options: _options
};
},
getScriptType(item, index) {
// 如果脚本选项对应的类型是数组,说明是枚举类型
let _type = item.type;
if (_type === 'enum') {
_type = 'select';
}
return scriptTypeMap[_type].component;
},
getScriptName(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.name : '';
},
getScriptOptions(id) {
let _script = this.scripts.find(script => script.id === id);
return _script ? _script.props : {};
},
/**
* 删除节点脚本
*/
deleteNodeScript(index) {
let _scripts = _.cloneDeep(this.activeComponent.scripts);
_.remove(_scripts, (s, sindex) => {
return sindex === index;
});
this.$store.dispatch('modifyActiveView', {
scripts: _scripts
}); });
} }
} }
...@@ -72,14 +167,17 @@ export default { ...@@ -72,14 +167,17 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.zero-inspector-script-form { .zero-inspector-props-form {
width: 100%; width: 100%;
padding-right: 10px; padding-right: 10px;
.el-form-item--mini.el-form-item {
margin-bottom: 10px;
}
.el-divider__text { .el-divider__text {
background-color: #e9e9e9; background-color: #e9e9e9;
} }
.zero-inspector-props-group {
max-height: 500px;
}
}
.script-config-dialog {
height: 350px;
} }
</style> </style>
\ No newline at end of file
<template> <template>
<div class="tool-bar"> <div class="tool-bar">
<sample-menu :data="menu" @click-menu="clickMenu"/> <sample-menu :data="menu" @click-menu="clickMenu"/>
<upload-indicator/>
<div style="flex: 1"></div> <div style="flex: 1"></div>
<div class="right-part"> <div class="right-part">
<span> <span>
...@@ -15,11 +14,10 @@ ...@@ -15,11 +14,10 @@
<script> <script>
import {mapState, mapActions, mapMutations} from 'vuex' import {mapState, mapActions, mapMutations} from 'vuex'
import SampleMenu from "../../components/SampleMenu"; import SampleMenu from "../../components/SampleMenu";
import UploadIndicator from "./ToolBar/UploadIndicator";
export default { export default {
name: "ToolBar", name: "ToolBar",
components: {UploadIndicator, SampleMenu}, components: {SampleMenu},
data() { data() {
return {} return {}
}, },
...@@ -45,7 +43,7 @@ ...@@ -45,7 +43,7 @@
async mounted() { async mounted() {
//监听键盘事件 //监听键盘事件
document.addEventListener('keydown', this.onKeyPress); //document.addEventListener('keydown', this.onKeyPress);
}, },
methods: { methods: {
clickMenu(menuItem) { clickMenu(menuItem) {
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
:show-close="false" :show-close="false"
fullscreen fullscreen
:append-to-body="true" :append-to-body="true"
custom-class="behavior-editor-dialog" custom-class="flex-dialog 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>
<el-form-item prop="id" :label="$t('ID')"> <el-form-item prop="id" :label="$t('ID')">
<el-input v-model="meta.id" :placeholder="$t('ID')" :readonly="!editable"/> <el-input v-model="meta.id" :placeholder="$t('ID')" :readonly="!editable"/>
...@@ -42,6 +43,7 @@ ...@@ -42,6 +43,7 @@
</template> </template>
</el-form> </el-form>
<div style="margin-top: 5px;"> <div style="margin-top: 5px;">
<code-sync-indicator/>
<el-tag v-for="(item, key) in exposeVariables" :key="key" 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')"
...@@ -49,10 +51,7 @@ ...@@ -49,10 +51,7 @@
<codemirror ref="codeEditor" v-if="meta" <codemirror ref="codeEditor" v-if="meta"
v-model="meta.script" v-model="meta.script"
:options="cmOptions" :options="cmOptions"
@cursorActivity="onCodeChange" @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">
...@@ -64,7 +63,7 @@ ...@@ -64,7 +63,7 @@
</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(true)">{{$t('Save And Preview')}}</el-button> <!--<el-button size="mini" plain @click="save(true)">{{$t('Save And Preview')}}</el-button>-->
<el-button size="mini" type="primary" plain @click="save(false)">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" plain @click="save(false)">{{$t('Save')}}</el-button>
</div> </div>
</div> </div>
...@@ -85,14 +84,17 @@ ...@@ -85,14 +84,17 @@
import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css' import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/javascript-hint.js' import 'codemirror/addon/hint/javascript-hint.js'
import events from "@/global-events.js" import 'codemirror/addon/lint/lint.js'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/addon/lint/javascript-lint.js'
import events from '../../../global-events';
import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator";
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, codemirror}, components: {CodeSyncIndicator, PropsEditorDialog, ElFormItem, codemirror},
data() { data() {
return { return {
visible: false, visible: false,
...@@ -102,26 +104,35 @@ ...@@ -102,26 +104,35 @@
rules: { rules: {
id: [ id: [
{ required: true, trigger: 'blur' }, {required: true, trigger: 'blur'},
], ],
name: [ name: [
{ required: true, trigger: 'blur' } {required: true, trigger: 'blur'}
], ],
}, },
cmOptions: { cmOptions: {
tabSize: 2, tabSize: 2,
mode: 'text/javascript',
styleActiveLine: true, styleActiveLine: true,
theme: 'default', theme: 'default',
lineNumbers: true,
line: true, line: true,
matchBrackets: true, matchBrackets: true,
autoCloseBrackets: true, autoCloseBrackets: true,
extraKeys: {
"Alt-Space": "autocomplete",
},
lineNumbers: true,
mode: {name: 'javascript', globalVars: true},
gutters: ["CodeMirror-lint-markers"],
lint: true
} }
} }
}, },
mounted(){ mounted() {
events.$on('edit-save', this.onEditSave);
},
destroyed(){
events.$off('edit-save', this.onEditSave);
}, },
computed: { computed: {
editable() { editable() {
...@@ -136,6 +147,11 @@ ...@@ -136,6 +147,11 @@
this.visible = true; this.visible = true;
this.meta = clonePureObj(meta); this.meta = clonePureObj(meta);
this.oldMetaID = this.meta.id; this.oldMetaID = this.meta.id;
events.$emit('edit-open', this.meta.script);
},
onEditSave(code){
this.$set(this.meta, 'script', code);
}, },
onClickEditProps() { onClickEditProps() {
this.$refs.propsEditorDialog.edit(this.meta.props); this.$refs.propsEditorDialog.edit(this.meta.props);
...@@ -148,8 +164,8 @@ ...@@ -148,8 +164,8 @@
.catch((e) => { .catch((e) => {
}); });
} else { } else {
this.$emit('input',this.meta,isPreview); this.$emit('input', this.meta, isPreview);
this.visible=false; this.visible = false;
} }
} else { } else {
return false; return false;
...@@ -167,19 +183,19 @@ ...@@ -167,19 +183,19 @@
}, },
onPaste(e) { onPaste(e) {
let metaStr = e.clipboardData.getData("Text"); let metaStr = e.clipboardData.getData("Text");
if(metaStr){ if (metaStr) {
try { try {
let meta = JSON.parse(metaStr); let meta = JSON.parse(metaStr);
this.meta = meta; this.meta = meta;
}catch (e) { } catch (e) {
} }
} }
}, },
focusPasteBoard(){ focusPasteBoard() {
this.$refs.pasteBoard.focus(); this.$refs.pasteBoard.focus();
}, },
onCodeChange(codemirror){ onCodeChange(codemirror) {
//codemirror.showHint(); //codemirror.showHint();
//console.log(code); //console.log(code);
} }
......
<template> <template>
<el-dialog :title="$t('Behavior Editor')" :visible.sync="visible" :before-close="beforeClose" @opened="onOpened" <el-dialog :title="$t('Behavior Editor')" :visible.sync="visible" :before-close="beforeClose" @opened="onOpened"
:fullscreen="true" :close-on-click-modal="false" :close-on-press-escape="false" :fullscreen="true" :close-on-click-modal="false" :close-on-press-escape="false"
:append-to-body="true" custom-class="behavior-editor-dialog"> :append-to-body="true" custom-class="flex-dialog 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" @click="onSave(true)">{{$t('Save And Preview')}}</el-button> <el-button size="mini" @click="onSave(true)">{{$t('Save And Preview')}}</el-button>
......
<template>
<el-dialog :title="$t('CodeSyncServe')" width="70%" :visible.sync="visible"
:append-to-body="true"
custom-class=""
>
<div>
<el-form label-position="right" label-width="50px" size="mini">
<el-form-item label="IP">
<el-input v-model="config.ip"/>
</el-form-item>
<el-form-item label="Port">
<el-input-number v-model="config.port" controls-position="right" :max="65535"/>
</el-form-item>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<div>
</div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import {mapMutations, mapState} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import ElFormItem from "../behavior-editor/inputs/form-item";
import {clonePureObj} from "../../../utils";
import {startCodeSyncServe} from "../../../code-sync-serve";
export default {
name: "CodeSyncServeDialog",
components: {ElFormItem, EnabledSetter,},
data() {
return {
visible: false,
config: {},
}
},
mounted() {
},
computed: {
...mapState({
codeSyncServeConfig(state) {
return state.env.codeSyncServeConfig;
}
})
},
methods: {
show() {
this.config = clonePureObj(this.codeSyncServeConfig);
this.visible = true;
},
onSave() {
this.saveCodeSyncServeConfig(this.config);
startCodeSyncServe(this.config);
this.visible = false;
},
onClose() {
this.visible = false;
},
...mapMutations([
'saveCodeSyncServeConfig',
]),
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template> <template>
<el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @open="onOpen" <el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @opened="onOpen"
:close-on-click-modal="false" :close-on-click-modal="false"
:append-to-body="true" :append-to-body="true"
:show-close="false" :show-close="false"
fullscreen fullscreen
custom-class="details-dialog" custom-class="flex-dialog details-dialog"
> >
<el-tabs v-model="activeName"> <el-tabs v-model="activeName" class="tabs">
<el-tab-pane :label="$t('Project')" name="project"> <el-tab-pane :label="$t('Project')" name="project">
<project-editor/> <project-editor ref="projectEditor"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('Env constant')" name="env"> <el-tab-pane :label="$t('Env constant')" name="env">
<env-editor/> <env-editor ref="envEditor"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('Data mapping')" name="data-mapping"> <el-tab-pane :label="$t('Data mapping')" name="data-mapping">
<data-mapping-editor/> <data-mapping-editor ref="dataMappingEditor"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('Custom module')" name="custom"> <el-tab-pane :label="$t('Custom module')" name="custom">
<custom-editor/> <custom-editor ref="customEditor"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button> <el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import {mapMutations} from 'vuex';
import ProjectEditor from "./editors/ProjectEditor"; import ProjectEditor from "./editors/ProjectEditor";
import EnvEditor from "./editors/EnvEditor"; import EnvEditor from "./editors/EnvEditor";
import CustomEditor from "./editors/CustomEditor"; import CustomEditor from "./editors/CustomEditor";
import DataMappingEditor from "./editors/DataMappingEditor"; import DataMappingEditor from "./editors/DataMappingEditor";
const refs = [
'projectEditor',
'envEditor',
'dataMappingEditor',
'customEditor',
];
export default { export default {
name: "DetailsDialog", name: "DetailsDialog",
components: {DataMappingEditor, CustomEditor, EnvEditor, ProjectEditor}, components: {DataMappingEditor, CustomEditor, EnvEditor, ProjectEditor},
...@@ -45,12 +54,24 @@ ...@@ -45,12 +54,24 @@
show() { show() {
this.visible = true; this.visible = true;
}, },
onSave() {
for (let ref of refs) {
this.$refs[ref].save();
}
this.visible = false;
this.modifyProjectDetails();
},
onClose() { onClose() {
this.visible = false; this.visible = false;
}, },
onOpen() { onOpen() {
for (let ref of refs) {
this.$refs[ref].edit();
}
}, },
...mapMutations([
'modifyProjectDetails',
]),
} }
} }
</script> </script>
......
<template>
<el-dialog :title="$t('Mock Editor')" width="70%" :visible.sync="visible"
:close-on-click-modal="false"
:append-to-body="true"
:show-close="false"
fullscreen
custom-class="flex-dialog mock-editor-dialog"
>
<div class="mock-editor-view">
<label class="enabled-switch">
<el-switch :value="mockServeEnabled" @input="onMockServeEnabledChange"/>
{{$t('Enable mock serve')}}
</label>
<el-table class="mock-table" :data="mocks" height="100%" stripe size="mini">
<el-table-column type="expand">
<template slot-scope="props">
<codemirror ref="codeEditor"
v-model="props.row.data"
:options="cmOptions"/>
</template>
</el-table-column>
<el-table-column
prop="disabled"
width="40">
<template slot-scope="scope">
<enabled-setter :target="scope.row"/>
</template>
</el-table-column>
<el-table-column
prop="path"
:label="$t('Path')"
width="200">
<template slot-scope="scope">
<el-input v-model="scope.row.path" size="mini"/>
</template>
</el-table-column>
<el-table-column
prop="timeout"
:label="$t('Timeout')"
width="100">
<template slot-scope="scope">
<el-input-number style="width:100%;" v-model="scope.row.timeout" size="mini" controls-position="right"/>
</template>
</el-table-column>
<el-table-column
prop="successRatio"
:label="$t('SuccessRatio')"
width="150">
<template slot-scope="scope">
<el-slider v-model="scope.row.successRatio" size="mini" :max="1" :min="0" :step="0.1"/>
</template>
</el-table-column>
<el-table-column
prop="data"
:label="$t('Data')">
<template slot-scope="scope">
<span style="white-space: nowrap;overflow: hidden;">{{scope.row.data}}</span>
</template>
</el-table-column>
<el-table-column
width="50">
<template slot-scope="scope">
<el-button circle size="mini" type="danger" icon="el-icon-delete" plain
@click="toDeleteItem(scope.$index)"/>
</template>
</el-table-column>
</el-table>
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-button size="mini" @click="onAdd">{{$t('Add')}}</el-button>
</div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import {mapState, mapMutations, mapActions} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import {clonePureObj} from "../../../utils";
import {codemirror} from "vue-codemirror";
import 'codemirror/addon/lint/lint.js'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/addon/lint/json-lint.js'
export default {
name: "MockEditorDialog",
components: {EnabledSetter, codemirror},
data() {
return {
visible: false,
mocks: [],
cmOptions: {
tabSize: 2,
styleActiveLine: true,
theme: 'default',
line: true,
matchBrackets: true,
autoCloseBrackets: true,
lineNumbers: true,
mode: "application/json",
gutters: ["CodeMirror-lint-markers"],
lint: true
}
}
},
mounted() {
},
computed: {
...mapState({
mocksOrigin: state => state.project.data.mock,
mockServeEnabled: state => state.project.mockServeEnabled,
}),
},
watch: {
mockServeEnabled(v) {
}
},
methods: {
show() {
this.mocks = clonePureObj(this.mocksOrigin);
this.visible = true;
},
onSave() {
this.modifyMocks(this.mocks);
this.visible = false;
},
onClose() {
this.visible = false;
},
onAdd() {
this.mocks.push({
path: '',
data: '',
timeout: 0,
successRatio: 1,
});
},
onDelete(index) {
this.mocks.splice(index, 1);
},
toDeleteItem(index) {
this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), {
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning'
}).then(() => {
this.onDelete(index);
}).catch((e) => {
});
},
onMockServeEnabledChange(v){
this.setMockServeEnabled(v);
},
...mapMutations([
'modifyMocks',
]),
...mapActions([
'setMockServeEnabled',
]),
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template> <template>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view"> <el-table v-if="editData" :data="customMetas" stripe height="100%">
<el-checkbox-group :value="customs" class="custom-module-list" @input="onChange"> <el-table-column
<el-checkbox class="item" v-for="customMeta in customMetas" :key="customMeta.id" :label="customMeta.id"> width="40"
{{customMeta.alias || customMeta.name}} >
</el-checkbox> <template slot-scope="scope">
</el-checkbox-group> <el-checkbox v-model="scope.row.selected"/>
</el-scrollbar> </template>
</el-table-column>
<el-table-column
prop="id"
label="ID"
width="200">
</el-table-column>
<el-table-column
prop="name"
:label="$t('Name')"
width="200">
</el-table-column>
<!--<el-table-column
label="Version"
width="100"
>
<template slot-scope="scope">
<el-select size="mini"/>
</template>
</el-table-column>-->
<el-table-column>
</el-table-column>
</el-table>
</template> </template>
<script> <script>
import {mapState, mapMutations} from 'vuex' import {mapState, mapMutations} from 'vuex'
import {clonePureObj} from "../../../../utils";
export default { export default {
name: "CustomEditor", name: "CustomEditor",
data() { data() {
return { return {
visible: false, visible: false,
customMetas: [],
editData: null,
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
customMetas: state => state.env.customs,
customs: state => state.project.data.customs, customs: state => state.project.data.customs,
}), }),
}, },
methods: { methods: {
edit() {
this.editData = clonePureObj(this.customs);
this.customMetas.splice(0);
for (let meta of this.$store.state.env.customs) {
this.customMetas.push({
id: meta.id,
name: meta.name,
selected: this.editData.includes(meta.id),
})
}
},
save() {
const editData = this.editData;
editData.splice(0);
for (let meta of this.customMetas) {
if(meta.selected){
editData.push(meta.id);
}
}
this.modifyCustoms(editData);
},
...mapMutations([ ...mapMutations([
'modifyCustoms', 'modifyCustoms',
]), ]),
onChange(v){
this.modifyCustoms(v);
}
} }
} }
</script> </script>
......
<template> <template>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view"> <el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<div class="mapping-list"> <div class="mapping-list">
<el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/> <el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/>
<div class="list"> <div class="list">
<div class="item" v-for="(link, index) in mapping"> <div class="item" v-for="(link, index) in editData">
<el-input size="mini" style="width: 30%" v-model="link.name" @change="onChange"/> <el-input size="mini" style="width: 30%" v-model="link.name"/>
<el-icon class="el-icon-connection"/> <el-icon class="el-icon-connection"/>
<el-input size="mini" v-model="link.path" @change="onChange"/> <el-input size="mini" v-model="link.path"/>
<el-button class="delete-button" icon="el-icon-minus" circle size="mini" plain type="danger" @click="toDeleteItem(link, index)"/> <el-button class="delete-button" icon="el-icon-minus" circle size="mini" plain type="danger" @click="toDeleteItem(link, index)"/>
</div> </div>
</div> </div>
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
<script> <script>
import {mapState, mapMutations} from 'vuex' import {mapState, mapMutations} from 'vuex'
import {clonePureObj} from "../../../../utils";
export default { export default {
name: "DataMappingEditor", name: "DataMappingEditor",
data() { data() {
return { return {
visible: false, visible: false,
editData: null,
} }
}, },
computed: { computed: {
...@@ -30,11 +32,17 @@ ...@@ -30,11 +32,17 @@
}), }),
}, },
methods: { methods: {
onAdd() { edit() {
this.addDataMapping(); this.editData = clonePureObj(this.mapping);
},
save() {
this.modifyDataMapping(this.editData);
}, },
onChange() { onAdd() {
this.modifyDataMapping(); this.editData.push({
name: '',
path: '',
});
}, },
toDeleteItem(link, index) { toDeleteItem(link, index) {
this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), { this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), {
...@@ -42,13 +50,11 @@ ...@@ -42,13 +50,11 @@
cancelButtonText: this.$t('Cancel'), cancelButtonText: this.$t('Cancel'),
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.deleteDataMapping(index); this.editData.splice(index, 1);
}).catch((e) => { }).catch((e) => {
}); });
}, },
...mapMutations([ ...mapMutations([
'addDataMapping',
'deleteDataMapping',
'modifyDataMapping', 'modifyDataMapping',
]), ]),
} }
......
<template> <template>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="view"> <el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<div class="mapping-list"> <div class="mapping-list">
<el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/> <el-button class="add-button" icon="el-icon-plus" size="mini" circle @click="onAdd"/>
<div class="list"> <div class="list">
<div class="item" v-for="(link, index) in env"> <div class="item" v-for="(link, index) in editData">
<el-input size="mini" style="width: 30%" v-model="link.name" @change="onChange"/> <el-input size="mini" style="width: 30%" v-model="link.name"/>
<el-icon class="el-icon-connection"/> <el-icon class="el-icon-connection"/>
<el-input size="mini" v-model="link.value" @change="onChange"/> <el-input size="mini" v-model="link.value"/>
<el-button class="delete-button" icon="el-icon-minus" circle size="mini" plain type="danger" @click="toDeleteItem(link, index)"/> <el-button class="delete-button" icon="el-icon-minus" circle size="mini" plain type="danger"
@click="toDeleteItem(link, index)"/>
</div> </div>
</div> </div>
</div> </div>
...@@ -16,12 +17,14 @@ ...@@ -16,12 +17,14 @@
<script> <script>
import {mapState, mapMutations} from 'vuex' import {mapState, mapMutations} from 'vuex'
import {clonePureObj} from "../../../../utils";
export default { export default {
name: "EnvEditor", name: "EnvEditor",
data() { data() {
return { return {
visible: false, visible: false,
editData: null,
} }
}, },
computed: { computed: {
...@@ -30,11 +33,17 @@ ...@@ -30,11 +33,17 @@
}), }),
}, },
methods: { methods: {
onAdd() { edit() {
this.addEnvMapping(); this.editData = clonePureObj(this.env);
},
save() {
this.modifyEnv(this.editData);
}, },
onChange() { onAdd() {
this.modifyEnvMapping(); this.editData.push({
name: '',
value: '',
});
}, },
toDeleteItem(link, index) { toDeleteItem(link, index) {
this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), { this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), {
...@@ -42,14 +51,12 @@ ...@@ -42,14 +51,12 @@
cancelButtonText: this.$t('Cancel'), cancelButtonText: this.$t('Cancel'),
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.deleteEnvMapping(index); this.editData.splice(index, 1);
}).catch((e) => { }).catch((e) => {
}); });
}, },
...mapMutations([ ...mapMutations([
'addEnvMapping', 'modifyEnv',
'deleteEnvMapping',
'modifyEnvMapping',
]), ]),
} }
} }
......
<template> <template>
<div> <div class="project-editor">
<el-scrollbar class="scrollbar full-scrollbar" wrap-class="wrap-x-hidden" view-class="view"> <el-scrollbar v-if="editData" class="project-scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<el-form @submit.native.prevent ref="form" :model="options" size="mini" label-position="right" <el-form @submit.native.prevent ref="form" :model="editData" size="mini" label-position="right"
label-width="150px"> label-width="150px">
<el-form-item prop="pageTitle" :label="$t('Page title')"> <el-form-item prop="pageTitle" :label="$t('Page title')">
<el-input v-model="options.pageTitle"/> <el-input v-model="editData.pageTitle"/>
</el-form-item> </el-form-item>
<el-form-item prop="entrySceneView" :label="$t('Entry scene view')"> <el-form-item prop="entrySceneView" :label="$t('Entry scene view')">
<el-select v-model="options.entrySceneView"> <el-select v-model="editData.entrySceneView">
<el-option v-for="(view, index) in project.data.views" <el-option v-for="(view, index) in project.data.views"
:key="index" :key="index"
:value="view.name" :value="view.name"
...@@ -16,19 +16,19 @@ ...@@ -16,19 +16,19 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item prop="containerId" :label="$t('Container ID')"> <el-form-item prop="containerId" :label="$t('Container ID')">
<el-input v-model="options.containerId"/> <el-input v-model="editData.containerId"/>
</el-form-item> </el-form-item>
<el-form-item prop="designWidth" :label="$t('Design width')"> <el-form-item prop="designWidth" :label="$t('Design width')">
<el-input-number v-model="options.designWidth" controls-position="right"/> <el-input-number v-model="editData.designWidth" controls-position="right"/>
</el-form-item> </el-form-item>
<el-form-item prop="designHeight" :label="$t('Design height')"> <el-form-item prop="designHeight" :label="$t('Design height')">
<el-input-number v-model="options.designHeight" controls-position="right"/> <el-input-number v-model="editData.designHeight" controls-position="right"/>
</el-form-item> </el-form-item>
<el-form-item prop="frameRate" :label="$t('Frame Rate')"> <el-form-item prop="frameRate" :label="$t('Frame Rate')">
<el-input-number v-model="options.frameRate" :max="60" :min="0" controls-position="right"/> <el-input-number v-model="editData.frameRate" :max="60" :min="0" controls-position="right"/>
</el-form-item> </el-form-item>
<el-form-item prop="scaleMode" :label="$t('Scale Mode')"> <el-form-item prop="scaleMode" :label="$t('Scale Mode')">
<el-select v-model="options.scaleMode"> <el-select v-model="editData.scaleMode">
<el-option v-for="(label, key) in scaleMode" <el-option v-for="(label, key) in scaleMode"
:key="key" :key="key"
:value="key" :value="key"
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item prop="rendererType" :label="$t('Renderer Type')"> <el-form-item prop="rendererType" :label="$t('Renderer Type')">
<el-select v-model="options.rendererType"> <el-select v-model="editData.rendererType">
<el-option v-for="(label, key) in rendererType" <el-option v-for="(label, key) in rendererType"
:key="key" :key="key"
:value="key" :value="key"
...@@ -48,18 +48,18 @@ ...@@ -48,18 +48,18 @@
<el-form-item prop="tpl" :label="$t('Template')"> <el-form-item prop="tpl" :label="$t('Template')">
<!-- <el-input type="textarea" v-model="options.tpl" :rows="10"/> --> <!-- <el-input type="textarea" v-model="options.tpl" :rows="10"/> -->
<codemirror ref="codeEditor" <codemirror ref="codeEditor"
v-model="options.tpl" v-model="editData.tpl"
:options="cmOptions" :options="cmOptions"
@cursorActivity="onCodeChange" @cursorActivity="onCodeChange"
> >
</codemirror> </codemirror>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-scrollbar> </el-scrollbar>
<div class="operate-bar"> <!--<div class="operate-bar">
<el-button size="mini" @click="onReset">{{$t('Reset')}}</el-button> <el-button size="mini" @click="onReset">{{$t('Reset')}}</el-button>
<el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button> <el-button size="mini" type="primary" @click="onSave">{{$t('Save')}}</el-button>
</div> </div>-->
</div> </div>
</template> </template>
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css' import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/javascript-hint.js' import 'codemirror/addon/hint/javascript-hint.js'
import {clonePureObj} from "../../../../utils";
export default { export default {
name: "ProjectEditor", name: "ProjectEditor",
...@@ -82,6 +83,7 @@ ...@@ -82,6 +83,7 @@
const rendererType = this.$t('rendererType'); const rendererType = this.$t('rendererType');
return { return {
visible: false, visible: false,
editData: null,
scaleMode, scaleMode,
rendererType, rendererType,
cmOptions: { cmOptions: {
...@@ -106,15 +108,21 @@ ...@@ -106,15 +108,21 @@
}, },
methods: { methods: {
...mapMutations([ ...mapMutations([
'modifyProject', 'modifyOptions',
]), ]),
onReset() { edit() {
this.editData = clonePureObj(this.options);
},
save() {
this.modifyOptions(this.editData);
},
/*onReset() {
this.$refs.form.resetFields(); this.$refs.form.resetFields();
}, },
onSave() { onSave() {
this.modifyProject(); this.modifyProject();
}, },*/
onCodeChange(codemirror){ onCodeChange(codemirror) {
//codemirror.showHint(); //codemirror.showHint();
//console.log(code); //console.log(code);
} }
......
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
<template slot="header" slot-scope="scope"> <template slot="header" slot-scope="scope">
<el-checkbox <el-checkbox
v-model="onlyMine" v-model="onlyMine"
size="mini">{{$t('Only mine')}}</el-checkbox> size="mini">{{$t('Only mine')}}
</el-checkbox>
</template> </template>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
...@@ -44,11 +45,12 @@ ...@@ -44,11 +45,12 @@
type="warning" icon="icon-download" type="warning" icon="icon-download"
size="small" circle plain> size="small" circle plain>
</el-button> </el-button>
<!--<el-button <el-button
v-if="showDeleteButton"
@click.native.prevent="onDeleteProject(scope.row)" @click.native.prevent="onDeleteProject(scope.row)"
type="danger" icon="el-icon-delete" type="danger" icon="el-icon-delete"
size="small" circle plain> size="small" circle plain>
</el-button>--> </el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -96,13 +98,16 @@ ...@@ -96,13 +98,16 @@
}); });
}, },
computed: { computed: {
showDeleteButton() {
return location.host.startsWith('localhost');
},
...mapState([ ...mapState([
'projects', 'projects',
'env', 'env',
]), ]),
}, },
watch: { watch: {
onlyMine(){ onlyMine() {
this.handleCurrentChange(1); this.handleCurrentChange(1);
} }
}, },
......
<template> <template>
<iframe ref="iframe" class="player-wrapper"> <div class="wrapper">
<iframe v-if="flag" ref="iframe" class="player-wrapper"></iframe>
</iframe> </div>
</template> </template>
<script> <script>
import {applyMock} from "./Preview/mock-serve";
import db from "../utils/db-storage";
import {newScriptEl} from "../utils";
export default { export default {
name: "Preview", name: "Preview",
components: {},
data() { data() {
return { return {
ts: '', ts: '',
flag: false,
} }
}, },
mounted() { async mounted() {
if(!this.ts){ this.codes = {};
this.urls = {};
if (!this.ts) {
this.ts = localStorage.getItem('preview-ts'); this.ts = localStorage.getItem('preview-ts');
} }
document.addEventListener("visibilitychange", this.onVisibilityChange); document.addEventListener("visibilitychange", this.onVisibilityChange);
setTimeout(()=>{
this.buildPage(); await db.open();
}, 100);
this.reload();
}, },
destroyed(){ destroyed() {
document.removeEventListener("visibilitychange", this.onVisibilityChange); document.removeEventListener("visibilitychange", this.onVisibilityChange);
}, },
methods: { methods: {
onVisibilityChange(e){ reload() {
if(!document.hidden){ this.flag = false;
setTimeout(() => {
this.flag = true;
this.buildPage();
}, 300);
},
onVisibilityChange(e) {
if (!document.hidden) {
let ts = localStorage.getItem('preview-ts'); let ts = localStorage.getItem('preview-ts');
if(this.ts !== ts){ if (this.ts !== ts) {
this.$refs.iframe.contentDocument.location.reload(); //this.$refs.iframe.contentDocument.location.reload();
document.location.reload(); //document.location.reload();
this.ts = ts; this.ts = ts;
this.reload();
} }
} }
}, },
buildPage() { async buildPage() {
const {projectID} = this.$route.params; const {projectID} = this.$route.params;
const storeKey = 'preview-project-' + projectID; const {data, codes} = await db.get('preview', projectID);
let data = localStorage.getItem(storeKey);
let dataObj = JSON.parse(data); let {options: {tpl, pageTitle, containerId}} = data;
//const dataName = projectID + "_data";
//const launchCode = `engine.launchWithWindowVariable("${dataName}");`;
let {options: {tpl, pageTitle, containerId}} = dataObj.data; const scripts = [];
for (let key in codes) {
let oldCode = this.codes[key];
let code = codes[key];
let url;
if (oldCode !== code) {
url = this.urls[key] = URL.createObjectURL(new Blob([code]));
} else {
url = this.urls[key];
}
scripts.push(newScriptEl(url));
}
this.codes = codes;
const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(data)]));
const launchCode = `engine.launchWithLocalStorage("${projectID}");`; document.title = pageTitle;
tpl = tpl tpl = tpl
.replace('$PAGE_TITLE$', pageTitle) .replace('$PAGE_TITLE$', pageTitle)
.replace('$CONTAINER_ID$', containerId) .replace('$CONTAINER_ID$', containerId)
.replace('$SCRIPTS$', '') .replace('$SCRIPTS$', scripts.join('\n'))
.replace('engine.launch(\'//yun.duiba.com.cn/aurora/$VERSION$-data.json\');', launchCode); .replace('//yun.duiba.com.cn/aurora/$VERSION$-data.json', dataUrl);
const doc = this.$refs.iframe.contentDocument; const doc = this.$refs.iframe.contentDocument;
const win = this.$refs.iframe.contentWindow;
doc.write(tpl); doc.write(tpl);
applyMock(projectID, win);
}, },
} }
} }
</script> </script>
<style scoped> <style scoped>
.player-wrapper{ .wrapper {
border: 0; width: 100%;
width: 100%; height: 100%;
height: 100%; }
}
.player-wrapper {
border: 0;
width: 100%;
height: 100%;
}
.mock-button {
position: absolute;
right: 10px;
bottom: 10px;
}
</style> </style>
\ No newline at end of file
/**
* Created by rockyl on 2019-12-18.
*/
import db from "../../utils/db-storage";
import {getMockServeEnabled} from "../../utils";
db.open();
const logStyle = "color: rgb(63, 172, 203)";
export function applyMock(projectID, win) {
win.mock = function ({url, method, params = {}, type}, callback, resolve, reject) {
const mockServeEnabled = getMockServeEnabled(projectID);
if (!mockServeEnabled) {
callback();
return;
}
if(url.includes('projectx')){
url = url.replace(/projectx\/\w+\//, '');
}
db.get('mock', url)
.then(
rule => {
if (rule && !rule.disabled) {
const {timeout = 0, successRatio = 1, data} = rule;
setTimeout(function () {
if (Math.random() < successRatio) {
try {
console.log(`%c[mock] ${url} ${method} ${JSON.stringify(params)}`, logStyle, JSON.parse(data));
resolve(JSON.parse(data));
} catch (e) {
reject(e);
}
} else {
reject(url + ' 404 (Not Found)')
}
}, timeout);
callback(rule);
} else {
callback();
}
},
e => {
callback();
}
);
};
}
\ No newline at end of file
/**
* Created by rockyl on 2019-12-20.
*/
import {clonePureObj} from "../../utils";
import {divideCode} from "zeroing-code-divider";
import db from "../../utils/db-storage";
const storeName = 'preview';
function getPack(packs) {
return function (ids) {
return packs.filter(pack => ids.includes(pack.id))
}
}
export async function preprocess(project, data, processes, scripts, customs) {
let newData = clonePureObj(data);
const codes = await divideCode(newData, {
debug: true,
getProcesses: getPack(processes),
getScripts: getPack(scripts),
getCustoms: getPack(customs),
});
db.set(storeName, {
id: project.id,
data: newData,
codes,
});
localStorage.setItem('preview-ts', Date.now().toString());
}
const serverHost = 'http://10.10.95.74:7777'; const serverHost = 'http://10.10.95.74:7777';
//const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = { module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '//yun.duiba.com.cn/editor/zeroing/v1/' : '', publicPath: process.env.NODE_ENV === 'production' ? '//yun.duiba.com.cn/editor/zeroing/v1/' : '',
pluginOptions: { pluginOptions: {
...@@ -23,6 +25,10 @@ module.exports = { ...@@ -23,6 +25,10 @@ module.exports = {
} }
},*/ },*/
configureWebpack: { configureWebpack: {
plugins: [
/*new MonacoWebpackPlugin({
languages: ['html', 'javascript', 'json']
})*/
]
} }
}; };
This diff is collapsed.
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<module version="4"> <module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/dist" />
</content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
......
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