Commit c8071b6c authored by rockyl's avatar rockyl

Merge branch 'dev' into dep-lock

# Conflicts:
#	src/store/modules/project.js
#	src/views/Editor/dialogs/editors/CustomModuleEditor.vue
parents ef0c2537 6860fcba
......@@ -4,5 +4,6 @@ module.exports = {
id: 'LTAIqO2wblIxQvwc',
secret: '4brsaSRbRpjxw3oDIxJi6bNMcndIR6',
bucket: 'duiba',
output: '/editor/zeroing/v1'
output: '/editor/zeroing/v1',
exclude: /.js.map$/,
};
......@@ -7,8 +7,9 @@
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>烽火台</title>
<script src="https://cdn.bootcss.com/jshint/2.10.2/jshint.min.js"></script>
<script src="https://cdn.bootcss.com/jsonlint/1.6.0/jsonlint.min.js"></script>
<script src="//yun.duiba.com.cn/js-libs/jshint/2.10.2/jshint.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>
<body>
<noscript>
......@@ -18,7 +19,7 @@
<script>
window.__data = {
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>
<div id="app"></div>
......
......@@ -4,11 +4,12 @@
* 项目相关api
*/
import {fetchApi} from "./common";
import { fetchApi } from "./common"
import { getCookie } from './utils'
export async function fetchAll(currentPage, pageSize, onlyMine) {
return await fetchApi('/api/project/query', {
params: {currentPage, pageSize, isAll: onlyMine ? 0 : 1},
params: { currentPage, pageSize, isAll: onlyMine ? 0 : 1 },
errMessage: 'Failed to fetch projects',
})
}
......@@ -31,7 +32,7 @@ export async function duplicateOne(project) {
export async function deleteOne(id) {
return await fetchApi('/api/project/delete', {
params: {id},
params: { id },
method: 'post',
errMessage: 'Failed to delete project',
})
......@@ -39,7 +40,7 @@ export async function deleteOne(id) {
export async function fetchOne(id) {
return await fetchApi('/api/project/query/data', {
params: {id},
params: { id },
method: 'get',
errMessage: 'Failed to fetch project',
})
......@@ -55,14 +56,14 @@ export async function fetchOneFromDataUrl(dataUrl) {
export async function fetchHistory(id, currentPage, pageSize) {
return await fetchApi('/api/project/history', {
params: {id, currentPage, pageSize},
params: { id, currentPage, pageSize },
method: 'get',
errMessage: 'Failed to history',
})
}
export async function saveOne(project, remark) {
project.remark = remark;
project.remark = remark
return await fetchApi('/api/project/update', {
params: project,
method: 'post',
......@@ -72,7 +73,7 @@ export async function saveOne(project, remark) {
export async function pack(id, debug, packedAssets) {
return await fetchApi('/api/project/pack', {
params: {id, debug, packedAssets},
params: { id, debug, packedAssets },
method: 'post',
errMessage: 'Failed to pack project',
})
......@@ -86,22 +87,70 @@ export async function importView(file) {
method: 'post',
contentType: 'form-data',
errMessage: 'Failed to import view',
});
})
response.__originFile = file
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;
return response
}
export async function uploadFile(file, compress = false) {
let params = {file};
export async function uploadFile(file, compress = false, uuid) {
let params = { file }
if (compress) {
params.compress = true;
params.compress = true
}
if (uuid) {
params.uuid = uuid
}
const response = await fetchApi('/api/uploadFile', {
params,
method: 'post',
contentType: 'form-data',
errMessage: 'Failed to upload file',
});
response.__originFile = file;
return response;
})
response.__originFile = file
return response
}
export async function saveSkins(params) {
return await fetchApi(`/polaris/autoSaveSkins`, {
params,
method: 'post'
})
}
export async function getProjectSkins(projectId, env) {
return await fetchApi(`/polaris/getProjectSkins?projectId=${projectId}&env=${env}`, {
method: 'post',
params: {
cookie: {
dev: getCookie('sso_ticket'),
test: localStorage.getItem('ticket'),
prod: localStorage.getItem('prod_ticket'),
}
}
})
}
export async function getTestEnvTicket() {
return await fetchApi(`/polaris/getTestEnvTicket`, { method: 'get' })
}
export async function getProdTicket() {
return await fetchApi(`/polaris/getProdTicket`, { method: 'get' })
}
export async function sendDingTalk() {
return await fetchApi(`/polaris/sendMessage`, { method: 'post' })
}
\ No newline at end of file
export function getCookie(name) {
var cookie = document.cookie,
pattern = /([^=]+)=([^;]+);?\s*/g,
result,
value = {}
while ((result = pattern.exec(cookie)) != null) {
value[result[1]] = result[2]
}
return value[name]
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import events from './global-events';
let socket;
export let codeSyncServeEnabled = false;
export let codeSyncServeConnected = false;
export function startCodeSyncServe(config) {
if (socket) {
......@@ -20,25 +21,33 @@ export function startCodeSyncServe(config) {
socket.on('edit-save', onEditSave);
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) {
if(socket && socket.connected){
if (socket && socket.connected) {
socket.emit('edit-open', code);
}
}
function onConnect(t) {
codeSyncServeEnabled = true;
codeSyncServeConnected = true;
events.$emit('code-sync-start');
}
function onDisconnect() {
codeSyncServeEnabled = false;
codeSyncServeConnected = false;
events.$emit('code-sync-stop');
}
......
<template>
<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"
:is="getInput(property)"
:container="data.props"
:value="data.props[key]"
:propertyName="key"
:property="property"
:key="key"
:editable="editable"
:linkable="linkable"
@input="onInput"
/>
</el-form>
</template>
<script>
import {
NumberInput,
StringInput,
EnumInput,
BooleanInput,
ColorInput,
AssetInput,
NodeSelectInput,
MapInput,
DynamicInput,
Vector2Input,
} from "./inputs";
import {parseType} from 'props-compute'
const inputMapping = {
number: 'NumberInput',
string: 'StringInput',
enum: 'EnumInput',
boolean: 'BooleanInput',
color: 'ColorInput',
asset: 'AssetInput',
node: 'NodeSelectInput',
dynamic: 'DynamicInput',
map: 'MapInput',
vector2: 'Vector2Input',
array: 'StringInput',
};
export default {
name: "PropsEditor",
components: {
DynamicInput,
MapInput,
NodeSelectInput,
AssetInput,
ColorInput,
BooleanInput,
EnumInput,
NumberInput,
StringInput,
Vector2Input
},
data() {
return {}
},
props: {
labelWidth: {
type: String,
default: '100px',
},
editable: {
type: Boolean,
default: true
},
linkable: {
type: Boolean,
default: false
},
data: {
type: Object,
},
meta: {
type: Object,
},
},
methods: {
getInput(property) {
let {type} = parseType(property.type);
return inputMapping[type];
},
onInput(value, container, propName, oldValue) {
if (value === undefined) {
this.$delete(container, propName);
} else {
this.$set(container, propName, value);
}
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-select :disabled="!editable" :value="editValue" filterable @input="onInput" :placeholder="property.default" class="el-select">
<el-option
v-for="(item, key) in assets"
......@@ -19,7 +19,7 @@
export default {
name: "AssetInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-switch :disabled="!editable" :value="editValue" @input="onInput"
class="picker"></el-switch>
</input-wrapper>
......@@ -11,7 +11,7 @@
export default {
name: "BooleanInput",
components: {InputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
return {}
},
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName" class="color-input-container">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName" class="color-input-container">
<el-color-picker
:disabled="!editable"
class="picker"
......@@ -17,7 +17,7 @@
export default {
name: "ColorInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
return {
predefineColors: [
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property"
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<dynamic-selector style="flex: 1;" :value="value" @input="onChange"
:editable="editable"
......@@ -16,7 +16,7 @@
export default {
name: "DynamicInput",
components: {DynamicSelector, InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
methods: {
onChange(v){
this.$emit('input', v, this.container, this.propertyName, this.value);
......
......@@ -16,19 +16,19 @@
:placeholder="defaultValue"/>
</el-popover>
<el-button-group>
<el-button @click="onClickEdit" :disabled="!editable">{{editValue.type[0].toUpperCase()}}</el-button>
<el-button @click="onClickEdit" :disabled="!editable">{{dynamicIconMapping[editValue.type]}}</el-button>
<el-button icon="el-icon-delete" @click="onClickClean" :disabled="!editable"></el-button>
</el-button-group>
</div>
</template>
<script>
import {clonePureObj, getInputDefaultValue} from "../../../../utils";
import {clonePureObj, dynamicIconMapping, getInputDefaultValue} from "../../utils";
export default {
name: "DynamicSelector",
components: {},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
let dataTypes = this.$t('dataTypes');
return {
......@@ -36,6 +36,7 @@
popoverEditValue: this.value,
popoverVisible: false,
dataTypes,
dynamicIconMapping,
}
},
computed: {
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-select :disabled="!editable" :value="editValue" @input="onInput" :placeholder="property.default" class="el-select">
<el-option
v-for="(item, key) in property.enum"
......@@ -19,7 +19,7 @@
export default {
name: "EnumInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
......@@ -7,7 +7,7 @@
<p>{{$t('Name')}}{{propertyName}}</p>
</div>
<div>
<p class="alias">{{property.alias}}</p>
<p class="alias">{{property.alias||propertyName}}</p>
<p class="property-name">{{propertyName}}</p>
</div>
</el-tooltip>
......@@ -18,6 +18,7 @@
<slot></slot>
</template>
<el-popover
v-if="linkable"
trigger="click"
:disabled="!editable"
>
......@@ -49,6 +50,7 @@
container: {},
propertyName: String,
editable: Boolean,
linkable: Boolean,
contentWidth: {
type: String,
default: '65%',
......@@ -74,12 +76,12 @@
methods: {
onChange(v) {
if (v) {
this.$set(this.container.data.props, this.propertyName, {
this.$set(this.container, this.propertyName, {
type: 'link',
alias: undefined,
});
} else {
this.$delete(this.container.data.props, this.propertyName);
this.$delete(this.container, this.propertyName);
}
}
}
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property"
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
......@@ -38,13 +38,13 @@
<script>
import InputWrapper from "./InputWrapper";
import {getInputDefaultValue} from "../../../../utils";
import {getInputDefaultValue} from "../../utils";
import DynamicSelector from "./DynamicSelector";
export default {
name: "MapInput",
components: {DynamicSelector, InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
let dataTypes = this.$t('dataTypes');
return {
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property"
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
......@@ -11,8 +11,10 @@
v-model="popoverVisible"
>
<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-tree
ref="tree"
v-if="popoverVisible"
:data="behavior_views"
:props="defaultProps"
......@@ -22,6 +24,7 @@
:default-expand-all="true"
@node-click="handleNodeClick"
empty-text=""
:filter-node-method="filterNodeMethod"
>
<div slot-scope="{ node, data }" class="tree-node">
{{data.name}}
......@@ -30,15 +33,19 @@
</el-scrollbar>
<div class="bottom-bar">
<div></div>
<el-button-group>
<div>
<el-button @click="onCancel" plain>Cancel</el-button>
<el-button @click="onConfirm" type="primary" plain>Confirm</el-button>
</el-button-group>
<el-button @click="onConfirm" type="primary">Confirm</el-button>
</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">
<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-popover>
<el-button-group>
......@@ -52,35 +59,45 @@
<script>
import {mapGetters} from "vuex";
import InputWrapper from "./InputWrapper";
const nodeScheme = 'node://';
import {nodeScheme} from "../../utils";
export default {
name: "NodeSelectInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
return {
nodeScheme: nodeScheme,
filterText: '',
editValueOrigin: this.value,
popoverVisible: false,
defaultProps: {
children: 'children',
label: 'name'
},
nodePath: '',
}
},
watch: {
value(v) {
this.editValueOrigin = v;
}
this.editValue = v;
},
filterText(val) {
this.updateFilter();
},
},
computed: {
...mapGetters([
'behavior_views'
'behavior_views',
'behavior_searchViewNode',
]),
editValue: {
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) {
this.editValueOrigin = v;
......@@ -91,6 +108,23 @@
},
},
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) {
if (v !== this.value) {
this.$emit('input', v ? nodeScheme + v : undefined, this.container, this.propertyName, oldValue);
......@@ -103,6 +137,7 @@
this.popoverVisible = !this.popoverVisible;
},
onClickClean() {
this.nodePath = '';
this.$emit('input', undefined, this.container, this.propertyName, this.value);
},
onConfirm() {
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<el-input-number :disabled="!editable" :value="editValue" @input="onInput" controls-position="right"
:placeholder="defaultValue"></el-input-number>
</input-wrapper>
......@@ -7,12 +7,12 @@
<script>
import InputWrapper from "./InputWrapper";
import {getInputDefaultValue} from "../../../../utils";
import {getInputDefaultValue} from "../../utils";
export default {
name: "NumberInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
<template>
<input-wrapper :editable="editable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
placement="top"
......@@ -39,12 +39,12 @@
<script>
import InputWrapper from "./InputWrapper";
import {getInputDefaultValue} from "../../../../utils";
import {getInputDefaultValue} from "../../utils";
export default {
name: "StringInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
data() {
return {
editValueOrigin: this.value,
......
<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
/**
* Created by rockyl on 2020-01-08.
*/
export {default as NumberInput} from './NumberInput';
export {default as StringInput} from './StringInput';
export {default as EnumInput} from './EnumInput';
export {default as BooleanInput} from './BooleanInput';
export {default as ColorInput} from './ColorInput';
export {default as AssetInput} from './AssetInput';
export {default as NodeSelectInput} from './NodeSelectInput';
export {default as MapInput} from './MapInput';
export {default as DynamicInput} from './DynamicInput';
export {default as Vector2Input} from './Vector2Input';
......@@ -4,11 +4,11 @@
export let API_HOST;
if (process.env.NODE_ENV === 'development') {
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://192.168.1.16:7777';
//API_HOST = 'http://192.168.0.104:7777';
//API_HOST = 'http://10.10.92.33:7777';
//API_HOST = 'http://localhost:3002';
//API_HOST = '//10.10.95.74:7777';
//API_HOST = '//192.168.1.16:7777';
//API_HOST = '//192.168.0.104:7777';
//API_HOST = '//10.10.92.33:7777';
//API_HOST = '//localhost:3002';
API_HOST = window.__data.apiHost;
//API_HOST = '';
} else {
......
......@@ -9,7 +9,7 @@
"Save And Close": "Save And Close",
"Reset": "Reset",
"Copy": "Copy",
"Assets config": "Assets config",
"Assets": "Assets",
"Paste same level":"Paste(same level)",
"Paste child":"Paste(child)",
"Exit": "Exit",
......@@ -157,6 +157,7 @@
"Import single": "Import single",
"Import multi": "Import multi",
"Import view success": "Import view success",
"Input projectx id": "Input {envName} projectx id",
"menu": {
"save": {
"label": "Save"
......@@ -203,6 +204,7 @@
"static": "Static",
"arguments": "Arguments",
"data-center": "DataCenter",
"scope": "Scope",
"env": "Env"
},
"prosTypes": {
......@@ -242,5 +244,10 @@
"rendererType": {
"webgl": "WEBGL",
"canvas": "CANVAS"
},
"pxEnvs": {
"dev": "Dev Env",
"test": "Test Env",
"prod": "Prod Env"
}
}
\ No newline at end of file
......@@ -9,23 +9,28 @@
"Save And Close": "保存并关闭",
"Reset": "重置",
"Copy": "复制",
"Assets config": "素材配置",
"Assets": "素材",
"Paste same level":"粘贴(同级)",
"Paste child":"粘贴(子级)",
"Exit": "退出",
"Props": "属性",
"Behavior": "行为",
"Only mine": "仅显示我的",
"Only mine": "仅我的",
"Add": "添加",
"Delete": "删除",
"Delete all": "删除全部",
"Not delete": "不删除",
"History": "历史",
"Duplicate": "拷贝",
"Import": "导入",
"Export": "导出",
"Importing project": "项目导入中",
"Exporting project": "项目导出中",
"Upload": "上传",
"Uploading": "上传中",
"Auto launch": "自动启动",
"Running status": "运行状态",
"Stop status": "停止状态",
"Edit": "编辑",
"EditEnv": "编辑环境",
"EditCustomModule": "编辑自定义模块",
......@@ -34,6 +39,7 @@
"ID": "ID",
"Mock Editor": "Mock编辑器",
"Enable mock serve": "启用Mock服务",
"Events": "事件",
"Name": "名字",
"Alias": "别名",
"Output": "输出",
......@@ -90,6 +96,7 @@
"Scale Mode": "缩放模式",
"Renderer Type": "渲染模式",
"Props Editor": "属性编辑器",
"Events details": "事件详情",
"Trigger once": "触发一次",
"Meta Editor": "过程元配置",
"Env editor": "环境编辑器",
......@@ -107,6 +114,7 @@
"Builtin event should add directly": "内部事件请直接添加",
"Env constant": "自定义常量",
"Custom module": "自定义模块",
"Projectx config": "星速台配置",
"Custom module asset mapping": "自定义模块素材映射",
"Copy template to clipboard": "复制模板到粘贴板",
"Copied process to clipboard": "复制过程到粘贴板",
......@@ -161,6 +169,12 @@
"Import single": "导入单",
"Import multi": "导入多",
"Import view success": "视图导入成功",
"Input projectx id": "请舒服{envName}星速台项目ID",
"Save template to projectx": "是否保存皮肤到星速台",
"eventGroup": {
"in": "接收",
"out": "派发"
},
"menu": {
"save": {
"label": "保存"
......@@ -197,6 +211,7 @@
"textinput": "输入框",
"scrollView": "滚动视图",
"scrollList": "滚动列表",
"htmlView": "HTML视图",
"svga": "SVGA"
},
"panes": {
......@@ -209,6 +224,7 @@
"static": "静态",
"arguments": "入参",
"data-center": "数据中心",
"scope": "当前域",
"env": "自定义"
},
"prosTypes": {
......@@ -224,6 +240,7 @@
},
"nodeFilterPresets": {
"trigger": "行为触发",
"script": "脚本过滤",
"type": "节点类型"
},
"events": {
......@@ -248,5 +265,32 @@
"rendererType": {
"webgl": "WEBGL",
"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 @@
import Vue from "vue";
import i18n from "../../i18n";
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";
export const behaviorStore = {
......@@ -89,14 +89,16 @@ export const behaviorStore = {
return map;
},
metaInUse: state => targetMetaID => {
let result = false;
let allMetasInUse = [];
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;
break;
}*/
}
}
return result;
return allMetasInUse;
},
metaIDExists: state => id => {
let result = false;
......@@ -113,6 +115,11 @@ export const behaviorStore = {
},
behavior_views: state => {
return state.data.views;
},
behavior_searchViewNode: state => uuid => {
if(uuid){
return searchViewNode(state.data.views, uuid);
}
}
},
actions: {
......@@ -126,6 +133,7 @@ export const behaviorStore = {
script: '',
props: {},
isInline,
from: 'custom',
};
switch (processId) {
case 'custom':
......@@ -146,6 +154,7 @@ export const behaviorStore = {
let meta = clonePureObj(pMeta);
meta.id = generateUUID();
meta.isInline = isInline;
meta.from = 'custom';
delete meta.type;
addProcessMeta(commit, isInline, masterProcess, meta);
......@@ -180,14 +189,14 @@ function searchMeta(processes, keyword, path) {
}
}
export function addBehavior(alias, processes) {
export function addBehavior({alias, from}, processes) {
let metaUUID = generateUUID();
let behavior = {
uuid: generateUUID(),
meta: metaUUID,
};
let subEntryUUID = generateUUID();
processes.push({
let p = {
id: metaUUID,
name: alias,
props: {},
......@@ -203,7 +212,11 @@ export function addBehavior(alias, processes) {
}
},
},
});
};
if(from){
p.from = from;
}
processes.push(p);
return behavior;
}
......
......@@ -19,6 +19,7 @@ export const editorStore = {
custom: [],
},
codeSyncServeConfig: {
autoLaunch: false,
ip: 'localhost',
port: 7788,
}
......@@ -54,19 +55,25 @@ export const editorStore = {
];
const dividerProcess = {
id: 'divider',
name: i18n.t('Divider'),
name: 'Divider',
desc: i18n.t('Divider node desc'),//'分流节点,出口会按顺序一次执行',
};
tree.unshift(dividerProcess);
const customProcess = {
id: 'custom',
name: i18n.t('Custom'),
name: 'Custom',
desc: i18n.t('Custom node desc'),//'自定义节点',
};
tree.unshift(customProcess);
tree.push({
name: 'trigger',
from: 'trigger',
children: [],
});
tree.push({
name: 'custom',
from: 'custom',
children: [],
});
......
/**
* Created by rockyl on 2019-09-19.
*/
import Vue from "vue";
import JSZip from "jszip";
import {projectApi} from "../../api";
import path from "path";
import generateUUID from "uuid/v4";
import {getCmpProps, flattenViews, getCmpByUUID} from '../../utils/common';
import {clonePureObj, getMockServeEnabled, saveAs} from "../../utils";
import {template} from "../../template";
import {importView, uploadFile} from "../../api/project";
import events from "@/global-events";
import {packImages} from "../../utils/sheet-pack";
import {addBehavior, deleteProcessMeta, findProcess} from "./behavior";
import db from "../../utils/db-storage";
import {preprocess} from "../../views/Preview/preview-preprocess";
import {packagesStore} from "./packages";
const storeName = 'project';
import Vue from "vue"
import JSZip from "jszip"
import {projectApi} from "../../api"
import path from "path"
import generateUUID from "uuid/v4"
import {getCmpProps, flattenViews, getCmpByUUID} from '../../utils/common'
import {clonePureObj, getMockServeEnabled, saveAs} from "../../utils"
import {template} from "../../template"
import {importView, uploadFile, uploadView} from "../../api/project"
import events from "@/global-events"
import {packImages} from "../../utils/sheet-pack"
import {addBehavior, deleteProcessMeta, findProcess} from "./behavior"
import db from "../../utils/db-storage"
import {preprocess} from "../../views/Preview/preview-preprocess"
import {packagesStore} from "./packages"
import {fetchApi} from "../../api/common"
import {toZeroing} from "psd-parse-web"
const storeName = 'project'
const defaultOptions = {
pageTitle: 'no title',
......@@ -34,12 +36,17 @@ const defaultOptions = {
{name: 'appID', value: ''},
{name: 'projectID', value: ''},
],
pxEnv: {
dev: "",
test: "",
prod: "",
}
};
const OPERATE_MAX_LENGTH = 200; // 撤销重做栈最大值
function getDefaultOptions() {
return clonePureObj(defaultOptions);
return clonePureObj(defaultOptions)
}
function setUUIDForAllChildren(node) {
......@@ -51,10 +58,10 @@ function setUUIDForAllChildren(node) {
}
}
let copyNodeCatch = null;
let copyNodeCatch = null
function copyBaseRoot(node) {
let _node = JSON.parse(JSON.stringify(node));
let _node = JSON.parse(JSON.stringify(node))
let data;
......@@ -131,6 +138,10 @@ export const projectStore = {
if (data) {
const {views, assets, dataMapping, processes, options, customs, mock, dependencies} = typeof data === 'string' ? JSON.parse(data) : data;
if (!options.pxEnv) {
options.pxEnv = getDefaultOptions().pxEnv;
}
Vue.set(localData, 'options', options || getDefaultOptions());
Vue.set(localData, 'views', views || []);
Vue.set(localData, 'assets', assets || []);
......@@ -159,6 +170,9 @@ export const projectStore = {
modifyEnv(state, value) {
state.data.options.env = value;
},
modifyProjectx(state, value) {
state.data.options.pxEnv = value;
},
modifyDataMapping(state, value) {
state.data.dataMapping = value;
},
......@@ -584,7 +598,6 @@ export const projectStore = {
for (let key in state.data.dependencies) {
let version = state.data.dependencies[key];
}
},
......@@ -682,6 +695,23 @@ export const projectStore = {
scripts: _scripts
})
},
async importPsd({commit}, {file, action}) {
const result = await toZeroing(file);
let viewFile = new File([result], 'view.json');
const {view, assets} = await uploadView(viewFile);
switch (action) {
case 0: //单视图
view.name = file.name.substring(0, file.name.lastIndexOf('.'));
commit('importView', view);
break;
case 1: //多视图
for (let subView of view.children) {
commit('importView', subView)
}
break
}
commit('importAssets', assets)
},
async importView({commit}, {file, action}) {
const {view, assets} = await importView(file);
switch (action) {
......@@ -729,7 +759,7 @@ export const projectStore = {
savePreview({state, rootState, getters}) {
const {project} = getters;
const {processes, scripts, customs} = rootstate.editor;
const {processes, scripts, customs} = rootState.editor;
/*const data = {
processes, scripts, customs,
data: state.data,
......@@ -777,13 +807,22 @@ async function uploadFiles(files) {
return {
failedList,
result,
};
}
}
async function getSheetUrlByUUID(uuid) {
const response = await fetchApi('/api/uuid2url', {
params: {uuid},
errMessage: 'Failed to get url',
})
return response.url
}
async function packAssets(assets) {
let failedList = [];
let newAssets = assets.concat();
await packImages(newAssets);
let failedList = []
let newAssets = assets.concat()
await packImages(newAssets, {getSheetUrlByUUID})
for (let asset of newAssets) {
if (asset.file) {
......@@ -794,17 +833,18 @@ async function packAssets(assets) {
file: url,
type: 'sheet',
frames: asset.frames,
};
let sheetConfigFile = new File([JSON.stringify(sheetConfig)], 'sheet.json', {type: 'plain/text'});
}
let sheetConfigFile = new File([JSON.stringify(sheetConfig)], 'sheet.json', {type: 'plain/text'})
const {url: sheetConfigUrl} = await uploadFile(sheetConfigFile).catch(e => {
failedList.push(asset);
});
asset.url = sheetConfigUrl;
asset.uuid = generateUUID();
const {url: sheetConfigUrl} = await uploadFile(sheetConfigFile, false, asset.sheetUUID).catch(e => {
failedList.push(asset)
})
asset.url = sheetConfigUrl
asset.uuid = generateUUID()
delete asset.file;
delete asset.frames;
delete asset.file
delete asset.frames
delete asset.sheetUUID
}
}
......
......@@ -34,7 +34,7 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u
<body>
<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.269ce0ee2f951a11e004eee2df2fa1d875fa0b62.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$
<script>
engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json');
......
......@@ -280,25 +280,7 @@ $dock-pin-width: 9px;
display: flex;
flex-direction: column;
.linked {
display: block;
height: 26px;
overflow: hidden;
border: 1px solid $--border-color-base;
border-radius: 4px;
background-color: $--background-color-base;
flex: 1;
padding: 0 5px;
color: $--color-text-secondary;
}
.el-input-group__prepend {
padding: 0 5px;
}
.el-select {
width: 100%;
}
.wrapper {
padding: 5px;
......@@ -317,42 +299,23 @@ $dock-pin-width: 9px;
.scrollbar-view {
padding-right: 10px;
.input-wrapper {
.label {
p {
margin: 0;
//text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.alias {
line-height: 16px;
font-size: 14px;
}
.property-name {
line-height: 12px;
font-size: 12px;
color: $--color-text-secondary;
}
}
}
}
.el-form-item__content {
display: flex;
justify-content: flex-end;
.el-input-number--mini {
.inside-code{
flex: 1;
}
}
height: 0;
border-top: 1px solid $--border-color-base;
.node-select-container {
flex: 1;
.scrollbar {
height: 100%;
.code-body{
tab-size: 1.5em;
width: 100%;
margin: 0;
font-size: 12px;
white-space:pre-wrap;
}
}
}
}
......@@ -460,3 +423,64 @@ $dock-pin-width: 9px;
color: $--color-text-secondary;
}
}
.props-editor{
.linked {
display: block;
height: 26px;
overflow: hidden;
border: 1px solid $--border-color-base;
border-radius: 4px;
background-color: $--background-color-base;
flex: 1;
padding: 0 5px;
color: $--color-text-secondary;
}
.el-input-group__prepend {
padding: 0 5px;
}
.el-select {
width: 100%;
}
.input-wrapper {
.label {
p {
margin: 0;
//text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.alias {
line-height: 16px;
font-size: 14px;
}
.property-name {
line-height: 12px;
font-size: 12px;
color: $--color-text-secondary;
}
}
.field-label{
padding: 0 5px;
color: $--color-text-secondary;
}
}
.el-form-item__content {
display: flex;
justify-content: flex-end;
.el-input-number--mini {
flex: 1;
}
}
.node-select-container {
flex: 1;
}
}
......@@ -164,10 +164,53 @@
flex: 1;
}
}
}
.dialog-footer {
.dialog-footer {
display: flex;
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";
.home {
padding: 20px 30px;
padding: 20px 20px;
display: flex;
flex: 1;
flex-direction: column;
......
......@@ -59,6 +59,11 @@
height: 100%;
}
.el-collapse-item__header{
height: 30px;
line-height: 30px;
}
.el-tabs--border-card > .el-tabs__content {
padding: 5px 0 5px 5px;
}
......
......@@ -11,11 +11,6 @@
height: 0;
}
.el-collapse-item__header{
height: 25px;
line-height: 25px;
}
.el-tabs__item {
height: 25px;
line-height: 25px;
......
......@@ -30,6 +30,7 @@ const attrShortMapper = {
y: 'top',
align: 'text-align',
size: 'font-size',
font: 'font-family',
alpha: 'opacity',
'strokeColor': 'border-color',
'strokeWidth': 'border-width',
......
......@@ -6,6 +6,28 @@ import {Message, Loading} from "element-ui";
import i18n from '../i18n'
import generateUUID from "uuid/v4";
/**
* 动态数据图标映射
* @type {{"data-center": string, static: string, scope: string, arguments: string, env: string}}
*/
export const dynamicIconMapping = {
'static': 'S',
'arguments': 'A',
'data-center': 'D',
'scope': 'O',
'env': 'E',
};
/**
* 节点方案
* @type {string}
*/
export const nodeScheme = 'node://';
/**
* 弹出错误消息
* @param e
*/
export function messageError(e) {
Message({
dangerouslyUseHTMLString: true,
......@@ -14,6 +36,13 @@ export function messageError(e) {
})
}
/**
* 播放等待动画
* @param promise
* @param text
* @param closeLoading
* @return {*}
*/
export function playWaiting(promise, text, closeLoading = true) {
const loading = Loading.service({
lock: true,
......@@ -65,22 +94,38 @@ export function updateProcesses(processes, targetMetaID, replaceMetaID) {
}
}
/**
* 过程元依赖过程
* @param process
* @param targetMetaID
* @return {Array}
*/
export function metaInUse(process, targetMetaID) {
let result = false;
let result = [];
for (let key in process.sub) {
let subProcess = process.sub[key];
if (subProcess.meta === targetMetaID) {
result = true;
break;
result.push(process);
//break;
}
}
return result;
}
/**
* 克隆纯数据对象
* @param obj
* @return {any}
*/
export function clonePureObj(obj) {
return JSON.parse(JSON.stringify(obj));
}
/**
* 保存到本地
* @param blob
* @param fileName
*/
export function saveAs(blob, fileName) {
if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(blob, fileName);
......@@ -101,6 +146,11 @@ export function saveAs(blob, fileName) {
}
}
/**
* 读取文本文件
* @param file
* @return {Promise}
*/
export function readTextFile(file) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
......@@ -116,37 +166,55 @@ export function readTextFile(file) {
})
}
function scanEntries(item){
/**
* 扫描文件实体
* @param item
* @return {Promise}
*/
function scanEntries(item) {
return new Promise(resolve => {
if (item.isDirectory) {
let directoryReader = item.createReader();
directoryReader.readEntries(function(es){
directoryReader.readEntries(function (es) {
resolve(es);
});
}else{
} else {
resolve();
}
})
}
/**
* 扫描文件
* @param item
* @param container
* @return {Promise<void>}
*/
export async function scanFiles(item, container) {
const entries = await scanEntries(item);
if(entries){
for(let entry of entries){
if (entries) {
for (let entry of entries) {
container.push(entry);
await scanFiles(entry, container);
}
}
}
/**
* 选择文件
* @param callback
* @param accept
* @param multiple
* @param acceptDirectory
*/
export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) {
let input = document.createElement('input');
input.type = 'file';
input.onchange = function (e) {
callback(input.files);
};
if(acceptDirectory){
if (acceptDirectory) {
input.webkitdirectory = true;
}
if (accept) {
......@@ -158,6 +226,10 @@ export function selectFile(callback, {accept, multiple, acceptDirectory} = {}) {
input.click();
}
/**
* 打开预览页面
* @param packResult
*/
export function openPreview(packResult) {
setTimeout(() => {
let url;
......@@ -170,10 +242,29 @@ export function openPreview(packResult) {
}, 500);
}
/**
* url包装script元素
* @param url
* @return {string}
*/
export function newScriptEl(url) {
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) {
let enabled = localStorage.getItem('mock-enabled-' + projectID);
if (enabled) {
......@@ -181,3 +272,40 @@ export function getMockServeEnabled(projectID) {
}
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 {
value: undefined
},
horizonCenter: {
title: '水平偏移',
title: '水平居中偏移',
type: 'inputNumber',
value: undefined,
//desc: '相对于父元素中心点的水平偏移,0为正中心'
},
verticalCenter: {
title: '垂直偏移',
title: '垂直居中偏移',
type: 'inputNumber',
value: undefined,
//desc: '相对于父元素中心点的垂直偏移,0为正中心'
......@@ -135,10 +135,18 @@ export default {
type: 'textArea',
value: ''
},
font: {
title: '字体',
type: 'input',
value: 'Arial'
},
htmlText: {
title: 'HTML内容',
type: 'input',
value: ''
value: '',
props: {
clearable: true,
},
},
bold: {
title: '粗体',
......@@ -194,7 +202,7 @@ export default {
{ label: '居中', value: 'middle' },
{ label: '靠下', value: 'down' }
],
value: 'top'
value: 'up'
},
},
bitmapText: {
......@@ -203,12 +211,18 @@ export default {
text: {
title: '文本内容',
type: 'input',
value: ''
value: '',
props: {
clearable: true,
},
},
font: {
title: '字体名',
type: 'input',
value: ''
value: '',
props: {
clearable: true,
},
},
letterSpacing: {
title: '字间距',
......@@ -241,7 +255,10 @@ export default {
pattern: {
title: '输入模式',
type: 'input',
value: ''
value: '',
props: {
clearable: true,
},
},
maxLength: {
title: '最大长度',
......@@ -251,7 +268,10 @@ export default {
placeholder: {
title: '提示文字',
type: 'input',
value: ''
value: '',
props: {
clearable: true,
},
},
placeholderColor: {
title: '提示颜色',
......@@ -414,11 +434,15 @@ export default {
value: true,
},
},
/*htmlView: {
htmlView: {
base: 'node',
groupName: 'HTML视图',
htmlElement: {
title: 'HTML内容',
type: 'input',
props: {
clearable: true,
},
},
},
}*/
}
......@@ -4,6 +4,8 @@
import MaxRectsBinPack from "./MaxRectsBinPack";
import {clonePureObj} from "./index";
import sha256 from "crypto-js/sha256";
import generateUUID from "uuid/v4";
const packExts = ['.png']; //, '.jpg', '.jpeg', '.bmp'
......@@ -14,6 +16,8 @@ export async function packImages(asssts, options = {}) {
const maxSize = options.maxSize || 2048;
const mode = options.mode || 0;
const {getSheetUrlByUUID} = options;
const images = await preProcessing(asssts);
let rects = [], singles = [];
......@@ -70,7 +74,7 @@ export async function packImages(asssts, options = {}) {
});
let frames = {};
let i = 0;
let i = 0, urls = [];
for (let rect of packedRects) {
let sprite = {
x: rect.x + padding,
......@@ -83,17 +87,36 @@ export async function packImages(asssts, options = {}) {
sh: rect.sourceH,
};
urls.push(rect.assets[0].url);
for (let asset of rect.assets) {
frames[asset.uuid] = Object.assign({}, sprite, {name: asset.name});
i++;
}
}
const sheetUUID = sha256(urls.sort().join()).toString();
let url;
if (getSheetUrlByUUID) {
url = await getSheetUrlByUUID(sheetUUID);
}
if(url){
asssts.push({
ext: '.sht',
url,
uuid: generateUUID(),
});
}else{
asssts.push({
ext: '.sht',
file: new File([blob], name + '.png'),
frames,
sheetUUID,
});
}
index++;
}
}
......@@ -113,7 +136,7 @@ function loadImage(url, assets) {
})
}
async function preProcessing(assets) {
export async function preProcessing(assets) {
let targetAssets = [];
for (let i = 0, li = assets.length; i < li; i++) {
const asset = assets[i];
......@@ -134,6 +157,7 @@ async function preProcessing(assets) {
}
let ps = [];
for (let url in groups) {
ps.push(loadImage(url, groups[url]))
}
......
......@@ -90,9 +90,11 @@
await playWaiting(this.prepare(), this.$t('Preparing')).catch(e => {
console.log(e);
});
if(this.codeSyncServeConfig.autoLaunch){
setTimeout(() => {
//startCodeSyncServe(this.codeSyncServeConfig);
startCodeSyncServe(this.codeSyncServeConfig);
}, 100);
}
this.loadProject().catch(e => {
console.log(e);
......
......@@ -6,13 +6,13 @@
<script>
import events from "../../../global-events";
import {codeSyncServeEnabled} from "../../../code-sync-serve";
import {codeSyncServeConnected} from "../../../code-sync-serve";
export default {
name: "CodeSyncIndicator",
data() {
return {
enabled: codeSyncServeEnabled,
enabled: codeSyncServeConnected,
}
},
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>
<div class="zero-inspector-props-form" v-if="activeComponent.uuid">
<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-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item>
......
......@@ -76,6 +76,8 @@
import {selectFile} from "../../utils";
import events from "../../global-events";
let PSD = window['require']('psd');
export default {
name: 'Views',
components: {Pane},
......@@ -140,11 +142,28 @@
}
}
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':
if (param && param.length > 0) {
let types = param.split(',');
visible = types.includes(data.type);
}else{
} else {
visible = true;
}
break;
......@@ -162,6 +181,9 @@
case 'trigger':
filterText = ':trigger';
break;
case 'script':
filterText = ':script';
break;
case 'type':
filterText = ':type|node';
break;
......@@ -201,7 +223,7 @@
selectFile(async files => {
events.$emit('upload-indicator', true);
try {
await this.importView({
await this.importPsd({
file: files[0],
action,
});
......@@ -266,7 +288,7 @@
}
},
...mapMutations(['copyNode', 'pasteNode', 'deleteNode', 'addNode']),
...mapActions(['exportView', 'importView'])
...mapActions(['exportView', 'importView', 'importPsd'])
}
};
</script>
......
......@@ -64,8 +64,10 @@
},
normalProcessTree() {
const tree = this.builtinProcessTree;
const group = tree.find(item => item.name === 'custom');
group.children = this.$store.state.behavior.data.processes;
const customGroup = tree.find(item => item.name === 'custom');
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;
},
...mapState({
......@@ -74,7 +76,7 @@
}),
...mapGetters([
'prefabProcessTree',
'builtinProcessTree'
'builtinProcessTree',
]),
},
methods: {
......@@ -112,9 +114,13 @@
this.$refs.metaEditorDialog.edit(meta);
},
onDeleteMeta(meta) {
const inUse = this.$store.getters.metaInUse(meta.id);
if (inUse) {
this.$alert(this.$t('Meta is in use, can not delete'), this.$t('Alert'))
const metaInUse = this.$store.getters.metaInUse(meta.id);
if (metaInUse.length > 0) {
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) => {
});
} else {
......
<template>
<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">
<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-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider" @mousedown.stop.prevent @click.stop="onClickEdit"/>
<el-link icon="el-icon-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider"
@mousedown.stop.prevent @click.stop="onClickEdit"/>
<el-link icon="el-icon-document-copy" :underline="false" @mousedown.stop.prevent @click.stop="onClickCopy"/>
</div>
<div class="header">
......@@ -13,6 +15,14 @@
</div>
<div class="body">
<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-minus" circle @click="outputPointModify('remove')"></el-button>
</div>
......@@ -26,7 +36,7 @@
</template>
<template v-else>
{{objToString(data.props[key].value)}}
<i class="tag">{{data.props[key].type[0].toUpperCase()}}</i>
<i class="tag">{{dynamicIconMapping[data.props[key].type]}}</i>
</template>
</span>
</span>
......@@ -53,9 +63,10 @@
</template>
<script>
import {mapState} from "vuex";
import {mapState, mapGetters} from "vuex";
import DockPin from "./DockPin";
import events from "../../../../global-events";
import {dynamicIconMapping, nodeScheme} from "../../../../utils";
export default {
name: "ProcessNode",
......@@ -69,6 +80,8 @@
height: 100,
inputMeta,
active: false,
dynamicIconMapping,
dividerTypes: this.$t('dividerTypes'),
}
},
mounted() {
......@@ -90,6 +103,9 @@
drawState: state => state.behavior.drawState,
editable: state => state.behavior.editable,
}),
...mapGetters([
'behavior_searchViewNode'
]),
},
watch: {
process(v) {
......@@ -105,13 +121,19 @@
let asset = this.$store.getters.behavior_getAssetByUUID(data.props[key]);
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 {
return data.props[key] || param.default;
return data.props.hasOwnProperty(key) ? data.props[key] : param.default;
}
return '';
},
objToString(value){
objToString(value) {
return typeof value === 'object' ? '' : (value || '');
},
prepare() {
......
......@@ -99,25 +99,25 @@
:options="cmOptions"
@cursorActivity="onCodeChange"
/>-->
<!--<monaco-editor
<monaco-editor
ref="codeEditor"
v-if="meta"
:code="meta.script"
:options="monacoConfig"
/>-->
<code-editor v-if="meta" v-model="meta.script"/>
/>
<!-- <code-editor v-if="meta" v-model="meta.script" /> -->
</div>
<div slot="footer" class="dialog-footer">
<div class="button-bar">
<div>
<el-button-group style="margin-right: 20px;">
<el-button size="mini" plain @click="copyMeta">CopyMeta</el-button>
<el-popover>
<div ref="pasteBoard" @paste="onPaste">Click and Ctrl+V</div>
<el-button size="mini" slot="reference" plain @click="pasteMeta"
>PasteMeta</el-button
>
<el-button size="mini" slot="reference" plain @click="pasteMeta">PasteMeta</el-button>
</el-popover>
</el-button-group>
</div>
<div class="button-bar">
<el-button size="mini" plain @click="cancel">{{
$t("Cancel")
}}</el-button>
......@@ -132,16 +132,15 @@
</template>
<script>
import ElFormItem from "./inputs/form-item";
import PropsEditorDialog from "./PropsEditorDialog";
//import MonacoEditor from "../components/MonacoEditor";
import MonacoEditor from "../components/MonacoEditor";
import copy from "copy-to-clipboard";
import { clonePureObj } from "../../../utils";
import events from "../../../global-events";
import CodeSyncIndicator from "../BottomBar/CodeSyncIndicator";
import CodeEditor from "./CodeEditor";
const exposeVariables = ["args", "props", "target", "global", "vm", "engine"];
const exposeVariables = ["args", "props", "target", "global", "vm", "engine", 'scope'];
export default {
name: "MetaEditorDialog",
......@@ -149,8 +148,7 @@ export default {
CodeEditor,
CodeSyncIndicator,
PropsEditorDialog,
ElFormItem,
//"monaco-editor": MonacoEditor
"monaco-editor": MonacoEditor
},
data() {
return {
......@@ -227,6 +225,7 @@ export default {
this.meta.script = this.$refs.codeEditor.editor.getValue();
this.$emit("input", this.meta, isPreview);
this.visible = false;
this.meta = null;
}
} else {
return false;
......@@ -235,6 +234,7 @@ export default {
},
cancel() {
this.visible = false;
this.meta = null;
},
copyMeta() {
copy(JSON.stringify(this.meta));
......
......@@ -12,6 +12,7 @@
</div>
</div>
<div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" plain @click="close">{{$t('Close')}}</el-button>
</div>
</el-dialog>
......
......@@ -11,14 +11,15 @@
>
<div slot-scope="{ node, data }" class="process-tree-node">
<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>
<el-dropdown v-if="nodeMenu(data)" class="more-button" size="mini" trigger="click"
@command="(command)=>{onMoreMenu(command, data, node)}">
<el-link icon="el-icon-more" :underline="false" @click.stop/>
<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="delete" v-if="metaEditable(data)">{{$t('Delete')}}</el-dropdown-item>
</el-dropdown-menu>
......@@ -38,7 +39,7 @@
export default {
name: "ProcessList",
props: [
'data',
'data', 'type',
],
data() {
return {
......@@ -63,27 +64,34 @@
},
computed: {
...mapState({
currentProcess(state){
currentProcess(state) {
return state.behavior.currentProcess;
}
}),
},
methods: {
updateFilter(){
if(this.$refs.tree){
transName(meta, node){
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);
}
},
draggable(data) {
return !data.hasOwnProperty('children') && data.isDivider !== true ;
return !data.hasOwnProperty('children') && data.isDivider !== true;
},
dragProcessStart(data, event) {
event.dataTransfer.setData('process', data.id);
},
nodeMenu(data){
nodeMenu(data) {
return !data.hasOwnProperty('children')
},
metaEditable(data){
metaEditable(data) {
return data.type !== 'builtin' && !data.hasOwnProperty('children') && !editableIds.includes(data.id) && data.isDivider !== true
},
onMoreMenu(command, data, node) {
......@@ -104,14 +112,16 @@
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;
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){
let yes= this.currentProcess && this.currentProcess.meta && data.id && data.id === this.currentProcess.meta.id;
if(yes){
isCurrentProcess(data) {
let yes = this.currentProcess && this.currentProcess.meta && data.id && data.id === this.currentProcess.meta.id;
if (yes) {
console.log();
}
return yes;
......
<template>
<div class="wrapper" v-if="process">
<el-input :readonly="!editable" class="name-input" v-model="process.data.alias" clearable :placeholder="process.meta.name" size="mini">
<el-input :readonly="!editable" class="name-input" v-model="process.data.alias" clearable
:placeholder="process.meta.name" size="mini">
<template slot="prepend">{{$t('Name')}}</template>
</el-input>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"
view-class="scrollbar-view">
<el-form v-model="process" size="mini" label-width="100px" label-position="left" @submit.native.prevent>
<component v-for="(property, key) in process.meta.props"
:is="getInput(property)"
v-model="process.data.props[key]"
:propertyName="key"
:property="property"
:container="process"
:key="key"
:editable="editable"
/>
</el-form>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="scrollbar-view">
<props-editor ref="propsEditor" :editable="editable" :linkable="true" :data="process.data" :meta="process.meta"/>
</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>
</template>
<script>
import {mapState} from "vuex";
import NumberInput from "./inputs/NumberInput";
import StringInput from "./inputs/StringInput";
import EnumInput from "./inputs/EnumInput";
import BooleanInput from "./inputs/BooleanInput";
import ColorInput from "./inputs/ColorInput";
import AssetInput from "./inputs/AssetInput";
import NodeSelectInput from "./inputs/NodeSelectInput";
import MapInput from "./inputs/MapInput";
import DynamicInput from "./inputs/DynamicInput";
const inputMapping = {
number: 'NumberInput',
string: 'StringInput',
enum: 'EnumInput',
boolean: 'BooleanInput',
color: 'ColorInput',
asset: 'AssetInput',
node: 'NodeSelectInput',
dynamic: 'DynamicInput',
map: 'MapInput',
};
import PropsEditor from "../../../components/PropsEditor";
export default {
name: "PropertiesInput",
components: {
DynamicInput,
MapInput, NodeSelectInput, AssetInput, ColorInput, BooleanInput, EnumInput, NumberInput, StringInput},
PropsEditor,
},
data() {
return {
process: null,
......
......@@ -71,6 +71,7 @@
</el-scrollbar>
</div>
<div slot="footer" class="dialog-footer">
<div></div>
<div class="button-bar">
<el-button size="mini" plain @click="cancel">{{$t('Cancel')}}</el-button>
<el-button size="mini" plain @click="save">{{$t('Save')}}</el-button>
......
......@@ -2,19 +2,25 @@
<div id="container"></div>
</template>
<script>
import * as monaco from "monaco-editor";
export default {
import * as monaco from "monaco-editor";
const typesUrl = [
"http://yun.duiba.com.cn/editor/zeroing/types/types.d.ts",
"http://yun.duiba.com.cn/editor/zeroing/types/process-context.v4.d.ts",
];
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 {options, code} = this;
const types = await Promise.all(typesUrl.map(async url => {
const res = await fetch(url);
return res.text();
}));
const defaultConfig = {
language: "javascript",
......@@ -32,19 +38,22 @@ export default {
});
// extra libraries
monaco.languages.typescript.javascriptDefaults.addExtraLib(
[types].join("\n")
types.join("\n")
);
const config = Object.assign({}, defaultConfig, options, { value: code });
const config = Object.assign({}, defaultConfig, options, {value: code});
this.editor = monaco.editor.create(
document.getElementById("container"),
config
);
},
destroyed() {
this.editor.dispose();
}
};
};
</script>
<style lang="scss" scoped>
#container {
#container {
width: 100%;
height: 100%;
}
}
</style>
......@@ -4,9 +4,12 @@
:append-to-body="true" custom-class="flex-dialog behavior-editor-dialog">
<behavior-editor v-if="editorReady" ref="behaviorEditor" class="full-size"></behavior-editor>
<div slot="footer" class="dialog-footer">
<div></div>
<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>
</el-dialog>
</template>
......
<template>
<el-dialog :title="$t('CodeSyncServe')" width="70%" :visible.sync="visible"
:append-to-body="true"
custom-class=""
custom-class="code-sync-serve-dialog"
>
<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-input v-model="config.ip"/>
</el-form-item>
......@@ -15,7 +18,8 @@
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-switch :value="enabled" @input="onEnableServer"/>
<span class="status">{{$t(status)}}</span>
</div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
......@@ -28,23 +32,30 @@
<script>
import {mapMutations, mapState} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import ElFormItem from "../behavior-editor/inputs/form-item";
import {clonePureObj} from "../../../utils";
import {startCodeSyncServe} from "../../../code-sync-serve";
import {codeSyncServeEnabled, startCodeSyncServe, stopCodeSyncServe} from "../../../code-sync-serve";
import events from '../../../global-events';
export default {
name: "CodeSyncServeDialog",
components: {ElFormItem, EnabledSetter,},
components: {EnabledSetter,},
data() {
return {
visible: false,
config: {},
enabled: codeSyncServeEnabled,
}
},
mounted() {
events.$on('code-sync-status', this.onStatusChange);
},
destroyed() {
events.$off('code-sync-status', this.onStatusChange);
},
computed: {
status() {
return this.enabled ? 'Running status' : 'Stop status';
},
...mapState({
codeSyncServeConfig(state) {
return state.editor.codeSyncServeConfig;
......@@ -58,12 +69,22 @@
},
onSave() {
this.saveCodeSyncServeConfig(this.config);
startCodeSyncServe(this.config);
this.visible = false;
},
onClose() {
this.visible = false;
},
onStatusChange(v) {
this.enabled = v;
},
onEnableServer(v) {
if (v) {
startCodeSyncServe(this.config);
} else {
stopCodeSyncServe();
}
this.enabled = v;
},
...mapMutations([
'saveCodeSyncServeConfig',
]),
......
......@@ -19,11 +19,17 @@
<el-tab-pane :label="$t('Custom module')" name="custom">
<custom-module-editor ref="customModuleEditor"/>
</el-tab-pane>
<el-tab-pane :label="$t('Projectx config')" name="projectx">
<projectx-config ref="projectxConfig" />
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div>
</div>
</el-dialog>
</template>
......@@ -33,17 +39,20 @@
import EnvEditor from "./editors/EnvEditor";
import CustomModuleEditor from "./editors/CustomModuleEditor";
import DataMappingEditor from "./editors/DataMappingEditor";
import ProjectxConfig from "./editors/ProjectxConfig";
const refs = [
'projectEditor',
'envEditor',
'dataMappingEditor',
'customModuleEditor',
"projectxConfig"
];
export default {
name: "DetailsDialog",
components: {DataMappingEditor, CustomModuleEditor, EnvEditor, ProjectEditor},
components: {DataMappingEditor, CustomModuleEditor, EnvEditor, ProjectEditor,
ProjectxConfig},
data() {
return {
visible: false,
......
<template>
<el-dialog :title="$t('Project details')" width="70%" :visible.sync="visible" @open="onOpen"
<el-dialog
:title="$t('Project details')"
width="70%"
:visible.sync="visible"
@open="onOpen"
:close-on-click-modal="false"
:append-to-body="true"
:show-close="false"
custom-class="details-dialog"
>
<div>
<p>{{$t('Pack project successfully')}}</p>
<p>{{ $t("Pack project successfully") }}</p>
<el-collapse>
<el-collapse-item :title="$t('Check template code')" name="1">
<el-input v-if="packResult" type="textarea" readonly v-model="packResult.tpl" :rows="10"/>
<el-input
v-if="packResult"
type="textarea"
readonly
v-model="packResult.tpl"
:rows="10"
/>
</el-collapse-item>
</el-collapse>
<el-checkbox v-model="isSaveProjecx" style="margin: 20px 0">{{$t('Save template to projectx')}}</el-checkbox>
<projectx-options
v-if="isSaveProjecx"
:tpl="packResult.tpl"
></projectx-options>
</div>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="copy">{{$t('Copy template to clipboard')}}</el-button>
<el-button size="mini" type="primary" @click="openInNewTab">{{$t('Open in new tab')}}</el-button>
<div></div>
<div>
<el-button size="mini" @click="onClose">{{ $t("Close") }}</el-button>
<el-button size="mini" @click="copy">
{{ $t("Copy template to clipboard") }}
</el-button>
<el-button size="mini" type="primary" @click="openInNewTab">
{{ $t("Open in new tab") }}
</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import copy from 'copy-to-clipboard'
import ProjectxOptions from "./ProjectxOptions";
import {openPreview} from "../../../utils";
export default {
name: "PackResultDialog",
components: {},
components: {"projectx-options": ProjectxOptions},
data() {
return {
visible: false,
isSaveProjecx: false,
activeName: 'project',
packResult: null,
}
......
<template>
<div class="config">
<el-select
size="small"
v-model="env"
placeholder="请选择环境"
@change="changeenv"
>
<el-option
v-for="(item, key) in pxEnvs"
:key="key"
:label="item"
:value="key"
></el-option>
</el-select>
<el-select size="small" v-model="operate" placeholder="是否新增">
<el-option
v-for="(item, key) in tplOperates"
:key="key"
:label="item"
:value="key"
></el-option>
</el-select>
<el-select
v-if="operate !== 0"
size="small"
v-model="skinId"
placeholder="选择skinID"
clearable
>
<el-option
v-for="item in skinList"
:key="item.id"
:label="`${item.type !== 0 ? item.name : '首页'}(${item.id})`"
:value="item.id"
></el-option>
</el-select>
<div v-if="operate === 0">
<el-select size="small" v-model="tplType" placeholder>
<el-option
v-for="(item, key) in tplTypes"
:key="key"
:label="item"
:value="key"
></el-option>
</el-select>
<el-input
v-model="name"
size="small"
class="name"
placeholder="请输入皮肤名称"
></el-input>
</div>
&nbsp;
<el-button type="primary" size="small" @click="saveSkins">保存</el-button>
<el-button v-if="skinId" type="primary" size="small" @click="getUrl"
>获取链接</el-button
>
</div>
</template>
<script>
import { mapState } from "vuex";
import copy from "copy-to-clipboard";
import {
getProjectSkins,
saveSkins,
getTestEnvTicket,
getProdTicket,
sendDingTalk
} from "../../../../src/api/project";
export default {
name: "ProjectxOptions",
props: {
tpl: String
},
data() {
return {
pxEnvs: this.$t('pxEnvs'),
tplOperates: this.$t('tplOperates'),
tplTypes: this.$t('tplTypes'),
env: "dev",
operate: 1,
tplType: 0,
skinId: "",
skinList: [],
projectId: "",
name: ""
};
},
computed: {
...mapState(["project"])
},
methods: {
getProjectId(env) {
const { pxEnv } = this.project.data.options;
this.projectId = pxEnv[env];
return this.projectId;
},
async changeenv(e) {
if (e === "test") {
await this.getTicket(getTestEnvTicket);
} else if (e === "prod") {
await this.getTicket(getProdTicket, "prod_ticket");
}
const projectId = this.getProjectId(e);
this.skinId = "";
this.getSkinsList(projectId);
},
async getSkinsList(projectId) {
const { env } = this;
if (!projectId) {
this.$message({
message: `请先配置${env}环境下的projectId`,
type: "error"
});
return;
}
try {
const data = await getProjectSkins(projectId, env);
if (data.success !== false) {
this.skinList = data;
} else {
// 如果是测试环境,ticket过期,则重新获取ticket
if (env === "test" && data.notLogin) {
localStorage.setItem("ticket", "");
await this.getTicket(getTestEnvTicket);
this.getSkinsList(this.projectId);
} else if (env === "prod" && data.notLogin) {
// 如果是线上环境,则发送钉钉消息
sendDingTalk();
localStorage.setItem("prod_ticket", "");
this.$message({
message: "线上tickct失效,已给相关人员发送消息",
type: "info"
});
this.skinList = [];
return;
// sendDingTalk();
} else {
this.$message({
message: data.message,
type: "error"
});
this.skinList = [];
return;
}
}
} catch (e) {
this.skinList = [];
throw new Error(e.message);
}
},
hasIndex() {
const { skinList } = this;
return skinList.some(v => v.type === '1');
},
async saveSkins() {
const {
env,
skinId,
tplType,
operate,
projectId,
tpl,
name,
skinList
} = this;
if (operate === 1 && !skinId) {
this.$message({ message: "请选择修改的皮肤", type: "warning" });
return;
}
if (operate === 0) {
if (this.hasIndex() && tplType === 0) {
this.$message({ message: "已存在首页", type: "warning" });
return;
} else if (!name) {
this.$message({ message: "请输入要添加的皮肤名称", type: "warning" });
return;
}
}
const data = {
projectId,
type: (operate + 1).toString(),
currentHtmlType: (tplType + 1).toString(),
skinId,
tpl,
name,
env: env
};
const { ret } = await saveSkins(data);
if (ret.success !== false) {
this.$message({
message: `操作成功`,
type: "success"
});
} else {
this.$message({ message: ret.message, type: "error" });
}
// 新增皮肤则重新获取皮肤列表
if (operate !== 1) {
// 2为修改,修改不需重新获取列表
this.getSkinsList(projectId);
} else if (operate !== 2) {
this.name = "";
}
},
/** 获取访问链接 */
getUrl() {
const { tplType, env, skinId, projectId } = this;
const mapping = {
dev: "activity.m.duibadev.com.cn",
test: "activity.m.duibatest.com.cn",
prod: "https://activity.m.duiba.com.cn"
};
const url = `${mapping[env]}/projectx/${projectId}/${
tplType === 0 ? "index" : skinId
}.html`;
copy(url);
this.$message({
message: "链接复制成功",
type: "success"
});
},
async getTicket(fn, name = "ticket") {
let ticket = localStorage.getItem(name);
if (!ticket) {
ticket = await fn();
localStorage.setItem(name, ticket);
}
}
},
async mounted() {
const { projectxConfig } = this.project.data.options;
const projectId = projectxConfig[this.env];
this.projectId = projectId;
this.getSkinsList(projectId);
},
async created() {}
};
</script>
<style lang="scss">
.config {
display: flex;
.name {
display: inline-block;
width: 200px;
}
}
</style>
......@@ -8,6 +8,7 @@
<asset-list @click-item="onClickItem"/>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
</div>
</el-dialog>
......
......@@ -17,7 +17,7 @@
{{item.ext}}
</span>
<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>
<el-input size="mini" v-model="item.url" readonly/>
</div>
......@@ -40,9 +40,12 @@
</div>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div>
</div>
<select-asset-dialog ref="selectAssetDialog" @select="onSelectReplace"/>
</el-dialog>
</template>
......
......@@ -17,14 +17,44 @@
:label="$t('Name')"
width="200">
</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
prop="assets"
:label="$t('Assets config')"
width="100">
:label="$t('Assets')"
width="60">
<template slot-scope="scope">
<el-button size="mini" icon="el-icon-edit" circle type="primary" plain @click="editAssetMapping(scope.row)"/>
</template>
</el-table-column>
<el-table-column
prop="props"
:label="$t('Props')"
width="60">
<template slot-scope="scope">
<el-button size="mini" icon="el-icon-edit" circle type="primary" plain @click="editProps(scope.row)"/>
</template>
</el-table-column>
<!--<el-table-column
label="Version"
width="100"
......@@ -36,6 +66,8 @@
<el-table-column>
</el-table-column>
<asset-mapping-editor-dialog ref="assetMappingEditorDialog" @save="onSaveAssetMapping"/>
<props-editor-dialog ref="propsEditorDialog"/>
<events-details-dialog ref="eventsDetailsDialog"/>
</el-table>
</template>
......@@ -43,10 +75,12 @@
import {mapState, mapMutations} from 'vuex'
import {clonePureObj} from "../../../../utils";
import AssetMappingEditorDialog from "./AssetMappingEditorDialog";
import PropsEditorDialog from "./CustomModuleEditor/PropsEditorDialog";
import EventsDetailsDialog from "./CustomModuleEditor/EventsDetailsDialog";
export default {
name: "CustomModuleEditor",
components: {AssetMappingEditorDialog},
components: {EventsDetailsDialog, PropsEditorDialog, AssetMappingEditorDialog},
data() {
return {
visible: false,
......@@ -64,12 +98,18 @@
this.editData = clonePureObj(this.customs);
this.customMetas.splice(0);
for (let meta of this.$store.state.editor.customs) {
let data = this.editData.find(item => item.id === meta.id);
let editData = this.editData.find(item => item.id === meta.id);
let data = editData ? editData : (editData || {});
if (!data.props) {
data.props = {};
}
this.customMetas.push({
id: meta.id,
name: meta.name,
assetMapping: data && (data.assetMapping || {}),
selected: !!data,
meta,
data,
assetMapping: editData && (editData.assetMapping || {}),
selected: !!editData,
})
}
},
......@@ -81,16 +121,23 @@
editData.push({
id: meta.id,
assetMapping: meta.assetMapping || {},
props: meta.data.props || {},
});
}
}
this.modifyCustoms(editData);
},
editAssetMapping(data) {
this.$refs.assetMappingEditorDialog.show(data);
editAssetMapping(item) {
this.$refs.assetMappingEditorDialog.show(item);
},
editProps(item) {
this.$refs.propsEditorDialog.show(item.data, item.meta);
},
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([
'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
<template>
<el-dialog :title="$t('Props Editor')" width="70%" :visible.sync="visible" @opened="onOpen"
:close-on-click-modal="false"
:append-to-body="true"
:show-close="false"
custom-class="props-editor-dialog"
>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden"
view-class="scrollbar-view">
<props-editor v-if="data" ref="propsEditor" :data="data" :meta="meta" label-width="180px" :linkable="false"/>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<div></div>
<div>
<el-button size="mini" @click="onClose">{{$t('Close')}}</el-button>
<el-button size="mini" @click="onSave" type="primary">{{$t('Save')}}</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import PropsEditor from "../../../../../components/PropsEditor";
export default {
name: "PropsEditorDialog",
components: {PropsEditor},
data() {
return {
visible: false,
data: null,
meta: null,
}
},
methods: {
show(data, meta) {
this.data = data;
this.meta = meta;
this.visible = true;
},
onSave() {
this.visible = false;
},
onClose() {
this.visible = false;
},
onOpen() {
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>
<div v-for="(item, key) in pxEnvs" :key="key">
<div class="list">
<span>{{ item }}</span>
<el-icon class="el-icon-connection" />
<el-input
size="small"
v-model="editData[key]"
:placeholder="$t('Input projectx id', {envName: item})"
></el-input>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations } from "vuex";
import { clonePureObj } from "../../../../utils";
export default {
name: "ProjectxConfig",
data() {
return {
pxEnvs: this.$t('pxEnvs'),
editData: {
dev: "",
test: "",
prod: ""
}
};
},
computed: {
...mapState({
pxEnv: state => state.project.data.options.pxEnv,
}),
},
methods: {
...mapMutations(["modifyProjectx"]),
edit() {
this.editData = clonePureObj(this.pxEnv);
},
save() {
this.modifyProjectx(this.editData);
}
}
};
</script>
<style lang="scss" scoped>
.list {
display: flex;
align-items: center;
margin-bottom: 20px;
span {
width: 100px;
text-align: center;
}
i {
width: 50px;
}
> div {
width: 200px;
}
}
</style>
......@@ -22,7 +22,7 @@
</el-table-column>
<el-table-column
fixed="right"
width="180">
width="100">
<template slot="header" slot-scope="scope">
<el-checkbox
v-model="onlyMine"
......@@ -30,40 +30,52 @@
</el-checkbox>
</template>
<template slot-scope="scope">
<el-button
<!--<el-button
@click.native.prevent="selectProject(scope.row)"
type="primary" icon="el-icon-edit"
size="small" circle plain>
</el-button>
<el-button
size="mini" plain>
{{$t('Edit')}}
</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)"
type="primary" icon="el-icon-coin"
size="small" circle plain>
</el-button>
icon="el-icon-coin"
size="mini" plain
>{{$t('History')}}</el-button>
<el-button
@click.native.prevent="showDuplicateProjectDialog(scope.row)"
type="success" icon="el-icon-document-copy"
size="small" circle plain>
</el-button>
icon="el-icon-document-copy"
size="mini" plain
>{{$t('Duplicate')}}</el-button>
<el-button
@click.native.prevent="exportProject(scope.row)"
type="warning" icon="icon-download"
size="small" circle plain>
</el-button>
icon="icon-download"
size="mini" plain
>{{$t('Export')}}</el-button>
<el-button
v-if="showDeleteButton"
@click.native.prevent="onDeleteProject(scope.row)"
type="danger" icon="el-icon-delete"
size="small" circle plain>
</el-button>
size="mini" circle plain>
</el-button>-->
</template>
</el-table-column>
</el-table>
</div>
<div class="bottom-bar">
<div>
<el-button type="primary" @click="showCreateProjectDialog()">{{$t('Create')}}</el-button>
<el-button @click="importProject()">{{$t('Import')}}</el-button>
<el-button size="small" type="primary" @click="showCreateProjectDialog()">{{$t('Create')}}</el-button>
<el-button size="small" @click="importProject()">{{$t('Import')}}</el-button>
</div>
<el-pagination
@current-change="handleCurrentChange"
......@@ -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}) {
const project = await playWaiting(this.fetchProject(id), this.$t('Exporting project'));
saveAs(new Blob([JSON.stringify(project)]), project.name + '.json');
......
......@@ -22,9 +22,12 @@
</el-form-item>-->
</el-form>
<div slot="footer" class="dialog-footer">
<div></div>
<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>
</el-dialog>
</template>
......
......@@ -6,9 +6,12 @@
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<div></div>
<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>
</el-dialog>
</template>
......
......@@ -55,6 +55,7 @@
</el-pagination>
</div>
<div slot="footer" class="dialog-footer">
<div></div>
<el-button size="mini" @click="visible=false">{{$t('Cancel')}}</el-button>
</div>
</el-dialog>
......
<template>
<div class="wrapper">
<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>
</template>
<script>
import {applyMock} from "./Preview/mock-serve";
import db from "../utils/db-storage";
import {newScriptEl} from "../utils";
import {newScriptContent, newScriptEl} from "../utils";
export default {
name: "Preview",
......@@ -16,6 +27,7 @@
return {
ts: '',
flag: false,
proxyReady: true,
}
},
async mounted() {
......@@ -43,6 +55,13 @@
this.buildPage();
}, 300);
},
onCommand(command) {
switch (command) {
case 'refresh':
this.reload();
break;
}
},
onVisibilityChange(e) {
if (!document.hidden) {
let ts = localStorage.getItem('preview-ts');
......@@ -56,6 +75,9 @@
}
},
async buildPage() {
if (!this.proxyReady) {
return;
}
const {projectID} = this.$route.params;
const {data, codes} = await db.get('preview', projectID);
......@@ -77,6 +99,7 @@
}
scripts.push(newScriptEl(url));
}
scripts.push(newScriptContent('var proxy_mode=true;'));
this.codes = codes;
const dataUrl = URL.createObjectURL(new Blob([JSON.stringify(data)]));
......@@ -93,8 +116,16 @@
const win = this.$refs.iframe.contentWindow;
doc.write(tpl);
//win.proxy_window = this.$refs.proxyIframe.contentWindow;
applyMock(projectID, win);
},
onProxyIframeLoaded() {
this.proxyReady = true;
//this.$refs.proxyIframe.contentWindow.postMessage('hello', '*');
this.buildPage();
},
}
}
</script>
......@@ -103,12 +134,20 @@
.wrapper {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.side-bar {
position: absolute;
right: 3px;
bottom: 3px;
}
.player-wrapper {
border: 0;
width: 100%;
height: 100%;
flex: 1;
}
.mock-button {
......@@ -116,4 +155,12 @@
right: 10px;
bottom: 10px;
}
#proxyIframe {
/*display: none;*/
position: absolute;
top: 0;
width: 100px;
height: 100px;
}
</style>
\ No newline at end of file
......@@ -12,7 +12,7 @@ module.exports = {
enableInSFC: true
}
},
/*devServer: {
devServer: {
host: '0.0.0.0',
port: '8080',
proxy: {
......@@ -22,8 +22,11 @@ module.exports = {
'/api': {
target: serverHost,
},
'polaris': {
target: serverHost
}
},*/
}
},
configureWebpack: {
plugins: [
new MonacoWebpackPlugin({
......
......@@ -2271,7 +2271,7 @@ color-string@^1.5.2:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^3.0.0:
color@^3.0.0, color@^3.1.2:
version "3.1.2"
resolved "https://registry.npm.taobao.org/color/download/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
integrity sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=
......@@ -2566,6 +2566,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
crypto-js@^3.1.9-1:
version "3.1.9-1"
resolved "https://registry.npm.taobao.org/crypto-js/download/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8"
integrity sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
......@@ -2799,7 +2804,7 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
dependencies:
ms "^2.1.1"
debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5:
version "3.2.6"
resolved "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha1-6D0X3hbYp++3cX7b5fsQE17uYps=
......@@ -2828,11 +2833,6 @@ deep-equal@^1.0.1:
object-keys "^1.1.1"
regexp.prototype.flags "^1.2.0"
deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.npm.taobao.org/deep-extend/download/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
......@@ -2956,11 +2956,6 @@ destroy@^1.0.4, destroy@~1.0.4:
resolved "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
detect-libc@^1.0.2:
version "1.0.3"
resolved "https://registry.npm.taobao.org/detect-libc/download/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
detect-node@^2.0.4:
version "2.0.4"
resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
......@@ -3761,13 +3756,6 @@ fs-extra@^7.0.1:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^1.2.5:
version "1.2.7"
resolved "https://registry.npm.taobao.org/fs-minipass/download/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
integrity sha1-zP+FcIQef+QmVpPaiJNsVa7X98c=
dependencies:
minipass "^2.6.0"
fs-write-stream-atomic@^1.0.8:
version "1.0.10"
resolved "https://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
......@@ -4333,7 +4321,7 @@ humanize-ms@^1.2.0, humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
iconv-lite@0.4.24, iconv-lite@^0.4.15, iconv-lite@^0.4.4:
iconv-lite@0.4.24, iconv-lite@^0.4.15:
version "0.4.24"
resolved "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=
......@@ -4362,13 +4350,6 @@ iferr@^0.1.5:
resolved "https://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
ignore-walk@^3.0.1:
version "3.0.3"
resolved "https://registry.npm.taobao.org/ignore-walk/download/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
integrity sha1-AX4kRxhL/q3nwjjkrv3R6PlbHjc=
dependencies:
minimatch "^3.0.4"
ignore@^3.3.5:
version "3.3.10"
resolved "https://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
......@@ -4474,11 +4455,6 @@ inherits@2.0.3:
resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz?cache=0&sync_timestamp=1560975547815&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finherits%2Fdownload%2Finherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@~1.3.0:
version "1.3.5"
resolved "https://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=
internal-ip@^4.3.0:
version "4.3.0"
resolved "https://registry.npm.taobao.org/internal-ip/download/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
......@@ -5454,21 +5430,6 @@ minimist@~0.0.1:
resolved "https://registry.npm.taobao.org/minimist/download/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
version "2.9.0"
resolved "https://registry.npm.taobao.org/minipass/download/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
integrity sha1-5xN2Ln0+Mv7YAxFc+T4EvKn8yaY=
dependencies:
safe-buffer "^5.1.2"
yallist "^3.0.0"
minizlib@^1.2.1:
version "1.3.3"
resolved "https://registry.npm.taobao.org/minizlib/download/minizlib-1.3.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminizlib%2Fdownload%2Fminizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
integrity sha1-IpDeloGKNMKVUcio0wEha9Zahh0=
dependencies:
minipass "^2.9.0"
mississippi@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/mississippi/download/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f"
......@@ -5615,15 +5576,6 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
needle@^2.2.1:
version "2.4.0"
resolved "https://registry.npm.taobao.org/needle/download/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
integrity sha1-aDPnSXXERGQlkOFadQKIxfk5tXw=
dependencies:
debug "^3.2.6"
iconv-lite "^0.4.4"
sax "^1.2.4"
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
......@@ -5712,22 +5664,6 @@ node-libs-browser@^2.2.1:
util "^0.11.0"
vm-browserify "^1.0.1"
node-pre-gyp@*:
version "0.14.0"
resolved "https://registry.npm.taobao.org/node-pre-gyp/download/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
integrity sha1-mgWWUzuHcom8rU4UOYLKPZBN3IM=
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4.4.2"
node-releases@^1.1.44:
version "1.1.44"
resolved "https://registry.npm.taobao.org/node-releases/download/node-releases-1.1.44.tgz?cache=0&sync_timestamp=1577231700151&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-releases%2Fdownload%2Fnode-releases-1.1.44.tgz#cd66438a6eb875e3eb012b6a12e48d9f4326ffd7"
......@@ -5765,14 +5701,6 @@ node-sass@^4.9.2:
dependencies:
abbrev "1"
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.npm.taobao.org/nopt/download/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
dependencies:
abbrev "1"
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
......@@ -5820,26 +5748,6 @@ normalize-wheel@^1.0.1:
resolved "https://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=
npm-bundled@^1.0.1:
version "1.1.1"
resolved "https://registry.npm.taobao.org/npm-bundled/download/npm-bundled-1.1.1.tgz?cache=0&sync_timestamp=1575936189080&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnpm-bundled%2Fdownload%2Fnpm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
integrity sha1-Ht1XCGWpTNsbyCIHdeKUZsn7I0s=
dependencies:
npm-normalize-package-bin "^1.0.1"
npm-normalize-package-bin@^1.0.1:
version "1.0.1"
resolved "https://registry.npm.taobao.org/npm-normalize-package-bin/download/npm-normalize-package-bin-1.0.1.tgz?cache=0&sync_timestamp=1575936190670&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnpm-normalize-package-bin%2Fdownload%2Fnpm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
integrity sha1-bnmkHyP9I1wGIyGCKNp9nCO49uI=
npm-packlist@^1.1.6:
version "1.4.7"
resolved "https://registry.npm.taobao.org/npm-packlist/download/npm-packlist-1.4.7.tgz#9e954365a06b80b18111ea900945af4f88ed4848"
integrity sha1-npVDZaBrgLGBEeqQCUWvT4jtSEg=
dependencies:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz?cache=0&sync_timestamp=1577053500910&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnpm-run-path%2Fdownload%2Fnpm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
......@@ -5854,7 +5762,7 @@ npm-run-path@^4.0.0:
dependencies:
path-key "^3.0.0"
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0:
version "4.1.2"
resolved "https://registry.npm.taobao.org/npmlog/download/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=
......@@ -5905,6 +5813,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
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:
version "1.7.0"
resolved "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
......@@ -6097,7 +6010,7 @@ os-tmpdir@^1.0.0:
resolved "https://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
osenv@0, osenv@^0.1.4:
osenv@0:
version "0.1.5"
resolved "https://registry.npm.taobao.org/osenv/download/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha1-hc36+uso6Gd/QW4odZK18/SepBA=
......@@ -6902,6 +6815,14 @@ prr@~1.0.1:
resolved "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
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:
version "1.0.2"
resolved "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
......@@ -7047,16 +6968,6 @@ raw-body@^2.2.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
rc@^1.2.7:
version "1.2.8"
resolved "https://registry.npm.taobao.org/rc/download/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0=
dependencies:
deep-extend "^0.6.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-1.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg-up%2Fdownload%2Fread-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
......@@ -7464,7 +7375,7 @@ sass@^1.22.9:
dependencies:
chokidar ">=2.0.0 <4.0.0"
sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4:
sax@>=0.6.0, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha1-KBYjTiN4vdxOU1T6tcqold9xANk=
......@@ -8152,11 +8063,6 @@ strip-indent@^1.0.1:
dependencies:
get-stdin "^4.0.1"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
stylehacks@^4.0.0:
version "4.0.3"
resolved "https://registry.npm.taobao.org/stylehacks/download/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
......@@ -8230,19 +8136,6 @@ tar@^2.0.0:
fstream "^1.0.12"
inherits "2"
tar@^4.4.2:
version "4.4.13"
resolved "https://registry.npm.taobao.org/tar/download/tar-4.4.13.tgz?cache=0&sync_timestamp=1570258601713&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftar%2Fdownload%2Ftar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
integrity sha1-Q7NkvFKIjVVSmGN7ENYHkCVKtSU=
dependencies:
chownr "^1.1.1"
fs-minipass "^1.2.5"
minipass "^2.8.6"
minizlib "^1.2.1"
mkdirp "^0.5.0"
safe-buffer "^5.1.2"
yallist "^3.0.3"
terser-webpack-plugin@^1.2.3, terser-webpack-plugin@^1.4.3:
version "1.4.3"
resolved "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.4.3.tgz?cache=0&sync_timestamp=1576580745773&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
......@@ -9157,7 +9050,7 @@ yallist@^2.1.2:
resolved "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=
......
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