Commit ceb066c8 authored by 劳工's avatar 劳工

Merge branch 'feature/huhu' into 'master'

Feature/huhu

See merge request !8
parents 0925bfb2 97d5ae63
...@@ -4,5 +4,6 @@ module.exports = { ...@@ -4,5 +4,6 @@ module.exports = {
id: 'LTAIqO2wblIxQvwc', id: 'LTAIqO2wblIxQvwc',
secret: '4brsaSRbRpjxw3oDIxJi6bNMcndIR6', secret: '4brsaSRbRpjxw3oDIxJi6bNMcndIR6',
bucket: 'duiba', bucket: 'duiba',
output: '/editor/zeroing/v1' output: '/editor/zeroing/v1',
exclude: /.js.map$/,
}; };
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
<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="//yun.duiba.com.cn/js-libs/jshint/2.10.2/jshint.min.js"></script>
<script src="https://cdn.bootcss.com/jsonlint/1.6.0/jsonlint.min.js"></script> <script src="//yun.duiba.com.cn/js-libs/jsonlint/1.6.0/jsonlint.min.js"></script>
<script src="//yun.duiba.com.cn/js-libs/psd.js/3.2.0/psd.min.js"></script>
</head> </head>
<body> <body>
<noscript> <noscript>
...@@ -18,7 +19,7 @@ ...@@ -18,7 +19,7 @@
<script> <script>
window.__data = { window.__data = {
token : "<%= process.env.NODE_ENV === 'development' ? 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjA4NSwibmFtZSI6IuWKs-eQquWzsCIsImFjY291bnQiOiJsYW9xaWZlbmciLCJlbWFpbCI6Imxhb3FpZmVuZ0BkdWliYS5jb20uY24iLCJtb2JpbGUiOiIxMzQ1Njc3NDE1MyIsImRpbmdVc2VySWQiOiI1MDY5MDYyOTIxMjkxMDAxIiwibW9kZWxBdXRob3JpemUiOmZhbHNlLCJsb2dpblRpbWVvdXQiOjgzMzUzLCJnbXRDcmVhdGUiOjE1MzQ0MTIwMTUwMDAsImdtdE1vZGlmaWVkIjoxNTczODgyMDk2MDAwLCJzeXN0ZW1JZFNldCI6WzAsMSwzNCwyMjcsMzYsMzcsMjMxLDIwMyw0NCwxOSwyMSwyNDYsMjMsMjQ5LDI1LDI3LDMwXSwiaWF0IjoxNTc4Mjc3OTg5fQ.mm6T34NuMBwTKaLBbVOI5AqGQNC9rwfiAdIv8c4C4_I' : '$TOKEN$' %>", token : "<%= process.env.NODE_ENV === 'development' ? 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjA4NSwibmFtZSI6IuWKs-eQquWzsCIsImFjY291bnQiOiJsYW9xaWZlbmciLCJlbWFpbCI6Imxhb3FpZmVuZ0BkdWliYS5jb20uY24iLCJtb2JpbGUiOiIxMzQ1Njc3NDE1MyIsImRpbmdVc2VySWQiOiI1MDY5MDYyOTIxMjkxMDAxIiwibW9kZWxBdXRob3JpemUiOmZhbHNlLCJsb2dpblRpbWVvdXQiOjgzMzUzLCJnbXRDcmVhdGUiOjE1MzQ0MTIwMTUwMDAsImdtdE1vZGlmaWVkIjoxNTczODgyMDk2MDAwLCJzeXN0ZW1JZFNldCI6WzAsMSwzNCwyMjcsMzYsMzcsMjMxLDIwMyw0NCwxOSwyMSwyNDYsMjMsMjQ5LDI1LDI3LDMwXSwiaWF0IjoxNTc4Mjc3OTg5fQ.mm6T34NuMBwTKaLBbVOI5AqGQNC9rwfiAdIv8c4C4_I' : '$TOKEN$' %>",
apiHost : "<%= process.env.NODE_ENV === 'development' ? 'http://beacon.duibadev.com.cn' : '$API_HOST$' %>" apiHost : "<%= process.env.NODE_ENV === 'development' ? '//beacon.duibadev.com.cn' : '$API_HOST$' %>"
} }
</script> </script>
<div id="app"></div> <div id="app"></div>
......
...@@ -92,6 +92,19 @@ export async function importView(file) { ...@@ -92,6 +92,19 @@ export async function importView(file) {
return response return response
} }
export async function uploadView(file) {
const response = await fetchApi('/api/uploadView', {
params: {
file,
},
method: 'post',
contentType: 'form-data',
errMessage: 'Failed to upload view',
})
response.__originFile = file;
return response
}
export async function uploadFile(file, compress = false, uuid) { export async function uploadFile(file, compress = false, uuid) {
let params = { file } let params = { file }
if (compress) { if (compress) {
......
...@@ -8,6 +8,7 @@ import events from './global-events'; ...@@ -8,6 +8,7 @@ import events from './global-events';
let socket; let socket;
export let codeSyncServeEnabled = false; export let codeSyncServeEnabled = false;
export let codeSyncServeConnected = false;
export function startCodeSyncServe(config) { export function startCodeSyncServe(config) {
if (socket) { if (socket) {
...@@ -20,25 +21,33 @@ export function startCodeSyncServe(config) { ...@@ -20,25 +21,33 @@ export function startCodeSyncServe(config) {
socket.on('edit-save', onEditSave); socket.on('edit-save', onEditSave);
events.$on('edit-open', editCode); events.$on('edit-open', editCode);
codeSyncServeEnabled = true;
events.$emit('code-sync-status', true);
} }
export function stop() { export function stopCodeSyncServe() {
if (socket) {
socket.close();
}
codeSyncServeEnabled = false;
events.$emit('code-sync-status', false);
} }
export function editCode(code) { export function editCode(code) {
if(socket && socket.connected){ if (socket && socket.connected) {
socket.emit('edit-open', code); socket.emit('edit-open', code);
} }
} }
function onConnect(t) { function onConnect(t) {
codeSyncServeEnabled = true; codeSyncServeConnected = true;
events.$emit('code-sync-start'); events.$emit('code-sync-start');
} }
function onDisconnect() { function onDisconnect() {
codeSyncServeEnabled = false; codeSyncServeConnected = false;
events.$emit('code-sync-stop'); events.$emit('code-sync-stop');
} }
......
<template> <template>
<el-form class="props-editor" v-if="data&&meta" v-model="data.props" size="mini" label-width="100px" label-position="left" @submit.native.prevent> <el-form class="props-editor" v-if="data&&meta" v-model="data.props" size="mini" :label-width="labelWidth"
label-position="right" @submit.native.prevent>
<component v-for="(property, key) in meta.props" <component v-for="(property, key) in meta.props"
:is="getInput(property)" :is="getInput(property)"
:container="data.props" :container="data.props"
...@@ -25,7 +26,9 @@ ...@@ -25,7 +26,9 @@
NodeSelectInput, NodeSelectInput,
MapInput, MapInput,
DynamicInput, DynamicInput,
Vector2Input,
} from "./inputs"; } from "./inputs";
import {parseType} from 'props-compute'
const inputMapping = { const inputMapping = {
number: 'NumberInput', number: 'NumberInput',
...@@ -37,18 +40,32 @@ ...@@ -37,18 +40,32 @@
node: 'NodeSelectInput', node: 'NodeSelectInput',
dynamic: 'DynamicInput', dynamic: 'DynamicInput',
map: 'MapInput', map: 'MapInput',
vector2: 'Vector2Input',
array: 'StringInput',
}; };
export default { export default {
name: "PropsEditor", name: "PropsEditor",
components: { components: {
DynamicInput, MapInput, NodeSelectInput, AssetInput, ColorInput, BooleanInput, EnumInput, NumberInput, StringInput}, DynamicInput,
MapInput,
NodeSelectInput,
AssetInput,
ColorInput,
BooleanInput,
EnumInput,
NumberInput,
StringInput,
Vector2Input
},
data() { data() {
return { return {}
}
}, },
props: { props: {
labelWidth: {
type: String,
default: '100px',
},
editable: { editable: {
type: Boolean, type: Boolean,
default: true default: true
...@@ -66,12 +83,13 @@ ...@@ -66,12 +83,13 @@
}, },
methods: { methods: {
getInput(property) { getInput(property) {
return inputMapping[property.type]; let {type} = parseType(property.type);
return inputMapping[type];
}, },
onInput(value, container, propName, oldValue){ onInput(value, container, propName, oldValue) {
if(value === undefined){ if (value === undefined) {
this.$delete(container ,propName); this.$delete(container, propName);
}else{ } else {
this.$set(container, propName, value); this.$set(container, propName, value);
} }
}, },
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<p>{{$t('Name')}}{{propertyName}}</p> <p>{{$t('Name')}}{{propertyName}}</p>
</div> </div>
<div> <div>
<p class="alias">{{property.alias}}</p> <p class="alias">{{property.alias||propertyName}}</p>
<p class="property-name">{{propertyName}}</p> <p class="property-name">{{propertyName}}</p>
</div> </div>
</el-tooltip> </el-tooltip>
......
<template> <template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" <input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName"> :propertyName="propertyName">
<div style="display: flex;flex: 1;"> <div style="display: flex;flex: 1;">
<el-popover <el-popover
placement="top" placement="top"
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
v-model="popoverVisible" v-model="popoverVisible"
> >
<div> <div>
<el-input v-model="filterText" prefix-icon="el-icon-search" size="mini" clearable/>
<el-scrollbar class="tree-scrollbar" wrap-class="wrap-x-hidden"> <el-scrollbar class="tree-scrollbar" wrap-class="wrap-x-hidden">
<el-tree <el-tree
ref="tree"
v-if="popoverVisible" v-if="popoverVisible"
:data="behavior_views" :data="behavior_views"
:props="defaultProps" :props="defaultProps"
...@@ -22,6 +24,7 @@ ...@@ -22,6 +24,7 @@
:default-expand-all="true" :default-expand-all="true"
@node-click="handleNodeClick" @node-click="handleNodeClick"
empty-text="" empty-text=""
:filter-node-method="filterNodeMethod"
> >
<div slot-scope="{ node, data }" class="tree-node"> <div slot-scope="{ node, data }" class="tree-node">
{{data.name}} {{data.name}}
...@@ -30,15 +33,19 @@ ...@@ -30,15 +33,19 @@
</el-scrollbar> </el-scrollbar>
<div class="bottom-bar"> <div class="bottom-bar">
<div></div> <div></div>
<el-button-group> <div>
<el-button @click="onCancel" plain>Cancel</el-button> <el-button @click="onCancel" plain>Cancel</el-button>
<el-button @click="onConfirm" type="primary" plain>Confirm</el-button> <el-button @click="onConfirm" type="primary">Confirm</el-button>
</el-button-group> </div>
</div> </div>
</div> </div>
<el-input clearable slot="reference" v-model="editValue" @change="onInput" placeholder="unset" <el-input clearable slot="reference" :value="editValue" @change="onInput" placeholder="unset"
:readonly="!editable"> :readonly="!editable">
<template slot="prepend">node://</template> <template slot="prepend">
<el-tooltip effect="dark" :content="nodePath" placement="top" :open-delay="500" :disabled="!nodePath">
<el-button>{{nodeScheme}}</el-button>
</el-tooltip>
</template>
</el-input> </el-input>
</el-popover> </el-popover>
<el-button-group> <el-button-group>
...@@ -52,8 +59,7 @@ ...@@ -52,8 +59,7 @@
<script> <script>
import {mapGetters} from "vuex"; import {mapGetters} from "vuex";
import InputWrapper from "./InputWrapper"; import InputWrapper from "./InputWrapper";
import {nodeScheme} from "../../utils";
const nodeScheme = 'node://';
export default { export default {
name: "NodeSelectInput", name: "NodeSelectInput",
...@@ -61,26 +67,37 @@ ...@@ -61,26 +67,37 @@
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'], props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() { data() {
return { return {
nodeScheme: nodeScheme,
filterText: '',
editValueOrigin: this.value, editValueOrigin: this.value,
popoverVisible: false, popoverVisible: false,
defaultProps: { defaultProps: {
children: 'children', children: 'children',
label: 'name' label: 'name'
}, },
nodePath: '',
} }
}, },
watch: { watch: {
value(v) { value(v) {
this.editValueOrigin = v; this.editValue = v;
} },
filterText(val) {
this.updateFilter();
},
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'behavior_views' 'behavior_views',
'behavior_searchViewNode',
]), ]),
editValue: { editValue: {
get() { get() {
return this.editValueOrigin && typeof this.editValueOrigin !== 'object'? this.editValueOrigin.replace(nodeScheme, '') : ''; let v = this.editValueOrigin && typeof this.editValueOrigin !== 'object' ? this.editValueOrigin.replace(nodeScheme, '') : '';
this.updateNodePath(v);
return v;
}, },
set(v) { set(v) {
this.editValueOrigin = v; this.editValueOrigin = v;
...@@ -91,6 +108,23 @@ ...@@ -91,6 +108,23 @@
}, },
}, },
methods: { methods: {
updateNodePath(v) {
let uuid = v ? v.replace(nodeScheme, '') : null;
let searchResult = this.behavior_searchViewNode(uuid);
if (searchResult) {
this.nodePath = searchResult.path;
} else {
this.nodePath = '';
}
},
updateFilter() {
if (this.$refs.tree) {
this.$refs.tree.filter(this.filterText);
}
},
filterNodeMethod(value, data) {
return data.name.toLowerCase().includes(value.toLowerCase());
},
onInput(v, oldValue) { onInput(v, oldValue) {
if (v !== this.value) { if (v !== this.value) {
this.$emit('input', v ? nodeScheme + v : undefined, this.container, this.propertyName, oldValue); this.$emit('input', v ? nodeScheme + v : undefined, this.container, this.propertyName, oldValue);
...@@ -103,6 +137,7 @@ ...@@ -103,6 +137,7 @@
this.popoverVisible = !this.popoverVisible; this.popoverVisible = !this.popoverVisible;
}, },
onClickClean() { onClickClean() {
this.nodePath = '';
this.$emit('input', undefined, this.container, this.propertyName, this.value); this.$emit('input', undefined, this.container, this.propertyName, this.value);
}, },
onConfirm() { onConfirm() {
......
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<span class="field-label">x</span>
<el-input-number :disabled="!editable" :value="editValue.x" @input="v=>onInput(v, 'x')" controls-position="right"
:placeholder="defaultValue.x"></el-input-number>
<span class="field-label">y</span>
<el-input-number :disabled="!editable" :value="editValue.y" @input="v=>onInput(v, 'y')" controls-position="right"
:placeholder="defaultValue.y"></el-input-number>
</input-wrapper>
</template>
<script>
import {parseVector2} from "props-compute";
import InputWrapper from "./InputWrapper";
export default {
name: "Vector2Input",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
return {
editValue: {},
}
},
watch: {
value(v) {
let editValue = v === undefined ? this.property.default : v;
this.editValue = parseVector2(editValue);
}
},
computed: {
/*editValue() {
return this.value === undefined ? this.property.default : this.value;
},*/
defaultValue() {
let value = this.property.default;
let placeholder = {};
if (value) {
let v = parseVector2(value);
placeholder.x = v.x + '';
placeholder.y = v.y + '';
} else {
placeholder.x = 'unset';
placeholder.y = 'unset';
}
return placeholder;
},
},
methods: {
onInput(v, field) {
this.editValue[field] = v;
let {x, y} = this.editValue;
let value = {
x, y,
};
this.$emit('input', value, this.container, this.propertyName, this.value);
}
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -11,3 +11,4 @@ export {default as AssetInput} from './AssetInput'; ...@@ -11,3 +11,4 @@ export {default as AssetInput} from './AssetInput';
export {default as NodeSelectInput} from './NodeSelectInput'; export {default as NodeSelectInput} from './NodeSelectInput';
export {default as MapInput} from './MapInput'; export {default as MapInput} from './MapInput';
export {default as DynamicInput} from './DynamicInput'; export {default as DynamicInput} from './DynamicInput';
export {default as Vector2Input} from './Vector2Input';
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
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 = '//10.10.95.74:7777';
//API_HOST = 'http://192.168.1.16:7777'; //API_HOST = '//192.168.1.16:7777';
//API_HOST = 'http://192.168.0.104:7777'; //API_HOST = '//192.168.0.104:7777';
//API_HOST = 'http://10.10.92.33:7777'; //API_HOST = '//10.10.92.33:7777';
//API_HOST = 'http://localhost:3002'; //API_HOST = '//localhost:3002';
API_HOST = window.__data.apiHost; API_HOST = window.__data.apiHost;
//API_HOST = ''; //API_HOST = '';
} else { } else {
......
...@@ -157,6 +157,7 @@ ...@@ -157,6 +157,7 @@
"Import single": "Import single", "Import single": "Import single",
"Import multi": "Import multi", "Import multi": "Import multi",
"Import view success": "Import view success", "Import view success": "Import view success",
"Input projectx id": "Input {envName} projectx id",
"menu": { "menu": {
"save": { "save": {
"label": "Save" "label": "Save"
...@@ -243,5 +244,10 @@ ...@@ -243,5 +244,10 @@
"rendererType": { "rendererType": {
"webgl": "WEBGL", "webgl": "WEBGL",
"canvas": "CANVAS" "canvas": "CANVAS"
},
"pxEnvs": {
"dev": "Dev Env",
"test": "Test Env",
"prod": "Prod Env"
} }
} }
\ No newline at end of file
...@@ -15,17 +15,22 @@ ...@@ -15,17 +15,22 @@
"Exit": "退出", "Exit": "退出",
"Props": "属性", "Props": "属性",
"Behavior": "行为", "Behavior": "行为",
"Only mine": "仅显示我的", "Only mine": "仅我的",
"Add": "添加", "Add": "添加",
"Delete": "删除", "Delete": "删除",
"Delete all": "删除全部", "Delete all": "删除全部",
"Not delete": "不删除", "Not delete": "不删除",
"History": "历史",
"Duplicate": "拷贝",
"Import": "导入", "Import": "导入",
"Export": "导出", "Export": "导出",
"Importing project": "项目导入中", "Importing project": "项目导入中",
"Exporting project": "项目导出中", "Exporting project": "项目导出中",
"Upload": "上传", "Upload": "上传",
"Uploading": "上传中", "Uploading": "上传中",
"Auto launch": "自动启动",
"Running status": "运行状态",
"Stop status": "停止状态",
"Edit": "编辑", "Edit": "编辑",
"EditEnv": "编辑环境", "EditEnv": "编辑环境",
"EditCustomModule": "编辑自定义模块", "EditCustomModule": "编辑自定义模块",
...@@ -34,6 +39,7 @@ ...@@ -34,6 +39,7 @@
"ID": "ID", "ID": "ID",
"Mock Editor": "Mock编辑器", "Mock Editor": "Mock编辑器",
"Enable mock serve": "启用Mock服务", "Enable mock serve": "启用Mock服务",
"Events": "事件",
"Name": "名字", "Name": "名字",
"Alias": "别名", "Alias": "别名",
"Output": "输出", "Output": "输出",
...@@ -90,6 +96,7 @@ ...@@ -90,6 +96,7 @@
"Scale Mode": "缩放模式", "Scale Mode": "缩放模式",
"Renderer Type": "渲染模式", "Renderer Type": "渲染模式",
"Props Editor": "属性编辑器", "Props Editor": "属性编辑器",
"Events details": "事件详情",
"Trigger once": "触发一次", "Trigger once": "触发一次",
"Meta Editor": "过程元配置", "Meta Editor": "过程元配置",
"Env editor": "环境编辑器", "Env editor": "环境编辑器",
...@@ -162,6 +169,12 @@ ...@@ -162,6 +169,12 @@
"Import single": "导入单", "Import single": "导入单",
"Import multi": "导入多", "Import multi": "导入多",
"Import view success": "视图导入成功", "Import view success": "视图导入成功",
"Input projectx id": "请输入{envName}星速台项目ID",
"Save template to projectx": "是否保存皮肤到星速台",
"eventGroup": {
"in": "接收",
"out": "派发"
},
"menu": { "menu": {
"save": { "save": {
"label": "保存" "label": "保存"
...@@ -227,6 +240,7 @@ ...@@ -227,6 +240,7 @@
}, },
"nodeFilterPresets": { "nodeFilterPresets": {
"trigger": "行为触发", "trigger": "行为触发",
"script": "脚本过滤",
"type": "节点类型" "type": "节点类型"
}, },
"events": { "events": {
...@@ -251,5 +265,32 @@ ...@@ -251,5 +265,32 @@
"rendererType": { "rendererType": {
"webgl": "WEBGL", "webgl": "WEBGL",
"canvas": "CANVAS" "canvas": "CANVAS"
},
"pxEnvs": {
"dev": "开发环境",
"test": "测试环境",
"prod": "线上环境"
},
"tplOperates": [
"新增",
"修改",
"删除"
],
"tplTypes": [
"首页",
"其他"
],
"processGroups": {
"Custom": "自定义节点",
"Divider": "分流节点",
"builtin": "内建",
"trigger": "触发",
"custom": "自定义"
},
"dividerTypes": {
"first": "负责首个",
"last": "负责末个",
"all": "负责全部",
"race": "负责最先"
} }
} }
\ No newline at end of file
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import Vue from "vue"; import Vue from "vue";
import i18n from "../../i18n"; import i18n from "../../i18n";
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
import {clonePureObj, metaInUse, updateProcesses} from "../../utils"; import {clonePureObj, getViewNodePath, metaInUse, searchViewNode, updateProcesses} from "../../utils";
import {arrayFind} from "element-ui/src/utils/util"; import {arrayFind} from "element-ui/src/utils/util";
export const behaviorStore = { export const behaviorStore = {
...@@ -89,14 +89,16 @@ export const behaviorStore = { ...@@ -89,14 +89,16 @@ export const behaviorStore = {
return map; return map;
}, },
metaInUse: state => targetMetaID => { metaInUse: state => targetMetaID => {
let result = false; let allMetasInUse = [];
for (let process of state.data.processes) { for (let process of state.data.processes) {
if (metaInUse(process, targetMetaID)) { let usedMetas = metaInUse(process, targetMetaID);
allMetasInUse.push(...usedMetas);
/*if (usedMetas.length > 0) {
result = true; result = true;
break; break;
} }*/
} }
return result; return allMetasInUse;
}, },
metaIDExists: state => id => { metaIDExists: state => id => {
let result = false; let result = false;
...@@ -113,6 +115,11 @@ export const behaviorStore = { ...@@ -113,6 +115,11 @@ export const behaviorStore = {
}, },
behavior_views: state => { behavior_views: state => {
return state.data.views; return state.data.views;
},
behavior_searchViewNode: state => uuid => {
if(uuid){
return searchViewNode(state.data.views, uuid);
}
} }
}, },
actions: { actions: {
...@@ -126,6 +133,7 @@ export const behaviorStore = { ...@@ -126,6 +133,7 @@ export const behaviorStore = {
script: '', script: '',
props: {}, props: {},
isInline, isInline,
from: 'custom',
}; };
switch (processId) { switch (processId) {
case 'custom': case 'custom':
...@@ -146,6 +154,7 @@ export const behaviorStore = { ...@@ -146,6 +154,7 @@ export const behaviorStore = {
let meta = clonePureObj(pMeta); let meta = clonePureObj(pMeta);
meta.id = generateUUID(); meta.id = generateUUID();
meta.isInline = isInline; meta.isInline = isInline;
meta.from = 'custom';
delete meta.type; delete meta.type;
addProcessMeta(commit, isInline, masterProcess, meta); addProcessMeta(commit, isInline, masterProcess, meta);
...@@ -180,14 +189,14 @@ function searchMeta(processes, keyword, path) { ...@@ -180,14 +189,14 @@ function searchMeta(processes, keyword, path) {
} }
} }
export function addBehavior(alias, processes) { export function addBehavior({alias, from}, processes) {
let metaUUID = generateUUID(); let metaUUID = generateUUID();
let behavior = { let behavior = {
uuid: generateUUID(), uuid: generateUUID(),
meta: metaUUID, meta: metaUUID,
}; };
let subEntryUUID = generateUUID(); let subEntryUUID = generateUUID();
processes.push({ let p = {
id: metaUUID, id: metaUUID,
name: alias, name: alias,
props: {}, props: {},
...@@ -203,7 +212,11 @@ export function addBehavior(alias, processes) { ...@@ -203,7 +212,11 @@ export function addBehavior(alias, processes) {
} }
}, },
}, },
}); };
if(from){
p.from = from;
}
processes.push(p);
return behavior; return behavior;
} }
......
...@@ -22,6 +22,7 @@ export const envStore = { ...@@ -22,6 +22,7 @@ export const envStore = {
scripts: [], scripts: [],
customs: [], customs: [],
codeSyncServeConfig: { codeSyncServeConfig: {
autoLaunch: false,
ip: 'localhost', ip: 'localhost',
port: 7788, port: 7788,
} }
...@@ -60,19 +61,25 @@ export const envStore = { ...@@ -60,19 +61,25 @@ export const envStore = {
]; ];
const dividerProcess = { const dividerProcess = {
id: 'divider', id: 'divider',
name: i18n.t('Divider'), name: 'Divider',
desc: i18n.t('Divider node desc'),//'分流节点,出口会按顺序一次执行', desc: i18n.t('Divider node desc'),//'分流节点,出口会按顺序一次执行',
}; };
tree.unshift(dividerProcess); tree.unshift(dividerProcess);
const customProcess = { const customProcess = {
id: 'custom', id: 'custom',
name: i18n.t('Custom'), name: 'Custom',
desc: i18n.t('Custom node desc'),//'自定义节点', desc: i18n.t('Custom node desc'),//'自定义节点',
}; };
tree.unshift(customProcess); tree.unshift(customProcess);
tree.push({
name: 'trigger',
from: 'trigger',
children: [],
});
tree.push({ tree.push({
name: 'custom', name: 'custom',
from: 'custom',
children: [], children: [],
}); });
......
This diff is collapsed.
...@@ -34,7 +34,7 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u ...@@ -34,7 +34,7 @@ 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="${process.env.NODE_ENV === 'development' ? 'http://10.10.92.100:4002/debug/engine.js' : 'http://yun.duiba.com.cn/editor/zeroing/libs/engine.4db1f30a604493bbb87d4966af54cdd10840047a.js'}"></script> <script src="${process.env.NODE_ENV === 'development' ? 'http://10.10.92.100:4002/debug/engine.js' : '//yun.duiba.com.cn/editor/zeroing/libs/engine.4db1f30a604493bbb87d4966af54cdd10840047a.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');
......
...@@ -299,7 +299,23 @@ $dock-pin-width: 9px; ...@@ -299,7 +299,23 @@ $dock-pin-width: 9px;
.scrollbar-view { .scrollbar-view {
padding-right: 10px; padding-right: 10px;
}
}
.inside-code{
flex: 1;
height: 0;
border-top: 1px solid $--border-color-base;
.scrollbar {
height: 100%;
.code-body{
tab-size: 1.5em;
width: 100%;
margin: 0;
font-size: 12px;
white-space:pre-wrap;
}
} }
} }
} }
...@@ -449,6 +465,10 @@ $dock-pin-width: 9px; ...@@ -449,6 +465,10 @@ $dock-pin-width: 9px;
color: $--color-text-secondary; color: $--color-text-secondary;
} }
} }
.field-label{
padding: 0 5px;
color: $--color-text-secondary;
}
} }
.el-form-item__content { .el-form-item__content {
......
...@@ -164,10 +164,53 @@ ...@@ -164,10 +164,53 @@
flex: 1; flex: 1;
} }
} }
}
.dialog-footer { .dialog-footer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
}
.props-editor-dialog {
.scrollbar {
height: 40vh;
.scrollbar-view {
padding-right: 10px;
padding-bottom: 10px;
}
}
}
.events-details-dialog {
.scrollbar {
height: 40vh;
.collapse {
margin-right: 10px;
.group {
margin-left: 10px;
.data-item {
max-width: 300px;
display: flex;
justify-content: space-between;
}
.data-item + .data-item {
margin-top: 5px;
}
}
}
} }
} }
.code-sync-serve-dialog {
.dialog-footer {
.status {
font-size: 14px;
color: $--color-text-primary;
}
}
}
@import "var"; @import "var";
.home { .home {
padding: 20px 30px; padding: 20px 20px;
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
......
...@@ -59,6 +59,11 @@ ...@@ -59,6 +59,11 @@
height: 100%; height: 100%;
} }
.el-collapse-item__header{
height: 30px;
line-height: 30px;
}
.el-tabs--border-card > .el-tabs__content { .el-tabs--border-card > .el-tabs__content {
padding: 5px 0 5px 5px; padding: 5px 0 5px 5px;
} }
......
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
height: 0; height: 0;
} }
.el-collapse-item__header{
height: 25px;
line-height: 25px;
}
.el-tabs__item { .el-tabs__item {
height: 25px; height: 25px;
line-height: 25px; line-height: 25px;
......
...@@ -30,6 +30,7 @@ const attrShortMapper = { ...@@ -30,6 +30,7 @@ const attrShortMapper = {
y: 'top', y: 'top',
align: 'text-align', align: 'text-align',
size: 'font-size', size: 'font-size',
font: 'font-family',
alpha: 'opacity', alpha: 'opacity',
'strokeColor': 'border-color', 'strokeColor': 'border-color',
'strokeWidth': 'border-width', 'strokeWidth': 'border-width',
......
...@@ -6,6 +6,10 @@ import {Message, Loading} from "element-ui"; ...@@ -6,6 +6,10 @@ import {Message, Loading} from "element-ui";
import i18n from '../i18n' import i18n from '../i18n'
import generateUUID from "uuid/v4"; import generateUUID from "uuid/v4";
/**
* 动态数据图标映射
* @type {{"data-center": string, static: string, scope: string, arguments: string, env: string}}
*/
export const dynamicIconMapping = { export const dynamicIconMapping = {
'static': 'S', 'static': 'S',
'arguments': 'A', 'arguments': 'A',
...@@ -14,6 +18,16 @@ export const dynamicIconMapping = { ...@@ -14,6 +18,16 @@ export const dynamicIconMapping = {
'env': 'E', 'env': 'E',
}; };
/**
* 节点方案
* @type {string}
*/
export const nodeScheme = 'node://';
/**
* 弹出错误消息
* @param e
*/
export function messageError(e) { export function messageError(e) {
Message({ Message({
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
...@@ -22,6 +36,13 @@ export function messageError(e) { ...@@ -22,6 +36,13 @@ export function messageError(e) {
}) })
} }
/**
* 播放等待动画
* @param promise
* @param text
* @param closeLoading
* @return {*}
*/
export function playWaiting(promise, text, closeLoading = true) { export function playWaiting(promise, text, closeLoading = true) {
const loading = Loading.service({ const loading = Loading.service({
lock: true, lock: true,
...@@ -73,22 +94,38 @@ export function updateProcesses(processes, targetMetaID, replaceMetaID) { ...@@ -73,22 +94,38 @@ export function updateProcesses(processes, targetMetaID, replaceMetaID) {
} }
} }
/**
* 过程元依赖过程
* @param process
* @param targetMetaID
* @return {Array}
*/
export function metaInUse(process, targetMetaID) { export function metaInUse(process, targetMetaID) {
let result = false; let result = [];
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) {
result = true; result.push(process);
break; //break;
} }
} }
return result; return result;
} }
/**
* 克隆纯数据对象
* @param obj
* @return {any}
*/
export function clonePureObj(obj) { export function clonePureObj(obj) {
return JSON.parse(JSON.stringify(obj)); return JSON.parse(JSON.stringify(obj));
} }
/**
* 保存到本地
* @param blob
* @param fileName
*/
export function saveAs(blob, fileName) { export function saveAs(blob, fileName) {
if ('msSaveOrOpenBlob' in navigator) { if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(blob, fileName); navigator.msSaveOrOpenBlob(blob, fileName);
...@@ -109,6 +146,11 @@ export function saveAs(blob, fileName) { ...@@ -109,6 +146,11 @@ export function saveAs(blob, fileName) {
} }
} }
/**
* 读取文本文件
* @param file
* @return {Promise}
*/
export function readTextFile(file) { export function readTextFile(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const fileReader = new FileReader(); const fileReader = new FileReader();
...@@ -124,37 +166,55 @@ export function readTextFile(file) { ...@@ -124,37 +166,55 @@ export function readTextFile(file) {
}) })
} }
function scanEntries(item){ /**
* 扫描文件实体
* @param item
* @return {Promise}
*/
function scanEntries(item) {
return new Promise(resolve => { return new Promise(resolve => {
if (item.isDirectory) { if (item.isDirectory) {
let directoryReader = item.createReader(); let directoryReader = item.createReader();
directoryReader.readEntries(function(es){ directoryReader.readEntries(function (es) {
resolve(es); resolve(es);
}); });
}else{ } else {
resolve(); resolve();
} }
}) })
} }
/**
* 扫描文件
* @param item
* @param container
* @return {Promise<void>}
*/
export async function scanFiles(item, container) { export async function scanFiles(item, container) {
const entries = await scanEntries(item); const entries = await scanEntries(item);
if(entries){ if (entries) {
for(let entry of entries){ for (let entry of entries) {
container.push(entry); container.push(entry);
await scanFiles(entry, container); await scanFiles(entry, container);
} }
} }
} }
/**
* 选择文件
* @param callback
* @param accept
* @param multiple
* @param acceptDirectory
*/
export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) { 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){ if (acceptDirectory) {
input.webkitdirectory = true; input.webkitdirectory = true;
} }
if (accept) { if (accept) {
...@@ -166,6 +226,10 @@ export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) { ...@@ -166,6 +226,10 @@ export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) {
input.click(); input.click();
} }
/**
* 打开预览页面
* @param packResult
*/
export function openPreview(packResult) { export function openPreview(packResult) {
setTimeout(() => { setTimeout(() => {
let url; let url;
...@@ -178,10 +242,29 @@ export function openPreview(packResult) { ...@@ -178,10 +242,29 @@ export function openPreview(packResult) {
}, 500); }, 500);
} }
/**
* url包装script元素
* @param url
* @return {string}
*/
export function newScriptEl(url) { export function newScriptEl(url) {
return `<script src="${url}"></script>` return `<script src="${url}"></script>`
} }
/**
* 内容包装script元素
* @param content
* @return {string}
*/
export function newScriptContent(content) {
return `<script>${content}</script>`
}
/**
* 获取mock服务启用状态
* @param projectID
* @return {boolean}
*/
export function getMockServeEnabled(projectID) { export function getMockServeEnabled(projectID) {
let enabled = localStorage.getItem('mock-enabled-' + projectID); let enabled = localStorage.getItem('mock-enabled-' + projectID);
if (enabled) { if (enabled) {
...@@ -189,3 +272,40 @@ export function getMockServeEnabled(projectID) { ...@@ -189,3 +272,40 @@ export function getMockServeEnabled(projectID) {
} }
return !!enabled; return !!enabled;
} }
/**
* 搜索视图节点
* @param nodes
* @param uuid
* @param path
*/
export function searchViewNode(nodes, uuid, path = '') {
for (let node of nodes) {
if (node.uuid === uuid) {
return {
node,
path: path + '/' + node.name,
};
} else if (node.children && node.children.length > 0) {
let t = searchViewNode(node.children, uuid, path + '/' + node.name);
if (t) {
return t;
}
}
}
}
/**
* 获取视图节点路径(目前没有parent,所以无法使用)
* @param node
* @param sep
*/
export function getViewNodePath(node, sep = '/') {
let cNode = node;
let segs = [];
while (cNode) {
segs.unshift(cNode.name);
cNode = cNode.parent;
}
return segs.join(sep)
}
...@@ -52,13 +52,13 @@ export default { ...@@ -52,13 +52,13 @@ export default {
value: undefined value: undefined
}, },
horizonCenter: { horizonCenter: {
title: '水平偏移', title: '水平居中偏移',
type: 'inputNumber', type: 'inputNumber',
value: undefined, value: undefined,
//desc: '相对于父元素中心点的水平偏移,0为正中心' //desc: '相对于父元素中心点的水平偏移,0为正中心'
}, },
verticalCenter: { verticalCenter: {
title: '垂直偏移', title: '垂直居中偏移',
type: 'inputNumber', type: 'inputNumber',
value: undefined, value: undefined,
//desc: '相对于父元素中心点的垂直偏移,0为正中心' //desc: '相对于父元素中心点的垂直偏移,0为正中心'
...@@ -135,6 +135,11 @@ export default { ...@@ -135,6 +135,11 @@ export default {
type: 'textArea', type: 'textArea',
value: '' value: ''
}, },
font: {
title: '字体',
type: 'input',
value: 'Arial'
},
htmlText: { htmlText: {
title: 'HTML内容', title: 'HTML内容',
type: 'input', type: 'input',
......
...@@ -90,9 +90,11 @@ ...@@ -90,9 +90,11 @@
await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => { await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
console.log(e); console.log(e);
}); });
setTimeout(() => { if(this.codeSyncServeConfig.autoLaunch){
//startCodeSyncServe(this.codeSyncServeConfig); setTimeout(() => {
}, 100); startCodeSyncServe(this.codeSyncServeConfig);
}, 100);
}
this.loadProject().catch(e => { this.loadProject().catch(e => {
console.log(e); console.log(e);
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
<script> <script>
import events from "../../../global-events"; import events from "../../../global-events";
import {codeSyncServeEnabled} from "../../../code-sync-serve"; import {codeSyncServeConnected} from "../../../code-sync-serve";
export default { export default {
name: "CodeSyncIndicator", name: "CodeSyncIndicator",
data() { data() {
return { return {
enabled: codeSyncServeEnabled, enabled: codeSyncServeConnected,
} }
}, },
mounted() { mounted() {
......
<template>
<div class="zero-inspector-behavior-form" v-if="activeComponent.uuid">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-form ref="form" size="mini" label-width="60px">
<div v-for="(evn, key) in eventsObj" :key="key">
<el-form-item :label="$t('Event') + ':'">
<div>{{events[key]}}</div>
<div >
<!--<el-tooltip :content="$t('Trigger once')" placement="top">
<el-switch v-model="evn.once" @change="v => handleOnceChange(key, v)"></el-switch>
</el-tooltip>-->
<el-button size="mini" @click="showBehaviorEditor(evn, key)" style="margin-left: 20px;" icon="el-icon-edit">
<!--<i v-if="evn.behaviors && evn.behaviors.length" class="el-icon-check el-icon&#45;&#45;right"></i>-->
</el-button>
<el-button icon="el-icon-delete" size="mini" v-if="evn.behaviors && evn.behaviors.length" @click="deleteBehavior(key)">
</el-button>
</div>
</el-form-item>
</div>
</el-form>
</el-scrollbar>
<behavior-editor-dialog :behaviors="behaviors" @change="isPreview => handleBehaviorsChange(isPreview)" ref="behaviorEditorDialog"></behavior-editor-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import _ from 'lodash';
import BehaviorEditorDialog from '../dialogs/BehaviorEditorDialog';
import events from "@/global-events.js"
export default {
name: 'BehaviorTab2',
data() {
let eventsObj = {};
const events = this.$t('events');
Object.keys(events).forEach(event => {
eventsObj[event] = {
once: false,
behaviors: []
};
});
return {
events,
eventsObj,
behaviors: [],
currentEvent: ''
};
},
components: { BehaviorEditorDialog },
computed: {
...mapGetters(['activeComponent', 'componentList'])
},
methods: {
showBehaviorEditor(evn, key) {
this.currentEvent = key;
this.behaviors = evn.behaviors || [];
this.$refs.behaviorEditorDialog.show(this.behaviors, this.activeComponent.name + '_' + key);
},
/**
* 当前选中组件发生变化时,更新eventsObj的数据
*/
updateEventsObj() {
let _events = this.activeComponent.events || {};
_.forIn(this.eventsObj, (value, key) => {
if (_events[key]) {
this.$set(this.eventsObj, key, _.cloneDeep(_events[key]));
} else {
value.once = false;
value.behaviors = [];
}
});
},
/**
* 是否只执行一次
*/
handleOnceChange(key, v) {
let _event = this.eventsObj[key];
// 如果没有behavior,once没有用处,则不执行
if (_event.behaviors && _event.behaviors.length) {
let event = {};
event[key] = {
once: v,
behaviors: _event.behaviors
};
let events = this.activeComponent.events;
this.$store.dispatch('modifyActiveView', {
events: _.merge({}, events, event)
});
}
},
/**
* 行为发生变化,同步数据
*/
handleBehaviorsChange(isPreview) {
if (this.currentEvent /* && v && v.length*/) {
let event = {};
let currentEvent = this.eventsObj[this.currentEvent];
event[this.currentEvent] = Object.assign(currentEvent /*, { behaviors: v }*/);
let events = this.activeComponent.events;
this.$store.dispatch('modifyActiveView', {
events: _.merge({}, events, event)
});
this.updateEventsObj();
}
if(isPreview){
events.$emit('saveAndPreview')
}
},
/**
* 删除行为
*/
deleteBehavior(key) {
let _events = this.activeComponent.events || {};
delete _events[key];
this.$store.dispatch('modifyActiveView', {
events: _events
});
this.updateEventsObj();
}
},
watch: {
'activeComponent.uuid': function() {
this.updateEventsObj();
console.log('activeComponent.uuid change');
}
}
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template> <template>
<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="100px" @submit.native.prevent>
<el-form-item label="名称"> <el-form-item label="名称">
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input> <el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item> </el-form-item>
......
...@@ -76,6 +76,8 @@ ...@@ -76,6 +76,8 @@
import {selectFile} from "../../utils"; import {selectFile} from "../../utils";
import events from "../../global-events"; import events from "../../global-events";
let PSD = window['require']('psd');
export default { export default {
name: 'Views', name: 'Views',
components: {Pane}, components: {Pane},
...@@ -140,11 +142,28 @@ ...@@ -140,11 +142,28 @@
} }
} }
break; break;
case 'script':
if (data.scripts && data.scripts.length > 0) {
visible = true;
if (param && param.length > 0) {
let scripts = param.split(',');
let exists = false;
for (let script of data.scripts) {
if (scripts.includes(script.script)) {
exists = true;
break;
}
}
visible = exists;
}
}
break;
case 'type': case 'type':
if (param && param.length > 0) { if (param && param.length > 0) {
let types = param.split(','); let types = param.split(',');
visible = types.includes(data.type); visible = types.includes(data.type);
}else{ } else {
visible = true; visible = true;
} }
break; break;
...@@ -162,6 +181,9 @@ ...@@ -162,6 +181,9 @@
case 'trigger': case 'trigger':
filterText = ':trigger'; filterText = ':trigger';
break; break;
case 'script':
filterText = ':script';
break;
case 'type': case 'type':
filterText = ':type|node'; filterText = ':type|node';
break; break;
...@@ -201,7 +223,7 @@ ...@@ -201,7 +223,7 @@
selectFile(async files => { selectFile(async files => {
events.$emit('upload-indicator', true); events.$emit('upload-indicator', true);
try { try {
await this.importView({ await this.importPsd({
file: files[0], file: files[0],
action, action,
}); });
...@@ -266,7 +288,7 @@ ...@@ -266,7 +288,7 @@
} }
}, },
...mapMutations(['copyNode', 'pasteNode', 'deleteNode', 'addNode']), ...mapMutations(['copyNode', 'pasteNode', 'deleteNode', 'addNode']),
...mapActions(['exportView', 'importView']) ...mapActions(['exportView', 'importView', 'importPsd'])
} }
}; };
</script> </script>
......
...@@ -64,8 +64,10 @@ ...@@ -64,8 +64,10 @@
}, },
normalProcessTree() { normalProcessTree() {
const tree = this.builtinProcessTree; const tree = this.builtinProcessTree;
const group = tree.find(item => item.name === 'custom'); const customGroup = tree.find(item => item.name === 'custom');
group.children = this.$store.state.behavior.data.processes; customGroup.children = this.$store.state.behavior.data.processes;
const triggerGroup = tree.find(item => item.name === 'trigger');
triggerGroup.children = this.$store.state.behavior.data.processes;
return tree; return tree;
}, },
...mapState({ ...mapState({
...@@ -74,7 +76,7 @@ ...@@ -74,7 +76,7 @@
}), }),
...mapGetters([ ...mapGetters([
'prefabProcessTree', 'prefabProcessTree',
'builtinProcessTree' 'builtinProcessTree',
]), ]),
}, },
methods: { methods: {
...@@ -112,9 +114,13 @@ ...@@ -112,9 +114,13 @@
this.$refs.metaEditorDialog.edit(meta); this.$refs.metaEditorDialog.edit(meta);
}, },
onDeleteMeta(meta) { onDeleteMeta(meta) {
const inUse = this.$store.getters.metaInUse(meta.id); const metaInUse = this.$store.getters.metaInUse(meta.id);
if (inUse) { if (metaInUse.length > 0) {
this.$alert(this.$t('Meta is in use, can not delete'), this.$t('Alert')) console.log(metaInUse);
let metas = metaInUse.map(meta=>`<b>→ ${meta.name}</b>`).join('<br>');
this.$alert(metas, this.$t('Meta is in use, can not delete'),{
dangerouslyUseHTMLString: true,
})
.catch((e) => { .catch((e) => {
}); });
} else { } else {
......
<template> <template>
<foreignObject :x="data.design.x" :y="data.design.y" :width="width" :height="height"> <foreignObject :x="data.design.x" :y="data.design.y" :width="width" :height="height">
<div ref="node" :class="{active: active}" class="node" style="margin-top: 20px;" @mousedown="onMouseDown" @mouseenter="onMouseEnter" <div ref="node" :class="{active: active}" class="node" style="margin-top: 20px;" @mousedown="onMouseDown"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave" @click="onClick" @dblclick="onDblclick"> @mouseleave="onMouseLeave" @click="onClick" @dblclick="onDblclick">
<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"/> <el-link icon="el-icon-document-copy" :underline="false" @mousedown.stop.prevent @click.stop="onClickCopy"/>
</div> </div>
<div class="header"> <div class="header">
...@@ -13,6 +15,14 @@ ...@@ -13,6 +15,14 @@
</div> </div>
<div class="body"> <div class="body">
<div v-if="meta.isDivider"> <div v-if="meta.isDivider">
<el-select v-model="meta.dividerType" size="mini" placeholder="选择类型">
<el-option
v-for="(item, key) in dividerTypes"
:key="key"
:label="item"
:value="key">
</el-option>
</el-select>
<el-button size="mini" icon="el-icon-plus" circle @click="outputPointModify('add')"></el-button> <el-button size="mini" icon="el-icon-plus" circle @click="outputPointModify('add')"></el-button>
<el-button size="mini" icon="el-icon-minus" circle @click="outputPointModify('remove')"></el-button> <el-button size="mini" icon="el-icon-minus" circle @click="outputPointModify('remove')"></el-button>
</div> </div>
...@@ -53,10 +63,10 @@ ...@@ -53,10 +63,10 @@
</template> </template>
<script> <script>
import {mapState} from "vuex"; import {mapState, mapGetters} from "vuex";
import DockPin from "./DockPin"; import DockPin from "./DockPin";
import events from "../../../../global-events"; import events from "../../../../global-events";
import {dynamicIconMapping} from "../../../../utils"; import {dynamicIconMapping, nodeScheme} from "../../../../utils";
export default { export default {
name: "ProcessNode", name: "ProcessNode",
...@@ -71,6 +81,7 @@ ...@@ -71,6 +81,7 @@
inputMeta, inputMeta,
active: false, active: false,
dynamicIconMapping, dynamicIconMapping,
dividerTypes: this.$t('dividerTypes'),
} }
}, },
mounted() { mounted() {
...@@ -92,6 +103,9 @@ ...@@ -92,6 +103,9 @@
drawState: state => state.behavior.drawState, drawState: state => state.behavior.drawState,
editable: state => state.behavior.editable, editable: state => state.behavior.editable,
}), }),
...mapGetters([
'behavior_searchViewNode'
]),
}, },
watch: { watch: {
process(v) { process(v) {
...@@ -107,13 +121,19 @@ ...@@ -107,13 +121,19 @@
let asset = this.$store.getters.behavior_getAssetByUUID(data.props[key]); let asset = this.$store.getters.behavior_getAssetByUUID(data.props[key]);
return asset.name; return asset.name;
} }
} else if (param.type === 'node') {
let uuid = data.props[key] ? data.props[key].replace(nodeScheme, '') : null;
let searchResult = this.behavior_searchViewNode(uuid);
if (searchResult) {
return searchResult.node.name;
}
} else { } else {
return data.props[key] || param.default; return data.props.hasOwnProperty(key) ? data.props[key] : param.default;
} }
return ''; return '';
}, },
objToString(value){ objToString(value) {
return typeof value === 'object' ? '' : (value || ''); return typeof value === 'object' ? '' : (value || '');
}, },
prepare() { prepare() {
......
...@@ -108,16 +108,16 @@ ...@@ -108,16 +108,16 @@
<!-- <code-editor v-if="meta" v-model="meta.script" /> --> <!-- <code-editor v-if="meta" v-model="meta.script" /> -->
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div class="button-bar"> <div>
<el-button-group style="margin-right: 20px;"> <el-button-group style="margin-right: 20px;">
<el-button size="mini" plain @click="copyMeta">CopyMeta</el-button> <el-button size="mini" plain @click="copyMeta">CopyMeta</el-button>
<el-popover> <el-popover>
<div ref="pasteBoard" @paste="onPaste">Click and Ctrl+V</div> <div ref="pasteBoard" @paste="onPaste">Click and Ctrl+V</div>
<el-button size="mini" slot="reference" plain @click="pasteMeta" <el-button size="mini" slot="reference" plain @click="pasteMeta">PasteMeta</el-button>
>PasteMeta</el-button
>
</el-popover> </el-popover>
</el-button-group> </el-button-group>
</div>
<div class="button-bar">
<el-button size="mini" plain @click="cancel">{{ <el-button size="mini" plain @click="cancel">{{
$t("Cancel") $t("Cancel")
}}</el-button> }}</el-button>
...@@ -140,15 +140,7 @@ import events from "../../../global-events"; ...@@ -140,15 +140,7 @@ import events from "../../../global-events";
import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator"; import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator";
import CodeEditor from "./CodeEditor"; import CodeEditor from "./CodeEditor";
const exposeVariables = [ const exposeVariables = ["args", "props", "target", "global", "vm", "engine", 'scope'];
"args",
"props",
"target",
"global",
"vm",
"engine",
"scope"
];
export default { export default {
name: "MetaEditorDialog", name: "MetaEditorDialog",
...@@ -156,9 +148,7 @@ export default { ...@@ -156,9 +148,7 @@ export default {
CodeEditor, CodeEditor,
CodeSyncIndicator, CodeSyncIndicator,
PropsEditorDialog, PropsEditorDialog,
// ElFormItem,
"monaco-editor": MonacoEditor "monaco-editor": MonacoEditor
//"monaco-editor": MonacoEditor
}, },
data() { data() {
return { return {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
</div> </div>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" plain @click="close">{{$t('Close')}}</el-button> <el-button size="mini" plain @click="close">{{$t('Close')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
......
...@@ -11,14 +11,15 @@ ...@@ -11,14 +11,15 @@
> >
<div slot-scope="{ node, data }" class="process-tree-node"> <div slot-scope="{ node, data }" class="process-tree-node">
<div class="node-name"> <div class="node-name">
<span :class="{'current-node': isCurrentProcess(data)}" :draggable="draggable(data)" @dragstart.stop="dragProcessStart(data, $event)">{{data.name}}</span> <span :class="{'current-node': isCurrentProcess(data)}" :draggable="draggable(data)"
@dragstart.stop="dragProcessStart(data, $event)">{{transName(data, node)}}</span>
</div> </div>
<el-dropdown v-if="nodeMenu(data)" class="more-button" size="mini" trigger="click" <el-dropdown v-if="nodeMenu(data)" class="more-button" size="mini" trigger="click"
@command="(command)=>{onMoreMenu(command, data, node)}"> @command="(command)=>{onMoreMenu(command, data, node)}">
<el-link icon="el-icon-more" :underline="false" @click.stop/> <el-link icon="el-icon-more" :underline="false" @click.stop/>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="desc" >{{$t('Desc')}}</el-dropdown-item> <el-dropdown-item command="desc">{{$t('Desc')}}</el-dropdown-item>
<el-dropdown-item command="edit" v-if="metaEditable(data)" divided>{{$t('Edit')}}</el-dropdown-item> <el-dropdown-item command="edit" v-if="metaEditable(data)" divided>{{$t('Edit')}}</el-dropdown-item>
<el-dropdown-item command="delete" v-if="metaEditable(data)">{{$t('Delete')}}</el-dropdown-item> <el-dropdown-item command="delete" v-if="metaEditable(data)">{{$t('Delete')}}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
...@@ -38,7 +39,7 @@ ...@@ -38,7 +39,7 @@
export default { export default {
name: "ProcessList", name: "ProcessList",
props: [ props: [
'data', 'data', 'type',
], ],
data() { data() {
return { return {
...@@ -63,27 +64,34 @@ ...@@ -63,27 +64,34 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
currentProcess(state){ currentProcess(state) {
return state.behavior.currentProcess; return state.behavior.currentProcess;
} }
}), }),
}, },
methods: { methods: {
updateFilter(){ transName(meta, node){
if(this.$refs.tree){ if(node.parent.parent){
return meta.name
}else{
return this.$t('processGroups')[meta.name] || meta.name;
}
},
updateFilter() {
if (this.$refs.tree) {
this.$refs.tree.filter(this.filterText); this.$refs.tree.filter(this.filterText);
} }
}, },
draggable(data) { draggable(data) {
return !data.hasOwnProperty('children') && data.isDivider !== true ; return !data.hasOwnProperty('children') && data.isDivider !== true;
}, },
dragProcessStart(data, event) { dragProcessStart(data, event) {
event.dataTransfer.setData('process', data.id); event.dataTransfer.setData('process', data.id);
}, },
nodeMenu(data){ nodeMenu(data) {
return !data.hasOwnProperty('children') return !data.hasOwnProperty('children')
}, },
metaEditable(data){ metaEditable(data) {
return data.type !== 'builtin' && !data.hasOwnProperty('children') && !editableIds.includes(data.id) && data.isDivider !== true return data.type !== 'builtin' && !data.hasOwnProperty('children') && !editableIds.includes(data.id) && data.isDivider !== true
}, },
onMoreMenu(command, data, node) { onMoreMenu(command, data, node) {
...@@ -104,14 +112,16 @@ ...@@ -104,14 +112,16 @@
break; break;
} }
}, },
filterNodeMethod(value, data) { filterNodeMethod(value, data, node) {
let filterFrom = data.from && node.parent.data.from ? data.from === node.parent.data.from : true;
let filterDivider = data.isDivider !== true; let filterDivider = data.isDivider !== true;
if (!value) return filterDivider;
return filterDivider && !data.hasOwnProperty('children') && data.name.toUpperCase().indexOf(value.toUpperCase()) >= 0; if (!value) return filterDivider && filterFrom;
return filterDivider && filterFrom && !data.hasOwnProperty('children') && data.name.toUpperCase().indexOf(value.toUpperCase()) >= 0;
}, },
isCurrentProcess(data){ isCurrentProcess(data) {
let yes= this.currentProcess && this.currentProcess.meta && data.id && data.id === this.currentProcess.meta.id; let yes = this.currentProcess && this.currentProcess.meta && data.id && data.id === this.currentProcess.meta.id;
if(yes){ if (yes) {
console.log(); console.log();
} }
return yes; return yes;
......
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
:placeholder="process.meta.name" size="mini"> :placeholder="process.meta.name" size="mini">
<template slot="prepend">{{$t('Name')}}</template> <template slot="prepend">{{$t('Name')}}</template>
</el-input> </el-input>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="scrollbar-view">
view-class="scrollbar-view">
<props-editor ref="propsEditor" :editable="editable" :linkable="true" :data="process.data" :meta="process.meta"/> <props-editor ref="propsEditor" :editable="editable" :linkable="true" :data="process.data" :meta="process.meta"/>
</el-scrollbar> </el-scrollbar>
<div class="inside-code">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="scrollbar-view">
<!--<el-input class="code-body" type="textarea" size="mini" readonly v-model="process.meta.script" resize="none"/>-->
<pre class="code-body">{{process.meta.script}}</pre>
</el-scrollbar>
</div>
</div> </div>
</template> </template>
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
</el-scrollbar> </el-scrollbar>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div></div>
<div class="button-bar"> <div class="button-bar">
<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">{{$t('Save')}}</el-button>
......
<template> <template>
<div id="container"></div> <div id="container"></div>
</template> </template>
<script> <script>
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
export default {
name: "MonacoEditor",
props: {
options: Object,
code: String
},
async mounted() {
const { options, code } = this;
const res = await fetch(
"http://yun.duiba.com.cn/editor/zeroing/types/types.d.ts"
);
const types = await res.text();
const defaultConfig = { const typesUrl = [
language: "javascript", "http://yun.duiba.com.cn/editor/zeroing/types/types.d.ts",
value: "", "http://yun.duiba.com.cn/editor/zeroing/types/process-context.v4.d.ts",
minimap: { ];
enabled: false
}
};
// compiler options export default {
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ name: "MonacoEditor",
target: monaco.languages.typescript.ScriptTarget.ES6, props: {
allowNonTsExtensions: true, options: Object,
allowJs: true code: String
}); },
// extra libraries async mounted() {
monaco.languages.typescript.javascriptDefaults.addExtraLib( const {options, code} = this;
[types].join("\n") const types = await Promise.all(typesUrl.map(async url => {
); const res = await fetch(url);
const config = Object.assign({}, defaultConfig, options, { value: code }); return res.text();
this.editor = monaco.editor.create( }));
document.getElementById("container"),
config const defaultConfig = {
); language: "javascript",
}, value: "",
destroyed() { minimap: {
this.editor.dispose(); enabled: false
} }
}; };
// compiler options
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES6,
allowNonTsExtensions: true,
allowJs: true
});
// extra libraries
monaco.languages.typescript.javascriptDefaults.addExtraLib(
types.join("\n")
);
const config = Object.assign({}, defaultConfig, options, {value: code});
this.editor = monaco.editor.create(
document.getElementById("container"),
config
);
},
destroyed() {
this.editor.dispose();
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
#container { #container {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
</style> </style>
...@@ -4,8 +4,11 @@ ...@@ -4,8 +4,11 @@
:append-to-body="true" custom-class="flex-dialog 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> <div></div>
<el-button size="mini" type="primary" @click="onSave(false)">{{$t('Save And Close')}}</el-button> <div>
<el-button size="mini" @click="onSave(true)">{{$t('Save And Preview')}}</el-button>
<el-button size="mini" type="primary" @click="onSave(false)">{{$t('Save And Close')}}</el-button>
</div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
......
<template> <template>
<el-dialog :title="$t('CodeSyncServe')" width="70%" :visible.sync="visible" <el-dialog :title="$t('CodeSyncServe')" width="70%" :visible.sync="visible"
:append-to-body="true" :append-to-body="true"
custom-class="" custom-class="code-sync-serve-dialog"
> >
<div> <div>
<el-form label-position="right" label-width="50px" size="mini"> <el-form label-position="right" label-width="100px" size="mini">
<el-form-item :label="$t('Auto launch')">
<el-switch v-model="config.autoLaunch"/>
</el-form-item>
<el-form-item label="IP"> <el-form-item label="IP">
<el-input v-model="config.ip"/> <el-input v-model="config.ip"/>
</el-form-item> </el-form-item>
...@@ -15,7 +18,8 @@ ...@@ -15,7 +18,8 @@
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div> <div>
<el-switch :value="enabled" @input="onEnableServer"/>
<span class="status">{{$t(status)}}</span>
</div> </div>
<div> <div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button> <el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
...@@ -29,7 +33,8 @@ ...@@ -29,7 +33,8 @@
import {mapMutations, mapState} from 'vuex' import {mapMutations, mapState} from 'vuex'
import EnabledSetter from "../components/EnabledSetter"; import EnabledSetter from "../components/EnabledSetter";
import {clonePureObj} from "../../../utils"; import {clonePureObj} from "../../../utils";
import {startCodeSyncServe} from "../../../code-sync-serve"; import {codeSyncServeEnabled, startCodeSyncServe, stopCodeSyncServe} from "../../../code-sync-serve";
import events from '../../../global-events';
export default { export default {
name: "CodeSyncServeDialog", name: "CodeSyncServeDialog",
...@@ -38,12 +43,19 @@ ...@@ -38,12 +43,19 @@
return { return {
visible: false, visible: false,
config: {}, config: {},
enabled: codeSyncServeEnabled,
} }
}, },
mounted() { mounted() {
events.$on('code-sync-status', this.onStatusChange);
},
destroyed() {
events.$off('code-sync-status', this.onStatusChange);
}, },
computed: { computed: {
status() {
return this.enabled ? 'Running status' : 'Stop status';
},
...mapState({ ...mapState({
codeSyncServeConfig(state) { codeSyncServeConfig(state) {
return state.env.codeSyncServeConfig; return state.env.codeSyncServeConfig;
...@@ -57,12 +69,22 @@ ...@@ -57,12 +69,22 @@
}, },
onSave() { onSave() {
this.saveCodeSyncServeConfig(this.config); this.saveCodeSyncServeConfig(this.config);
startCodeSyncServe(this.config);
this.visible = false; this.visible = false;
}, },
onClose() { onClose() {
this.visible = false; this.visible = false;
}, },
onStatusChange(v) {
this.enabled = v;
},
onEnableServer(v) {
if (v) {
startCodeSyncServe(this.config);
} else {
stopCodeSyncServe();
}
this.enabled = v;
},
...mapMutations([ ...mapMutations([
'saveCodeSyncServeConfig', 'saveCodeSyncServeConfig',
]), ]),
......
<template> <template>
<el-dialog <el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @opened="onOpen"
:title="$t('Project details')" :close-on-click-modal="false"
width="70%" :append-to-body="true"
:visible.sync="visible" :show-close="false"
@opened="onOpen" fullscreen
:close-on-click-modal="false" custom-class="flex-dialog details-dialog"
:append-to-body="true" >
:show-close="false" <el-tabs v-model="activeName" class="tabs">
fullscreen <el-tab-pane :label="$t('Project')" name="project">
custom-class="flex-dialog details-dialog" <project-editor ref="projectEditor"/>
> </el-tab-pane>
<el-tabs v-model="activeName" class="tabs"> <el-tab-pane :label="$t('Env constant')" name="env">
<el-tab-pane :label="$t('Project')" name="project"> <env-editor ref="envEditor"/>
<project-editor ref="projectEditor" /> </el-tab-pane>
</el-tab-pane> <el-tab-pane :label="$t('Data mapping')" name="data-mapping">
<el-tab-pane :label="$t('Env constant')" name="env"> <data-mapping-editor ref="dataMappingEditor"/>
<env-editor ref="envEditor" /> </el-tab-pane>
</el-tab-pane> <el-tab-pane :label="$t('Custom module')" name="custom">
<el-tab-pane :label="$t('Data mapping')" name="data-mapping"> <custom-module-editor ref="customModuleEditor"/>
<data-mapping-editor ref="dataMappingEditor" /> </el-tab-pane>
</el-tab-pane> <el-tab-pane :label="$t('Projectx config')" name="projectx">
<el-tab-pane :label="$t('Custom module')" name="custom"> <projectx-config ref="projectxConfig" />
<custom-module-editor ref="customModuleEditor" /> </el-tab-pane>
</el-tab-pane> </el-tabs>
<el-tab-pane :label="$t('Projectx config')" name="projectx"> <div slot="footer" class="dialog-footer">
<projectx-config ref="projectxConfig" /> <div></div>
</el-tab-pane> <div>
</el-tabs> <el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<div slot="footer" class="dialog-footer"> <el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
<el-button size="mini" @click="onClose">{{ $t("Close") }}</el-button> </div>
<el-button size="mini" @click="onSave" type="primary">{{ </div>
$t("Save") </el-dialog>
}}</el-button>
</div>
</el-dialog>
</template> </template>
<script> <script>
import { mapMutations } from "vuex"; 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 CustomModuleEditor from "./editors/CustomModuleEditor"; import CustomModuleEditor from "./editors/CustomModuleEditor";
import DataMappingEditor from "./editors/DataMappingEditor"; import DataMappingEditor from "./editors/DataMappingEditor";
import ProjectxConfig from "./editors/ProjectxConfig"; import ProjectxConfig from "./editors/ProjectxConfig";
const refs = [ const refs = [
"projectEditor", 'projectEditor',
"envEditor", 'envEditor',
"dataMappingEditor", 'dataMappingEditor',
"customModuleEditor", 'customModuleEditor',
"projectxConfig" "projectxConfig"
]; ];
export default { export default {
name: "DetailsDialog", name: "DetailsDialog",
components: { components: {DataMappingEditor, CustomModuleEditor, EnvEditor, ProjectEditor,
DataMappingEditor, ProjectxConfig},
CustomModuleEditor, data() {
EnvEditor, return {
ProjectEditor, visible: false,
ProjectxConfig activeName: 'project',
}, }
data() { },
return { methods: {
visible: false, show() {
activeName: "project" this.visible = true;
}; },
}, onSave() {
methods: { for (let ref of refs) {
show() { this.$refs[ref].save();
this.visible = true; }
}, this.visible = false;
onSave() { this.modifyProjectDetails();
for (let ref of refs) { },
this.$refs[ref].save(); onClose() {
} this.visible = false;
this.visible = false; },
this.modifyProjectDetails(); onOpen() {
}, for (let ref of refs) {
onClose() { this.$refs[ref].edit();
this.visible = false; }
}, },
onOpen() { ...mapMutations([
for (let ref of refs) { 'modifyProjectDetails',
this.$refs[ref].edit(); ]),
} }
}, }
...mapMutations(["modifyProjectDetails"])
}
};
</script> </script>
<style scoped></style> <style scoped>
</style>
\ No newline at end of file
<template> <template>
<el-dialog <el-dialog
:title="$t('Project details')" :title="$t('Project details')"
width="70%" width="70%"
:visible.sync="visible" :visible.sync="visible"
@open="onOpen" @open="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"
custom-class="details-dialog" custom-class="details-dialog"
> >
<div> <div>
<p>{{ $t("Pack project successfully") }}</p> <p>{{ $t("Pack project successfully") }}</p>
<el-collapse> <el-collapse>
<el-collapse-item :title="$t('Check template code')" name="1"> <el-collapse-item :title="$t('Check template code')" name="1">
<el-input <el-input
v-if="packResult" v-if="packResult"
type="textarea" type="textarea"
readonly readonly
v-model="packResult.tpl" v-model="packResult.tpl"
:rows="10" :rows="10"
/> />
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<el-checkbox v-model="isSaveProjecx" style="margin: 20px 0" <el-checkbox v-model="isSaveProjecx" style="margin: 20px 0">{{$t('Save template to projectx')}}</el-checkbox>
>是否保存皮肤到星速台</el-checkbox <projectx-options
> v-if="isSaveProjecx"
<projectx-options :tpl="packResult.tpl"
v-if="isSaveProjecx" ></projectx-options>
:tpl="packResult.tpl" </div>
></projectx-options> <div slot="footer" class="dialog-footer">
</div> <div></div>
<div slot="footer" class="dialog-footer"> <div>
<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="copy"> <el-button size="mini" @click="copy">
{{ $t("Copy template to clipboard") }} {{ $t("Copy template to clipboard") }}
</el-button> </el-button>
<el-button size="mini" type="primary" @click="openInNewTab"> <el-button size="mini" type="primary" @click="openInNewTab">
{{ $t("Open in new tab") }} {{ $t("Open in new tab") }}
</el-button> </el-button>
</div> </div>
</el-dialog> </div>
</el-dialog>
</template> </template>
<script> <script>
import copy from "copy-to-clipboard"; import copy from 'copy-to-clipboard'
import ProjectxOptions from "./ProjectxOptions"; import ProjectxOptions from "./ProjectxOptions";
import { openPreview } from "../../../utils"; import {openPreview} from "../../../utils";
export default { export default {
name: "PackResultDialog", name: "PackResultDialog",
components: { components: {"projectx-options": ProjectxOptions},
"projectx-options": ProjectxOptions data() {
}, return {
data() { visible: false,
return { isSaveProjecx: false,
visible: false, activeName: 'project',
isSaveProjecx: false, packResult: null,
activeName: "project", }
packResult: null },
}; methods: {
}, show(packResult) {
methods: { this.packResult = packResult;
show(packResult) { this.visible = true;
this.packResult = packResult; },
this.visible = true; onClose() {
}, this.visible = false;
onClose() { },
this.visible = false; openInNewTab() {
}, this.visible = false;
openInNewTab() {
this.visible = false;
openPreview(this.packResult); openPreview(this.packResult);
}, },
copy() { copy() {
this.visible = false; this.visible = false;
copy(this.packResult.tpl); copy(this.packResult.tpl);
}, },
onOpen() {} onOpen() {
}
}; },
}
}
</script> </script>
<style scoped></style> <style scoped>
</style>
\ No newline at end of file
...@@ -2,27 +2,27 @@ ...@@ -2,27 +2,27 @@
<div class="config"> <div class="config">
<el-select <el-select
size="small" size="small"
v-model="currentEnv" v-model="env"
placeholder="请选择环境" placeholder="请选择环境"
@change="changeCurrentEnv" @change="changeenv"
> >
<el-option <el-option
v-for="item in env" v-for="(item, key) in pxEnvs"
:key="item.value" :key="key"
:label="item.name" :label="item"
:value="item.value" :value="key"
></el-option> ></el-option>
</el-select> </el-select>
<el-select size="small" v-model="currentTypes" placeholder="是否新增"> <el-select size="small" v-model="operate" placeholder="是否新增">
<el-option <el-option
v-for="item in types" v-for="(item, key) in tplOperates"
:key="item.value" :key="key"
:label="item.name" :label="item"
:value="item.value" :value="key"
></el-option> ></el-option>
</el-select> </el-select>
<el-select <el-select
v-if="currentTypes !== '1'" v-if="operate !== 0"
size="small" size="small"
v-model="skinId" v-model="skinId"
placeholder="选择skinID" placeholder="选择skinID"
...@@ -31,17 +31,17 @@ ...@@ -31,17 +31,17 @@
<el-option <el-option
v-for="item in skinList" v-for="item in skinList"
:key="item.id" :key="item.id"
:label="`${item.type !== '1' ? item.name : '首页'}(${item.id})`" :label="`${item.type !== 0 ? item.name : '首页'}(${item.id})`"
:value="item.id" :value="item.id"
></el-option> ></el-option>
</el-select> </el-select>
<div v-if="currentTypes === '1'"> <div v-if="operate === 0">
<el-select size="small" v-model="currentHtmlType" placeholder> <el-select size="small" v-model="tplType" placeholder>
<el-option <el-option
v-for="item in htmlType" v-for="(item, key) in tplTypes"
:key="item.value" :key="key"
:label="item.label" :label="item"
:value="item.value" :value="key"
></el-option> ></el-option>
</el-select> </el-select>
<el-input <el-input
...@@ -76,24 +76,15 @@ export default { ...@@ -76,24 +76,15 @@ export default {
}, },
data() { data() {
return { return {
env: [ pxEnvs: this.$t("pxEnvs"),
{ value: "dev", name: "开发环境" }, tplOperates: this.$t("tplOperates"),
{ value: "test", name: "测试环境" }, tplTypes: this.$t("tplTypes"),
{ value: "prod", name: "线上环境" }
], env: "dev",
currentEnv: "dev", operate: 1,
types: [ tplType: 0,
{ value: "1", name: "新增" },
{ value: "2", name: "修改" },
{ value: "3", name: "删除" }
],
currentTypes: "2",
skinId: "", skinId: "",
htmlType: [
{ value: "1", label: "首页" },
{ value: "2", label: "其他" }
],
currentHtmlType: "1",
skinList: [], skinList: [],
projectId: "", projectId: "",
name: "" name: ""
...@@ -104,40 +95,40 @@ export default { ...@@ -104,40 +95,40 @@ export default {
}, },
methods: { methods: {
getProjectId(env) { getProjectId(env) {
const { projectxConfig } = this.project.data.options; const { pxEnv } = this.project.data.options;
this.projectId = projectxConfig[env]; this.projectId = pxEnv[env];
return this.projectId; return this.projectId;
}, },
changeCurrentEnv(e) { async changeenv(e) {
if (e === "test") { if (e === "test") {
this.getTicket(getTestEnvTicket); await this.getTicket(getTestEnvTicket);
} else if (e === "prod") { } else if (e === "prod") {
this.getTicket(getProdTicket, "prod_ticket"); await this.getTicket(getProdTicket, "prod_ticket");
} }
const projectId = this.getProjectId(e); const projectId = this.getProjectId(e);
this.skinId = ""; this.skinId = "";
this.getSkinsList(projectId); this.getSkinsList(projectId);
}, },
async getSkinsList(projectId) { async getSkinsList(projectId) {
const { currentEnv } = this; const { env } = this;
if (!projectId) { if (!projectId) {
this.$message({ this.$message({
message: `请先配置${currentEnv}环境下的projectId`, message: `请先配置${env}环境下的projectId`,
type: "error" type: "error"
}); });
return; return;
} }
try { try {
const data = await getProjectSkins(projectId, currentEnv); const data = await getProjectSkins(projectId, env);
if (data.success !== false) { if (data.success !== false) {
this.skinList = data; this.skinList = data;
} else { } else {
// 如果是测试环境,ticket过期,则重新获取ticket // 如果是测试环境,ticket过期,则重新获取ticket
if (currentEnv === "test" && data.notLogin) { if (env === "test" && data.notLogin) {
localStorage.setItem("ticket", ""); localStorage.setItem("ticket", "");
await this.getTicket(getTestEnvTicket); await this.getTicket(getTestEnvTicket);
this.getSkinsList(this.projectId); this.getSkinsList(this.projectId);
} else if (currentEnv === "prod" && data.notLogin) { } else if (env === "prod" && data.notLogin) {
// 如果是线上环境,则发送钉钉消息 // 如果是线上环境,则发送钉钉消息
sendDingTalk(); sendDingTalk();
localStorage.setItem("prod_ticket", ""); localStorage.setItem("prod_ticket", "");
...@@ -168,21 +159,21 @@ export default { ...@@ -168,21 +159,21 @@ export default {
}, },
async saveSkins() { async saveSkins() {
const { const {
currentEnv, env,
skinId, skinId,
currentHtmlType, tplType,
currentTypes, operate,
projectId, projectId,
tpl, tpl,
name, name,
skinList skinList
} = this; } = this;
if (currentTypes === "2" && !skinId) { if (operate === 1 && !skinId) {
this.$message({ message: "请选择修改的皮肤", type: "warning" }); this.$message({ message: "请选择修改的皮肤", type: "warning" });
return; return;
} }
if (currentTypes === "1") { if (operate === 0) {
if (this.hasIndex() && currentHtmlType === "1") { if (this.hasIndex() && tplType === 0) {
this.$message({ message: "已存在首页", type: "warning" }); this.$message({ message: "已存在首页", type: "warning" });
return; return;
} else if (!name) { } else if (!name) {
...@@ -192,12 +183,12 @@ export default { ...@@ -192,12 +183,12 @@ export default {
} }
const data = { const data = {
projectId, projectId,
type: currentTypes, type: (operate + 1).toString(),
currentHtmlType, currentHtmlType: (tplType + 1).toString(),
skinId, skinId,
tpl, tpl,
name, name,
env: currentEnv env: env
}; };
const { ret } = await saveSkins(data); const { ret } = await saveSkins(data);
if (ret.success !== false) { if (ret.success !== false) {
...@@ -209,23 +200,29 @@ export default { ...@@ -209,23 +200,29 @@ export default {
this.$message({ message: ret.message, type: "error" }); this.$message({ message: ret.message, type: "error" });
} }
// 新增皮肤则重新获取皮肤列表 // 新增皮肤则重新获取皮肤列表
if (currentTypes !== "2") { if (operate !== 1) {
// 2为修改,修改不需重新获取列表 // 2为修改,修改不需重新获取列表
this.getSkinsList(projectId); this.getSkinsList(projectId);
} else if (currentTypes !== "3") { } else if (operate !== 2) {
this.name = ""; this.name = "";
} }
}, },
/** 获取访问链接 */ /** 获取访问链接 */
getUrl() { getUrl() {
const { currentHtmlType, currentEnv, skinId, projectId } = this; const { tplType, env, skinId, projectId, skinList } = this;
let type = 1;
skinList.forEach(skin => {
if (skin.id === skinId) {
type = skin.type;
}
});
const mapping = { const mapping = {
dev: "activity.m.duibadev.com.cn", dev: "activity.m.duibadev.com.cn",
test: "activity.m.duibatest.com.cn", test: "activity.m.duibatest.com.cn",
prod: "https://activity.m.duiba.com.cn" prod: "https://activity.m.duiba.com.cn"
}; };
const url = `${mapping[currentEnv]}/projectx/${projectId}/${ const url = `${mapping[env]}/projectx/${projectId}/${
currentHtmlType === "1" ? "index" : skinId type === "1" ? "index" : skinId
}.html`; }.html`;
copy(url); copy(url);
this.$message({ this.$message({
...@@ -237,14 +234,13 @@ export default { ...@@ -237,14 +234,13 @@ export default {
let ticket = localStorage.getItem(name); let ticket = localStorage.getItem(name);
if (!ticket) { if (!ticket) {
ticket = await fn(); ticket = await fn();
console.log(ticket, "ticketticket");
localStorage.setItem(name, ticket); localStorage.setItem(name, ticket);
} }
} }
}, },
async mounted() { async mounted() {
const { projectxConfig } = this.project.data.options; const { projectxConfig } = this.project.data.options;
const projectId = projectxConfig[this.currentEnv]; const projectId = projectxConfig[this.env];
this.projectId = projectId; this.projectId = projectId;
this.getSkinsList(projectId); this.getSkinsList(projectId);
}, },
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<asset-list @click-item="onClickItem"/> <asset-list @click-item="onClickItem"/>
</el-scrollbar> </el-scrollbar>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button> <el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
{{item.ext}} {{item.ext}}
</span> </span>
<div class="thumbnail"> <div class="thumbnail">
<img class="alpha-image-background" v-if="item.ext === '.png'" :src="item.url"> <img class="alpha-image-background" v-if="showThumbnail(item.ext)" :src="item.url">
</div> </div>
<el-input size="mini" v-model="item.url" readonly/> <el-input size="mini" v-model="item.url" readonly/>
</div> </div>
...@@ -40,8 +40,11 @@ ...@@ -40,8 +40,11 @@
</div> </div>
</el-scrollbar> </el-scrollbar>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button> <div></div>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button> <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> </div>
<select-asset-dialog ref="selectAssetDialog" @select="onSelectReplace"/> <select-asset-dialog ref="selectAssetDialog" @select="onSelectReplace"/>
</el-dialog> </el-dialog>
......
...@@ -17,6 +17,28 @@ ...@@ -17,6 +17,28 @@
:label="$t('Name')" :label="$t('Name')"
width="200"> width="200">
</el-table-column> </el-table-column>
<el-table-column
prop="desc"
:label="$t('Desc')"
width="60">
<template slot-scope="scope">
<el-popover
:title="scope.row.meta.name"
width="200"
trigger="click"
:content="scope.row.meta.desc">
<el-button slot="reference" size="mini" icon="el-icon-document" circle type="primary" plain/>
</el-popover>
</template>
</el-table-column>
<el-table-column
prop="events"
:label="$t('Events')"
width="60">
<template slot-scope="scope">
<el-button size="mini" icon="el-icon-guide" circle type="primary" plain @click="showEvents(scope.row)"/>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="assets" prop="assets"
:label="$t('Assets')" :label="$t('Assets')"
...@@ -45,6 +67,7 @@ ...@@ -45,6 +67,7 @@
</el-table-column> </el-table-column>
<asset-mapping-editor-dialog ref="assetMappingEditorDialog" @save="onSaveAssetMapping"/> <asset-mapping-editor-dialog ref="assetMappingEditorDialog" @save="onSaveAssetMapping"/>
<props-editor-dialog ref="propsEditorDialog"/> <props-editor-dialog ref="propsEditorDialog"/>
<events-details-dialog ref="eventsDetailsDialog"/>
</el-table> </el-table>
</template> </template>
...@@ -53,10 +76,11 @@ ...@@ -53,10 +76,11 @@
import {clonePureObj} from "../../../../utils"; import {clonePureObj} from "../../../../utils";
import AssetMappingEditorDialog from "./AssetMappingEditorDialog"; import AssetMappingEditorDialog from "./AssetMappingEditorDialog";
import PropsEditorDialog from "./CustomModuleEditor/PropsEditorDialog"; import PropsEditorDialog from "./CustomModuleEditor/PropsEditorDialog";
import EventsDetailsDialog from "./CustomModuleEditor/EventsDetailsDialog";
export default { export default {
name: "CustomModuleEditor", name: "CustomModuleEditor",
components: {PropsEditorDialog, AssetMappingEditorDialog}, components: {EventsDetailsDialog, PropsEditorDialog, AssetMappingEditorDialog},
data() { data() {
return { return {
visible: false, visible: false,
...@@ -112,6 +136,9 @@ ...@@ -112,6 +136,9 @@
onSaveAssetMapping(mid, assetMapping) { onSaveAssetMapping(mid, assetMapping) {
this.customMetas.find(item => item.id === mid).assetMapping = assetMapping; this.customMetas.find(item => item.id === mid).assetMapping = assetMapping;
}, },
showEvents(item){
this.$refs.eventsDetailsDialog.show(item.meta);
},
...mapMutations([ ...mapMutations([
'modifyCustoms', 'modifyCustoms',
]), ]),
......
<template>
<el-dialog :title="$t('Events details')" width="70%" :visible.sync="visible"
:close-on-click-modal="false"
:append-to-body="true"
custom-class="events-details-dialog"
>
<el-scrollbar v-if="meta" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view">
<el-collapse class="collapse">
<el-collapse-item v-for="(group, groupName) in meta.events" :key="groupName" :title="$t('eventGroup')[groupName]" :name="groupName">
<el-collapse-item class="group" v-for="(item, key) in group" :key="key" :title="key + (item.alias ? ` (${item.alias})` : '')" :name="key">
<div class="data-item" v-for="(alias, field) of item.data">
<el-tag size="small" type="primary">{{field}}</el-tag>
<el-tag size="small" type="success">{{alias}}</el-tag>
</div>
</el-collapse-item>
</el-collapse-item>
</el-collapse>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: "EventsDetailsDialog",
data() {
return {
visible: false,
meta: null,
}
},
methods: {
show(meta) {
this.meta = meta;
this.visible = true;
},
onClose() {
this.visible = false;
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -3,15 +3,19 @@ ...@@ -3,15 +3,19 @@
:close-on-click-modal="false" :close-on-click-modal="false"
:append-to-body="true" :append-to-body="true"
:show-close="false" :show-close="false"
custom-class="props-editor-dialog"
> >
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" <el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"
view-class="scrollbar-view"> view-class="scrollbar-view">
<props-editor v-if="data" ref="propsEditor" :data="data" :meta="meta" :linkable="false"/> <props-editor v-if="data" ref="propsEditor" :data="data" :meta="meta" label-width="180px" :linkable="false"/>
</el-scrollbar> </el-scrollbar>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button> <div></div>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button> <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> </div>
</el-dialog> </el-dialog>
</template> </template>
......
<template> <template>
<div> <div>
<div v-for="(item, index) in envConfig" :key="index"> <div v-for="(item, key) in pxEnvs" :key="key">
<div class="list"> <div class="list">
<span>{{ item.name }}</span> <span>{{ item }}</span>
<el-icon class="el-icon-connection" /> <el-icon class="el-icon-connection" />
<el-input <el-input
size="small" size="small"
v-model="envs[item.key]" v-model="editData[key]"
:placeholder="`请输入${item.name}星速台项目ID`" :placeholder="$t('Input projectx id', {envName: item})"
></el-input> ></el-input>
</div> </div>
</div> </div>
...@@ -20,12 +20,8 @@ export default { ...@@ -20,12 +20,8 @@ export default {
name: "ProjectxConfig", name: "ProjectxConfig",
data() { data() {
return { return {
envConfig: [ pxEnvs: this.$t('pxEnvs'),
{ key: "dev", name: "开发环境" }, editData: {
{ key: "test", name: "测试环境" },
{ key: "prod", name: "线上环境" }
],
envs: {
dev: "", dev: "",
test: "", test: "",
prod: "" prod: ""
...@@ -33,20 +29,17 @@ export default { ...@@ -33,20 +29,17 @@ export default {
}; };
}, },
computed: { computed: {
...mapState(["project"]) ...mapState({
}, pxEnv: state => state.project.data.options.pxEnv,
created() { }),
this.envs = this.project.data.options.projectxConfig;
}, },
methods: { methods: {
...mapMutations(["modifyOptions"]), ...mapMutations(["modifyProjectx"]),
edit() { edit() {
// this.editData = clonePureObj(this.options); this.editData = clonePureObj(this.pxEnv);
}, },
save() { save() {
const { options } = this.project.data; this.modifyProjectx(this.editData);
Object.assign(options, { projectxConfig: this.envs });
this.modifyOptions(options);
} }
} }
}; };
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</el-table-column> </el-table-column>
<el-table-column <el-table-column
fixed="right" fixed="right"
width="180"> width="100">
<template slot="header" slot-scope="scope"> <template slot="header" slot-scope="scope">
<el-checkbox <el-checkbox
v-model="onlyMine" v-model="onlyMine"
...@@ -30,40 +30,52 @@ ...@@ -30,40 +30,52 @@
</el-checkbox> </el-checkbox>
</template> </template>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <!--<el-button
@click.native.prevent="selectProject(scope.row)" @click.native.prevent="selectProject(scope.row)"
type="primary" icon="el-icon-edit" type="primary" icon="el-icon-edit"
size="small" circle plain> size="mini" plain>
</el-button> {{$t('Edit')}}
<el-button </el-button>-->
<el-dropdown size="small" trigger="click" split-button @click="selectProject(scope.row)"
@command="(command)=>{onMoreMenu(command, scope.row)}">
<i class="el-icon-edit"></i>{{$t('Edit')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit" icon="el-icon-edit">{{$t('Edit')}}</el-dropdown-item>
<el-dropdown-item command="history" icon="el-icon-coin">{{$t('History')}}</el-dropdown-item>
<el-dropdown-item command="duplicate" icon="el-icon-document-copy">{{$t('Duplicate')}}</el-dropdown-item>
<el-dropdown-item command="export" icon="icon-download">{{$t('Export')}}</el-dropdown-item>
<el-dropdown-item command="delete" icon="el-icon-delete" v-if="showDeleteButton">{{$t('Delete')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!--<el-button
@click.native.prevent="selectFromHistory(scope.row)" @click.native.prevent="selectFromHistory(scope.row)"
type="primary" icon="el-icon-coin" icon="el-icon-coin"
size="small" circle plain> size="mini" plain
</el-button> >{{$t('History')}}</el-button>
<el-button <el-button
@click.native.prevent="showDuplicateProjectDialog(scope.row)" @click.native.prevent="showDuplicateProjectDialog(scope.row)"
type="success" icon="el-icon-document-copy" icon="el-icon-document-copy"
size="small" circle plain> size="mini" plain
</el-button> >{{$t('Duplicate')}}</el-button>
<el-button <el-button
@click.native.prevent="exportProject(scope.row)" @click.native.prevent="exportProject(scope.row)"
type="warning" icon="icon-download" icon="icon-download"
size="small" circle plain> size="mini" plain
</el-button> >{{$t('Export')}}</el-button>
<el-button <el-button
v-if="showDeleteButton" 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="mini" circle plain>
</el-button> </el-button>-->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<div class="bottom-bar"> <div class="bottom-bar">
<div> <div>
<el-button type="primary" @click="showCreateProjectDialog()">{{$t('Create')}}</el-button> <el-button size="small" type="primary" @click="showCreateProjectDialog()">{{$t('Create')}}</el-button>
<el-button @click="importProject()">{{$t('Import')}}</el-button> <el-button size="small" @click="importProject()">{{$t('Import')}}</el-button>
</div> </div>
<el-pagination <el-pagination
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
...@@ -142,6 +154,25 @@ ...@@ -142,6 +154,25 @@
) )
}); });
}, },
async onMoreMenu(command, project){
switch (command) {
case 'edit':
this.selectProject(project);
break;
case 'history':
this.selectFromHistory(project);
break;
case 'duplicate':
this.showDuplicateProjectDialog(project);
break;
case 'export':
this.exportProject(project);
break;
case 'delete':
this.onDeleteProject(project);
break;
}
},
async exportProject({id}) { async exportProject({id}) {
const project = await playWaiting(this.fetchProject(id), this.$t('Exporting project')); const project = await playWaiting(this.fetchProject(id), this.$t('Exporting project'));
saveAs(new Blob([JSON.stringify(project)]), project.name + '.json'); saveAs(new Blob([JSON.stringify(project)]), project.name + '.json');
......
...@@ -22,8 +22,11 @@ ...@@ -22,8 +22,11 @@
</el-form-item>--> </el-form-item>-->
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button> <div></div>
<el-button size="mini" type="primary" @click="doCreateProject">{{$t('Create')}}</el-button> <div>
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button>
<el-button size="mini" type="primary" @click="doCreateProject">{{$t('Create')}}</el-button>
</div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
......
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button> <div></div>
<el-button size="mini" type="primary" @click="doCreateProject">{{$t('Create')}}</el-button> <div>
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button>
<el-button size="mini" type="primary" @click="doCreateProject">{{$t('Create')}}</el-button>
</div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
</el-pagination> </el-pagination>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button> <el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button>
</div> </div>
</el-dialog> </el-dialog>
......
<template> <template>
<div class="wrapper"> <div class="wrapper">
<iframe v-if="flag" ref="iframe" class="player-wrapper"></iframe> <iframe v-if="flag" ref="iframe" class="player-wrapper"></iframe>
<!--<el-dropdown class="side-bar" trigger="click" size="mini" @command="onCommand">
<el-button style="opacity: 0.5" circle plain class="micro" icon="el-icon-ice-cream-round" :underline="false"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="refresh">刷新</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>-->
<!--<iframe ref="proxyIframe" id="proxyIframe"
src="http://activity.m.duibadev.com.cn/projectx/p7c3b4fa4/index.html?__proxy_mode1__"
@load="onProxyIframeLoaded"></iframe>-->
<el-button style="opacity: 0.5" circle plain class="side-bar micro" icon="el-icon-refresh" :underline="false"
@click="reload"/>
</div> </div>
</template> </template>
<script> <script>
import {applyMock} from "./Preview/mock-serve"; import {applyMock} from "./Preview/mock-serve";
import db from "../utils/db-storage"; import db from "../utils/db-storage";
import {newScriptEl} from "../utils"; import {newScriptContent, newScriptEl} from "../utils";
export default { export default {
name: "Preview", name: "Preview",
...@@ -16,6 +27,7 @@ ...@@ -16,6 +27,7 @@
return { return {
ts: '', ts: '',
flag: false, flag: false,
proxyReady: true,
} }
}, },
async mounted() { async mounted() {
...@@ -43,6 +55,13 @@ ...@@ -43,6 +55,13 @@
this.buildPage(); this.buildPage();
}, 300); }, 300);
}, },
onCommand(command) {
switch (command) {
case 'refresh':
this.reload();
break;
}
},
onVisibilityChange(e) { onVisibilityChange(e) {
if (!document.hidden) { if (!document.hidden) {
let ts = localStorage.getItem('preview-ts'); let ts = localStorage.getItem('preview-ts');
...@@ -56,6 +75,9 @@ ...@@ -56,6 +75,9 @@
} }
}, },
async buildPage() { async buildPage() {
if (!this.proxyReady) {
return;
}
const {projectID} = this.$route.params; const {projectID} = this.$route.params;
const {data, codes} = await db.get('preview', projectID); const {data, codes} = await db.get('preview', projectID);
...@@ -77,6 +99,7 @@ ...@@ -77,6 +99,7 @@
} }
scripts.push(newScriptEl(url)); scripts.push(newScriptEl(url));
} }
scripts.push(newScriptContent('var proxy_mode=true;'));
this.codes = codes; this.codes = codes;
const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(data)])); const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(data)]));
...@@ -93,8 +116,16 @@ ...@@ -93,8 +116,16 @@
const win = this.$refs.iframe.contentWindow; const win = this.$refs.iframe.contentWindow;
doc.write(tpl); doc.write(tpl);
//win.proxy_window = this.$refs.proxyIframe.contentWindow;
applyMock(projectID, win); applyMock(projectID, win);
}, },
onProxyIframeLoaded() {
this.proxyReady = true;
//this.$refs.proxyIframe.contentWindow.postMessage('hello', '*');
this.buildPage();
},
} }
} }
</script> </script>
...@@ -103,12 +134,20 @@ ...@@ -103,12 +134,20 @@
.wrapper { .wrapper {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex;
flex-direction: column;
}
.side-bar {
position: absolute;
right: 3px;
bottom: 3px;
} }
.player-wrapper { .player-wrapper {
border: 0; border: 0;
width: 100%; flex: 1;
height: 100%;
} }
.mock-button { .mock-button {
...@@ -116,4 +155,12 @@ ...@@ -116,4 +155,12 @@
right: 10px; right: 10px;
bottom: 10px; bottom: 10px;
} }
#proxyIframe {
/*display: none;*/
position: absolute;
top: 0;
width: 100px;
height: 100px;
}
</style> </style>
\ No newline at end of file
...@@ -2271,7 +2271,7 @@ color-string@^1.5.2: ...@@ -2271,7 +2271,7 @@ color-string@^1.5.2:
color-name "^1.0.0" color-name "^1.0.0"
simple-swizzle "^0.2.2" simple-swizzle "^0.2.2"
color@^3.0.0: color@^3.0.0, color@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.npm.taobao.org/color/download/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" resolved "https://registry.npm.taobao.org/color/download/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
integrity sha1-aBSOf4XUGtdknF+oyBBvCY0inhA= integrity sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=
...@@ -5813,6 +5813,11 @@ object-copy@^0.1.0: ...@@ -5813,6 +5813,11 @@ object-copy@^0.1.0:
define-property "^0.2.5" define-property "^0.2.5"
kind-of "^3.0.3" kind-of "^3.0.3"
object-hash@^2.0.1:
version "2.0.1"
resolved "https://registry.npm.taobao.org/object-hash/download/object-hash-2.0.1.tgz#cef18a0c940cc60aa27965ecf49b782cbf101d96"
integrity sha1-zvGKDJQMxgqieWXs9Jt4LL8QHZY=
object-inspect@^1.7.0: object-inspect@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" resolved "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
...@@ -6778,6 +6783,10 @@ promise-inflight@^1.0.1: ...@@ -6778,6 +6783,10 @@ promise-inflight@^1.0.1:
resolved "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" resolved "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
"props-compute@http://gitlab2.dui88.com/laoqifeng/props-compute.git":
version "1.0.0"
resolved "http://gitlab2.dui88.com/laoqifeng/props-compute.git#c676e9e12a06ccc3556101197171ee47e9ebdd3c"
proxy-addr@~2.0.5: proxy-addr@~2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" resolved "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
...@@ -6810,6 +6819,14 @@ prr@~1.0.1: ...@@ -6810,6 +6819,14 @@ prr@~1.0.1:
resolved "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" resolved "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
"psd-parse-web@http://gitlab2.dui88.com/laoqifeng/psd-parse-web.git":
version "1.0.0"
resolved "http://gitlab2.dui88.com/laoqifeng/psd-parse-web.git#3b226df5c0bf306eae823324e3a5398fb1e548ac"
dependencies:
color "^3.1.2"
object-hash "^2.0.1"
uuid "^3.3.3"
pseudomap@^1.0.2: pseudomap@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" resolved "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
......
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