Commit e8227960 authored by rockyl's avatar rockyl

重构

增加mvvm实现
parent 34bbb913
<template>
<el-form class="props-editor" v-if="data&&meta" v-model="data.props" size="mini" :label-width="labelWidth"
<el-form class="props-editor" v-if="data&&meta" v-model="data" size="mini" :label-width="labelWidth"
label-position="right" @submit.native.prevent>
<component v-for="(property, key) in meta.props"
:key="key"
:is="mode + '-input-wrapper'"
:editable="editable"
:switchable="switchable"
:mode="mode"
:value="data[key]"
:container="data"
:property="property"
:propertyName="key"
@cmd-prop-change="onCmdPropChanged"
>
<component
:is="getInput(property)"
:container="data.props"
:value="data.props[key]"
:container="data"
:value="data[key]"
:propertyName="key"
:property="property"
:key="key"
:editable="editable"
:linkable="linkable"
@input="onInput"
/>
</component>
</el-form>
</template>
......@@ -19,6 +31,7 @@
import {
NumberInput,
StringInput,
TextInput,
EnumInput,
BooleanInput,
ColorInput,
......@@ -27,12 +40,17 @@
MapInput,
DynamicInput,
Vector2Input,
SourceInput,
} from "./inputs";
import {parseType} from 'props-compute'
import LinkableInputWrapper from "./inputs/LinkableInputWrapper";
import CmdInputWrapper from "./inputs/CmdInputWrapper";
import SampleInputWrapper from "./inputs/SampleInputWrapper";
const inputMapping = {
number: 'NumberInput',
string: 'StringInput',
text: 'TextInput',
enum: 'EnumInput',
boolean: 'BooleanInput',
color: 'ColorInput',
......@@ -42,11 +60,13 @@
map: 'MapInput',
vector2: 'Vector2Input',
array: 'StringInput',
source: 'SourceInput',
};
export default {
name: "PropsEditor",
components: {
SourceInput,
DynamicInput,
MapInput,
NodeSelectInput,
......@@ -56,10 +76,16 @@
EnumInput,
NumberInput,
StringInput,
Vector2Input
TextInput,
Vector2Input,
LinkableInputWrapper,
CmdInputWrapper,
SampleInputWrapper,
},
data() {
return {}
return {
}
},
props: {
labelWidth: {
......@@ -70,10 +96,14 @@
type: Boolean,
default: true
},
linkable: {
switchable: {
type: Boolean,
default: false
},
mode: {
type: String,
default: 'sample',
},
data: {
type: Object,
},
......@@ -81,6 +111,11 @@
type: Object,
},
},
watch: {
data(v){
}
},
methods: {
getInput(property) {
let {type} = parseType(property.type);
......@@ -92,6 +127,10 @@
} else {
this.$set(container, propName, value);
}
this.$emit('input', value, container, propName, oldValue);
},
onCmdPropChanged(value, container, propName, oldValue){
this.$emit('input', value, container, propName, oldValue);
},
}
}
......
<template>
<el-select v-model="selected" :filterable="filterable" allow-create placeholder="请选择">
<el-option
v-for="item in props"
:style="`${optionStyle}${item.value}`"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
<script>
import optionMapper from './optionMapper';
export default {
props: {
/*
* fontFamily: 字体
* fontSize: 字体大小选择列表
* borderStyle: 边框类型
* animeCount: 动效次数
*/
optionType: {
type: String,
default: 'fontSize'
},
optionList: Array, // 若有 optionList 则groupType 不起作用
value: [String, Number, Boolean],
filterable: Boolean
},
data() {
return {
selected: this.value || '',
optionMapper
};
},
computed: {
props() {
return this.optionList || this.optionMapper[this.optionType];
},
optionStyle() {
return this.optionType === 'fontFamily' ? 'font-family: ' : '';
}
},
watch: {
selected(v) {
this.$emit('change', v);
}
}
};
</script>
import _ from 'lodash'
const rangeStep = (start, step, stop) =>
_.map(
_.range(0, (1 + (stop - start) / step) >>> 0),
(n) => (start + step * n).toFixed(0),
);
export default {
fontFamily: [
{
label: '默认字体',
value: ''
},
{ label: '微软雅黑', value: 'Microsoft Yahei' },
// { label: '方正黑体简体', value: 'FZHei-B01S' },
// { label: '方正楷体简体', value: 'FZKai-Z03S' },
// { label: '方正书宋简体', value: 'FZShuSong-Z01S' },
// { label: '方正仿宋简体', value: 'FZFangSong-Z02S' },
// { label: '思源极细体', value: 'NotoSansSC-Thin' },
// { label: '思源细体', value: 'NotoSansSC-Light' },
// { label: '思源正常', value: 'NotoSansSC-DemiLight' },
// { label: '思源常规', value: 'NotoSansSC-Regular' },
// { label: '思源中等粗体', value: 'NotoSansSC-Medium' },
// { label: '思源粗体', value: 'NotoSansSC-Bold' },
// { label: '思源特粗', value: 'NotoSansSC-Black' },
{ label: '宋体', value: 'SimSun' },
// { label: '黑体', value: 'SimHei' },
{ label: 'fantasy', value: 'fantasy' },
{ label: 'Cursive', value: 'Cursive' }
],
borderStyle: [
{ label: '实线', value: 'solid' },
{ label: '点线', value: 'dotted' },
{ label: '虚线', value: 'dashed' },
{ label: '双线', value: 'double' }
],
backgroundSize: [
{ label: '全覆盖', value: 'cover' },
{ label: '完全显示图片', value: 'contain' }
],
backgroundRepeat: [
{ label: '显示一次', value: 'no-repeat' },
{ label: '重复', value: 'repeat' },
{ label: '水平方向重复', value: 'repeat-x' },
{ label: '垂直方向重复', value: 'repeat-y' }
],
backgroundPosition: [
{ label: '居中', value: 'center' },
{ label: '左上', value: 'top left' },
{ label: '顶部居中', value: 'top center' },
{ label: '右上', value: 'top right' },
{ label: '靠左', value: 'center left' },
{ label: '靠右', value: 'center right' },
{ label: '左下', value: 'bottom left' },
{ label: '底部居中', value: 'bottom center' },
{ label: '右下', value: 'bottom right' }
],
weekIndex: [
{ label: '周日', value: 0 },
{ label: '周一', value: 1 },
{ label: '周二', value: 2 },
{ label: '周三', value: 3 },
{ label: '周四', value: 4 },
{ label: '周五', value: 5 },
{ label: '周六', value: 6 }
],
fontSize: rangeStep(12, 1, 120).map((v) => ({ value: v, label: v })),
animeCount: rangeStep(1, 1, 10)
.map((v) => ({ value: v, label: v }))
.concat({ label: '无限循环', value: true })
};
<template>
<el-slider class="zero-slider" v-model="swvalue" :min="min" :max="max" :step="step" show-input :show-input-controls="false" input-size="mini"></el-slider>
</template>
<style>
/* .zero-slider > .el-slider__input > span {
display: none;
}
.zero-slider > .el-slider__input input {
padding: 0 10px;
} */
/* .zero-slider {
position: relative;
}
.zero-slider > .el-slider__input {
position: absolute;
left: 110%;
top: -250%;
width: 60px;
}
.zero-slider > .el-slider__input input {
padding: 0 10px;
} */
</style>
<script>
export default {
props: {
min: Number,
max: Number,
value: [String, Number, Boolean],
step: Number
},
data() {
return {
swvalue: this.value || 0
};
},
watch: {
swvalue(v) {
this.$emit('change', v);
}
}
};
</script>
<template>
<el-switch v-model="swvalue"></el-switch>
</template>
<style>
</style>
<script>
export default {
props: {
value: [String, Number, Boolean],
},
data() {
return {
swvalue: true
};
},
mounted() {
console.log('switch created', this.swvalue);
},
watch: {
swvalue(v) {
console.log('switch value change', this.swvalue);
this.$emit('change', v);
}
}
};
</script>
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<component :is="mode + '-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"
......@@ -9,17 +9,18 @@
<span>{{item.name}}</span>
</el-option>
</el-select>
</input-wrapper>
</component>
</template>
<script>
import {mapMutations} from 'vuex'
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
export default {
name: "AssetInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
<template>
<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>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
export default {
name: "BooleanInput",
components: {InputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {}
},
......
<template>
<el-form-item class="input-wrapper" :label="propertyName" content-float="right"
:content-width="contentWidth" :labelOffsetTop="labelOffsetTop">
<el-tooltip placement="left" class="label" slot="label" trigger="hover" :open-delay="500" :enterable="false">
<div slot="content" class="property-name-popover">
<p>{{$t('Alias')}}{{property.alias}}</p>
<p>{{$t('Name')}}{{propertyName}}</p>
</div>
<div>
<p class="alias">{{property.alias||propertyName}}</p>
<p class="property-name">{{propertyName}}</p>
</div>
</el-tooltip>
<template v-if="cmdMode">
<el-input class="cmd-input" placeholder="exp" :value="cmdValue" @input="onInputCmdValue"
@change="saveCmdValue"></el-input>
</template>
<template v-else>
<slot></slot>
</template>
<el-link style="padding: 3px;" icon="el-icon-link" :underline="false"
v-if="switchable"
:type="cmdMode ? 'success' : 'default'" :disabled="!editable" @click="onClickLink"/>
</el-form-item>
</template>
<script>
import ElFormItem from "./form-item";
import {cmdOldPrefix, cmdPrefix} from "../../utils";
export default {
name: "CmdInputWrapper",
components: {ElFormItem},
props: {
property: Object,
value: {},
container: {},
propertyName: String,
editable: Boolean,
switchable: Boolean,
contentWidth: {
type: String,
default: '65%',
},
labelOffsetTop: {
type: Number,
default: 0,
},
},
data() {
return {
//cmdValue: this.container[this.cmdPropName] || '',
}
},
watch: {
container(v) {
//this.cmdValue = this.container[this.cmdPropName] || '';
},
},
computed: {
cmdValue() {
return this.container[this.cmdPropName] || '';
},
cmdMode() {
return this.container.hasOwnProperty(this.cmdPropName);
},
cmdPropName() {
return cmdPrefix + this.propertyName;
},
cmdOldPropName() {
return cmdOldPrefix + this.propertyName;
},
},
methods: {
onClickLink() {
if (this.cmdMode) {
this.$set(this.container, this.cmdOldPropName, this.cmdValue);
this.$delete(this.container, this.cmdPropName);
} else {
let cmdValue = this.container[this.cmdOldPropName] || '';
this.$set(this.container, this.cmdPropName, cmdValue);
}
},
onInputCmdValue(v) {
this.container[this.cmdPropName] = v;
},
saveCmdValue(v) {
let oldValue = this.container[this.cmdPropName];
//this.cmdValue = v;
this.$set(this.container, this.cmdPropName, v);
this.$emit('cmd-prop-change', v, this.container, this.cmdPropName, oldValue);
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<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"
......@@ -8,16 +7,16 @@
show-alpha
:predefine="predefineColors">
</el-color-picker>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
export default {
name: "ColorInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {
predefineColors: [
......
<template>
<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"
:container="container"
:property="property"
:propertyName="propertyName"/>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import DynamicSelector from "./DynamicSelector";
export default {
name: "DynamicInput",
components: {DynamicSelector, InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {DynamicSelector, LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
methods: {
onChange(v){
this.$emit('input', v, this.container, this.propertyName, this.value);
......
......@@ -28,7 +28,7 @@
export default {
name: "DynamicSelector",
components: {},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
let dataTypes = this.$t('dataTypes');
return {
......
<template>
<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"
:key="item"
:label="item"
:value="item">
<span>{{item}}</span>
<span class="comment"></span>
:key="key"
:label="typeof item === 'object' ? item.label : item"
:value="typeof item === 'object' ? item.value : item">
<span>{{typeof item === 'object' ? item.label : item}}</span>
<span class="enum-input-comment">{{typeof item === 'object' ? item.value : item}}</span>
</el-option>
</el-select>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
export default {
name: "EnumInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
<template>
<el-form-item class="input-wrapper" :label="propertyName" content-float="right"
:content-width="contentWidth" :labelOffsetTop="labelOffsetTop">
<el-tooltip placement="top" class="label" slot="label" trigger="hover" :open-delay="500" :enterable="false">
<el-tooltip placement="left" class="label" slot="label" trigger="hover" :open-delay="500" :enterable="false">
<div slot="content" class="property-name-popover">
<p>{{$t('Alias')}}{{property.alias}}</p>
<p>{{$t('Name')}}{{propertyName}}</p>
......@@ -18,7 +18,7 @@
<slot></slot>
</template>
<el-popover
v-if="linkable"
v-if="switchable"
trigger="click"
:disabled="!editable"
>
......@@ -42,7 +42,7 @@
import ElFormItem from "./form-item";
export default {
name: "InputWrapper",
name: "LinkableInputWrapper",
components: {ElFormItem},
props: {
property: Object,
......@@ -50,7 +50,7 @@
container: {},
propertyName: String,
editable: Boolean,
linkable: Boolean,
switchable: Boolean,
contentWidth: {
type: String,
default: '65%',
......
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
popper-class="input-area-popover"
......@@ -33,18 +31,18 @@
<el-button icon="el-icon-delete" @click="onClickClean" :disabled="!editable"></el-button>
</el-button-group>
</div>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {getInputDefaultValue} from "../../utils";
import DynamicSelector from "./DynamicSelector";
export default {
name: "MapInput",
components: {DynamicSelector, InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {DynamicSelector, LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
let dataTypes = this.$t('dataTypes');
return {
......
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
placement="top"
......@@ -53,18 +51,18 @@
<el-button icon="el-icon-delete" @click="onClickClean" :disabled="!editable"></el-button>
</el-button-group>
</div>
</input-wrapper>
</template>
<script>
import {mapGetters} from "vuex";
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {nodeScheme} from "../../utils";
export default {
name: "NodeSelectInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {
nodeScheme: nodeScheme,
......
<template>
<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"
<el-input-number :disabled="!editable" :value="editValue" @change="onInput" controls-position="right"
:placeholder="defaultValue"></el-input-number>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {getInputDefaultValue} from "../../utils";
export default {
name: "NumberInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
computed: {
editValue() {
return this.value === undefined ? this.property.default : this.value;
......
<template>
<el-form-item class="input-wrapper" :label="propertyName" content-float="right"
:content-width="contentWidth" :labelOffsetTop="labelOffsetTop">
<el-tooltip placement="left" class="label" slot="label" trigger="hover" :open-delay="500" :enterable="false">
<div slot="content" class="property-name-popover">
<p>{{$t('Alias')}}{{property.alias}}</p>
<p>{{$t('Name')}}{{propertyName}}</p>
</div>
<div>
<p class="alias">{{property.alias||propertyName}}</p>
<p class="property-name">{{propertyName}}</p>
</div>
</el-tooltip>
<template>
<slot></slot>
</template>
</el-form-item>
</template>
<script>
import camelcase from 'camelcase'
import ElFormItem from "./form-item";
export default {
name: "SampleInputWrapper",
components: {ElFormItem},
props: {
property: Object,
value: {},
container: {},
propertyName: String,
editable: Boolean,
switchable: Boolean,
contentWidth: {
type: String,
default: '65%',
},
labelOffsetTop: {
type: Number,
default: 0,
},
},
data() {
return {}
},
watch: {
},
computed: {
},
methods: {
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -5,70 +5,90 @@
width="auto"
:disabled="!legalUrl"
:content="url"
class="source-input"
>
<img style="max-width: 200px;" v-if="url" :src="url" alt=""/>
<el-input v-model="swvalue" slot="reference" @drop.native="drop" @dragover.native="dragOver">
<el-input slot="reference" :disabled="!editable" v-model="editValue" controls-position="right" :placeholder="defaultValue"
@change="onChange" @drop.native="drop" @dragover.native="dragOver">
<el-button slot="append" icon="el-icon-aim" @click="locateAsset"></el-button>
</el-input>
</el-popover>
</template>
<style>
</style>
<script>
import {mapGetters} from 'vuex'
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {assetScheme, getInputDefaultValue} from "../../utils";
import events from "@/global-events.js"
import {assetScheme} from "../../../utils";
export default {
props: {
value: [String, Number, Boolean]
},
data() {
name: "SourceInput",
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data(){
return {
swvalue: this.value || ''
};
editValue: this.getEditValue(),
}
},
mounted(){
this.editValue = this.getEditValue();
},
watch: {
swvalue(v) {
this.$emit('change', v);
computed: {
defaultValue(){
return getInputDefaultValue(this.property);
},
url: function () {
if (this.value) {
if (this.value.indexOf(assetScheme) > -1) {
let uuid = this.value.replace(assetScheme, '');
let _ass = this.assets.find(a => a.uuid === uuid);
return _ass ? _ass.url : '';
} else {
return this.value;
}
} else {
return '';
}
},
legalUrl: function () {
return this.value && this.value.startsWith(assetScheme);
},
...mapGetters(['assets']),
},
methods: {
getEditValue() {
return this.value === undefined ? this.property.default : this.value;
},
onChange(v) {
if(v !== this.value){
this.$emit('input', v, this.container, this.propertyName, this.value);
}
},
drop(e) {
if (this.$store.state.project.dragUUID) {
console.log('native drop', this.$store.state);
this.swvalue = assetScheme + this.$store.state.project.dragUUID
this.onChange(assetScheme + this.$store.state.project.dragUUID)
}
},
dragOver(e) {
if(this.editable){
e.preventDefault();
}
},
locateAsset() {
let uuid = this.swvalue ? this.swvalue.split('//')[1] : null;
let uuid = this.value ? this.value.replace(assetScheme, '') : null;
if (uuid) {
let asset = this.$store.state.project.data.assets.find(a => a.uuid === uuid);
let asset = this.assets.find(a => a.uuid === uuid);
if (asset) {
events.$emit('select-asset-item', asset);
}
}
}
},
computed: {
url: function () {
if (this.swvalue) {
if (this.swvalue.indexOf(assetScheme) > -1) {
let uuid = this.swvalue.split('//')[1];
let _ass = this.$store.state.project.data.assets.find(a => a.uuid === uuid);
return _ass ? _ass.url : '';
} else {
return this.swvalue;
}
} else {
return '';
}
},
legalUrl: function () {
return (this.swvalue + '').indexOf('//') > -1;
}
}
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property" :propertyName="propertyName">
<div style="display: flex;flex: 1;">
<el-popover
placement="top"
......@@ -34,17 +33,17 @@
<el-button icon="el-icon-delete" @click="onClickClean" :disabled="!editable"></el-button>
</el-button-group>
</div>
</input-wrapper>
</template>
<script>
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {getInputDefaultValue} from "../../utils";
export default {
name: "StringInput",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {
editValueOrigin: this.value,
......
<template>
<div style="display: flex;flex: 1;">
<el-input :value="value" readonly/>
</div>
</template>
<script>
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
import {getInputDefaultValue} from "../../utils";
export default {
name: "TextInput",
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {
}
},
computed: {
},
watch: {
},
methods: {
},
}
</script>
<style scoped>
.bottom-bar {
margin-top: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
</style>
<template>
<input-wrapper :editable="editable" :linkable="linkable" :value="value" :container="container" :property="property"
:propertyName="propertyName">
<div>
<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>
</div>
</template>
<script>
import {parseVector2} from "props-compute";
import InputWrapper from "./InputWrapper";
import LinkableInputWrapper from "./LinkableInputWrapper";
import CmdInputWrapper from "./CmdInputWrapper";
export default {
name: "Vector2Input",
components: {InputWrapper,},
props: ['value', 'container', 'property', 'propertyName', 'editable', 'linkable'],
components: {LinkableInputWrapper, CmdInputWrapper},
props: ['value', 'container', 'property', 'propertyName', 'editable'],
data() {
return {
editValue: {},
......
......@@ -4,6 +4,7 @@
export {default as NumberInput} from './NumberInput';
export {default as StringInput} from './StringInput';
export {default as TextInput} from './TextInput';
export {default as EnumInput} from './EnumInput';
export {default as BooleanInput} from './BooleanInput';
export {default as ColorInput} from './ColorInput';
......@@ -12,3 +13,4 @@ export {default as NodeSelectInput} from './NodeSelectInput';
export {default as MapInput} from './MapInput';
export {default as DynamicInput} from './DynamicInput';
export {default as Vector2Input} from './Vector2Input';
export {default as SourceInput} from './SourceInput';
......@@ -6,11 +6,11 @@ export let API_HOST;
if (process.env.NODE_ENV === 'development') {
//API_HOST = '//10.10.95.74:7777';
//API_HOST = '//192.168.1.16:7777';
API_HOST = '//10.10.93.88:7777';
//API_HOST = '//10.10.93.88:7777';
//API_HOST = '//192.168.0.105:7777';
//API_HOST = '//localhost:3002';
//API_HOST = window.__data.apiHost;
//API_HOST = '';
API_HOST = 'http://beacon.duiba.com.cn';
} else {
API_HOST = window.__data.apiHost;
}
......@@ -23,7 +23,7 @@ export const SSO_VERIFY_PAGE_URL = '/sso/logout';
export const DOCK_POINT_OFFSET = 4;
export const PROJECT_PAGE_SIZE = 10;
export const PROJECT_PAGE_SIZE = 20;
export const HISTORY_PAGE_SIZE = 20;
//文件类型图标 t表示展示缩略图
......
......@@ -216,6 +216,11 @@
"Are you sure to transform process?": "你确定将此转化为{inlineType}过程吗?",
"Input custom process name": "请输入自定义过程名称",
"Invalid name": "无效名称",
"Store editor": "数据编辑器",
"Store": "数据",
"Operate": "操作",
"Computed": "计算属性",
"Are you sure to close?": "确定关闭吗?",
"eventGroup": {
"in": "接收",
"out": "派发"
......@@ -357,5 +362,8 @@
"rename": "重命名",
"replace": "替换",
"combine": "合并"
},
"customCmds": {
"z-for": "循环"
}
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ export const editorStore = {
state: {
initialized: false,
name: 'Zeroing Editor',
version: '1.0.3',
version: '0.1.0',
templates: {
builtin: ['blank'],
custom: [],
......
......@@ -246,7 +246,7 @@ export const projectStore = {
if (view.type) {
// view.type有值说明修改了节点的类型
// 如果修改了节点类型,需要删除无用的属性
let defaultProps = Object.keys(getCmpProps(view.type));
let defaultProps = Object.keys(getCmpProps(view.type).props);
_.forIn(newView.properties, (value, key) => {
if (defaultProps.indexOf(key) === -1) {
......@@ -481,6 +481,11 @@ export const projectStore = {
setMockServeEnabled(state, enabled) {
state.mockServeEnabled = enabled;
},
modifyViewStore(state, {view, store}){
view.store = store;
this.commit('makeProjectDirty');
}
},
getters: {
......@@ -676,15 +681,25 @@ export const projectStore = {
return getTopView(node.parent);
}
};
let _view = getTopView(data.node);
if (!data.fromPlayground) {
// 点击视图区域选中节点
// 则需要切换当前节点所在的最顶层视图
let _view = getTopView(data.node);
if (_view && _view.data) {
context.state.activeViews = _view.data.uuid;
}
}
if(_view.data === data.data){
if(!data.data.hasOwnProperty('$isRootView')){
Object.defineProperty(data.data, '$isRootView', {
get(){
return true;
}
})
}
}
context.commit('activeComponent', data.data);
},
/**
......
......@@ -473,7 +473,16 @@ $dock-pin-width: 9px;
}
}
.source-input{
flex: 1;
}
.node-select-container {
flex: 1;
}
}
.enum-input-comment{
float: right;
color: $--color-text-secondary;
}
......@@ -47,6 +47,38 @@
background-color: $--pane-background-color;
}
.package-list{
display: flex;
flex-direction: column;
.list {
display: flex;
flex-direction: column;
flex: 1;
margin-bottom: 5px;
.item + .item {
}
.item {
display: flex;
align-items: center;
padding-top: 5px;
&:hover {
& > .delete-button {
visibility: visible;
}
}
&:nth-child(odd){
background-color: #FAFAFA;
}
}
}
}
.mapping-list {
display: flex;
flex-direction: column;
......@@ -309,6 +341,43 @@
}
}
.store-editor-dialog {
.wrapper {
height: 50vh;
.tabs {
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__content {
flex: 1;
& > div {
height: 100%;
}
.editor {
height: 100%;
}
.computed-editor{
.editor{
height: 200px;
}
}
}
}
}
.dialog-footer{
.save-button{
margin-left: 10px;
}
}
}
.px-publish-view {
display: flex;
flex-direction: column;
......
......@@ -76,8 +76,12 @@
line-height: 30px;
}
.el-collapse-item__content{
padding-bottom: 5px;
}
.el-tabs--border-card > .el-tabs__content {
padding: 5px 0 5px 5px;
padding: 5px;
}
.el-input-number.is-controls-right .el-input__inner {
......@@ -98,3 +102,12 @@
padding: 3px;
align-self: center;
}
.el-tabs__item {
height: 25px;
line-height: 25px;
}
.el-tab-pane {
height: 100%;
}
......@@ -6,45 +6,42 @@
display: flex;
flex-direction: column;
&>:last-child{
& > :last-child {
flex: 1;
height: 0;
}
.el-tabs__item {
height: 25px;
line-height: 25px;
}
.el-tab-pane{
height: 100%;
}
.zero-inspector-props-form {
height: 100%;
.el-form{
padding-right: 10px;
.form {
height: 100%;
display: flex;
flex-direction: column;
}
.el-input-number.el-input-number--mini, .el-select.el-select--mini {
width: 100%;
.top-bar {
padding: 5px;
}
.el-slider.zero-slider {
width: 180px;
.scrollbar {
flex: 1;
margin-right: -5px;
}
.zero-slider .el-slider__runway.show-input {
width: 100px;
.all-form {
padding-right: 10px;
}
.zero-slider > .el-slider__input {
width: 60px;
.cmd-input {
.el-input__inner {
color: $--color-primary;
}
}
.scrollbar{
height: 100%;
.add-item-bar {
padding: 10px 0;
text-align: center;
}
}
......@@ -53,11 +50,11 @@
display: flex;
flex-direction: column;
.add-trigger{
.add-trigger {
align-self: flex-start;
}
.scrollbar{
.scrollbar {
margin-top: 5px;
height: 100%;
}
......@@ -66,7 +63,7 @@
margin-left: 5px;
}
.trigger-list{
.trigger-list {
color: $--color-text-regular;
font-size: 12px;
padding-right: 10px;
......@@ -74,21 +71,22 @@
.trigger-item + .trigger-item {
margin-top: 5px;
}
.trigger-item {
border: 1px solid lightgray;
border-radius: 3px;
padding: 3px;
.el-button{
.el-button {
padding: 3px;
}
.top-bar{
.top-bar {
display: flex;
justify-content: space-between;
align-items: center;
.name{
.name {
color: $--color-primary;
font-size: 14px;
font-weight: bold;
......@@ -111,12 +109,12 @@
align-items: center;
margin-top: 2px;
.name-field{
.name-field {
flex: 1;
margin-left: 3px;
}
.missing-behavior{
.missing-behavior {
color: $--color-danger;
}
......
......@@ -161,7 +161,7 @@ function completeSelfProps(component) {
let defaultProps = getCmpProps(component.type);
// 把这些属性格式转换成key: value
defaultProps = _.mapValues(defaultProps, o => (o.value));
defaultProps = _.mapValues(defaultProps.props, o => (o.default));
return _.merge(defaultProps, component.properties);
}
......@@ -320,26 +320,25 @@ export const styles = {
}
}
const cmpPropsCache = {};
const cmpMetaCache = {};
export function getCmpProps(type) {
if (!type) {
return {}
} else {
let cmpProps = cmpPropsCache[type];
let cmpProps = cmpMetaCache[type];
if (cmpProps) {
cmpProps = _.cloneDeep(cmpProps);
} else {
let typeProps = properties[type];
let inherits = [_.cloneDeep(typeProps)];
while (typeProps.base) {
typeProps = cmpPropsCache.hasOwnProperty(typeProps.base) ? cmpPropsCache[typeProps.base] : properties[typeProps.base];
inherits.unshift(_.cloneDeep(typeProps));
let typeMeta = _.cloneDeep(properties[type]);
let inherits = [typeMeta.props];
let tempMeta = typeMeta;
while (tempMeta.base) {
tempMeta = cmpMetaCache.hasOwnProperty(tempMeta.base) ? cmpMetaCache[tempMeta.base] : properties[tempMeta.base];
inherits.unshift(_.cloneDeep(tempMeta.props));
}
let result = Object.assign({}, ...inherits);
cmpProps = cmpPropsCache[type] = result;
delete result.base;
delete result.groupName;
typeMeta.props = Object.assign({}, ...inherits);
cmpProps = cmpMetaCache[type] = typeMeta;
}
return cmpProps;
......
......@@ -32,6 +32,14 @@ export const pxHostMapping = {
prod: "https://activity.m.duiba.com.cn"
};
export const monacoEditorOptions = {
tabSize: 2,
insertSpaces: false
};
export const cmdPrefix = 'z-';
export const cmdOldPrefix = '//z-';
/**
* 节点方案
* @type {string}
......
......@@ -2,460 +2,393 @@
export default {
node: {
groupName: '基础',
visible: {
title: '是否可见',
type: 'switch',
alias: '基础',
props: {
width: 40
},
value: true
visible: {
alias: '是否可见',
type: 'boolean',
default: true
},
x: {
title: 'x坐标',
type: 'inputNumber',
value: 0,
alias: 'x坐标',
type: 'number',
default: 0,
},
y: {
title: 'y坐标',
type: 'inputNumber',
value: 0,
alias: 'y坐标',
type: 'number',
default: 0,
},
width: {
alias: '宽度',
type: 'number',
},
height: {
alias: '高度',
type: 'number',
},
left: {
title: '左边距',
type: 'inputNumber',
value: undefined,
alias: '左边距',
type: 'number',
},
right: {
title: '右边距',
type: 'inputNumber',
value: undefined,
alias: '右边距',
type: 'number',
},
top: {
title: '上边距',
type: 'inputNumber',
value: undefined,
alias: '上边距',
type: 'number',
},
bottom: {
title: '下边距',
type: 'inputNumber',
value: undefined,
},
width: {
title: '宽度',
type: 'inputNumber',
value: undefined
},
height: {
title: '高度',
type: 'inputNumber',
value: undefined
alias: '下边距',
type: 'number',
},
horizonCenter: {
title: '水平居中偏移',
type: 'inputNumber',
value: undefined,
//desc: '相对于父元素中心点的水平偏移,0为正中心'
alias: '水平居中偏移',
type: 'number',
},
verticalCenter: {
title: '垂直居中偏移',
type: 'inputNumber',
value: undefined,
//desc: '相对于父元素中心点的垂直偏移,0为正中心'
alias: '垂直居中偏移',
type: 'number',
},
rotation: {
title: '旋转',
type: 'inputNumber',
props: {
min: -180,
max: 180,
step: 1
},
value: 0
alias: '旋转',
type: 'number',
default: 0
},
anchorX: {
title: '锚点X',
type: 'inputNumber',
value: 0
alias: '锚点X',
type: 'number',
default: 0
},
anchorY: {
title: '锚点Y',
type: 'inputNumber',
value: 0
alias: '锚点Y',
type: 'number',
default: 0
},
scaleX: {
title: 'X轴缩放',
type: 'inputNumber',
value: 1,
props: {
min: 0
}
alias: 'X轴缩放',
type: 'number',
default: 1,
},
scaleY: {
title: 'Y轴缩放',
type: 'inputNumber',
value: 1,
props: {
min: 0
}
alias: 'Y轴缩放',
type: 'number',
default: 1,
},
alpha: {
title: '透明度',
type: 'slider',
value: 1,
props: {
min: 0,
max: 1,
step: 0.1
}
alias: '透明度',
type: 'number',
default: 1,
},
mouseEnabled: {
title: '可否交互',
type: 'switch',
props: {
width: 40
},
value: true
alias: '可否交互',
type: 'boolean',
default: true
},
mouseChildren: {
title: '子集交互',
type: 'switch',
props: {
width: 40
alias: '子集交互',
type: 'boolean',
default: true
},
value: true
},
}
},
label: {
base: 'node',
groupName: '文本',
alias: '文本',
props: {
text: {
title: '文本内容',
type: 'textArea',
value: ''
alias: '文本内容',
type: 'string',
default: ''
},
font: {
title: '字体',
type: 'input',
value: 'Arial'
alias: '字体',
type: 'string',
default: 'Arial'
},
htmlText: {
title: 'HTML内容',
type: 'input',
value: '',
props: {
clearable: true,
},
alias: 'HTML内容',
type: 'string',
default: '',
},
bold: {
title: '粗体',
type: 'switch',
props: {
width: 40
},
value: false,
alias: '粗体',
type: 'boolean',
default: false,
},
italic: {
title: '斜体',
type: 'switch',
props: {
width: 40
},
value: false,
alias: '斜体',
type: 'boolean',
default: false,
},
fillColor: {
title: '颜色',
type: 'colorPicker',
value: '#000'
alias: '颜色',
type: 'color',
default: '#000'
},
lineType: {
title: '自动换行',
type: 'select',
options: [
{ label: '单行', value: 'single' },
{ label: '多行', value: 'multi' }
alias: '自动换行',
type: 'enum',
enum: [
{label: '单行', value: 'single'},
{label: '多行', value: 'multi'},
],
value: 'single'
default: 'single'
},
size: {
title: '字体大小',
type: 'inputNumber',
/*type: 'swSelect',
props: {
optionType: 'fontSize'
},*/
value: 12
alias: '字体大小',
type: 'number',
default: 12
},
lineSpacing: {
title: '行间距',
type: 'inputNumber',
value: 14
},
/*lineHeight: {
title: '行高',
type: 'inputNumber',
value: 1
},*/
alias: '行间距',
type: 'number',
default: 14
},
textAlign: {
title: '文本对齐',
type: 'select',
options: [
{ label: '靠左', value: 'left' },
{ label: '居中', value: 'center' },
{ label: '靠右', value: 'right' }
alias: '文本对齐',
type: 'enum',
enum: [
{label: '靠左', value: 'left'},
{label: '居中', value: 'center'},
{label: '靠右', value: 'right'}
],
value: 'left'
default: 'left'
},
verticalAlign: {
title: '纵向对齐',
type: 'select',
options: [
{ label: '靠上', value: 'up' },
{ label: '居中', value: 'middle' },
{ label: '靠下', value: 'down' }
alias: '纵向对齐',
type: 'enum',
enum: [
{label: '靠上', value: 'up'},
{label: '居中', value: 'middle'},
{label: '靠下', value: 'down'}
],
value: 'up'
default: 'up'
},
}
},
bitmapText: {
base: 'node',
groupName: '图片文本',
text: {
title: '文本内容',
type: 'input',
value: '',
alias: '图片文本',
props: {
clearable: true,
},
text: {
alias: '文本内容',
type: 'string',
default: '',
},
font: {
title: '字体名',
type: 'input',
value: '',
props: {
clearable: true,
},
alias: '字体名',
type: 'string',
default: '',
},
letterSpacing: {
title: '字间距',
type: 'inputNumber',
value: 0
alias: '字间距',
type: 'number',
default: 0
},
verticalAlign: {
title: '纵向对齐',
type: 'select',
options: [
{ label: '靠上', value: 'up' },
{ label: '居中', value: 'middle' },
{ label: '靠下', value: 'down' }
alias: '纵向对齐',
type: 'enum',
enum: [
{label: '靠上', value: 'up'},
{label: '居中', value: 'middle'},
{label: '靠下', value: 'down'}
],
value: 'down'
default: 'down'
},
}
},
textinput: {
base: 'label',
groupName: '输入框',
alias: '输入框',
props: {
type: {
title: '输入类型',
type: 'select',
options: [
{ label: '文本', value: 'text' },
{ label: '密码', value: 'password' },
alias: '输入类型',
type: 'enum',
enum: [
{label: '文本', value: 'text'},
{label: '密码', value: 'password'},
],
value: 'text'
default: 'text'
},
charRegStr: {
title: '字符正则式',
type: 'input',
value: '',
props: {
clearable: true,
},
alias: '字符正则式',
type: 'string',
default: '',
},
maxLength: {
title: '最大长度',
type: 'inputNumber',
value: undefined,
alias: '最大长度',
type: 'number',
},
placeholder: {
title: '提示文字',
type: 'input',
value: '',
props: {
clearable: true,
},
alias: '提示文字',
type: 'string',
default: '',
},
placeholderColor: {
title: '提示颜色',
type: 'colorPicker',
value: '#666666'
alias: '提示颜色',
type: 'color',
default: '#666666'
},
}
},
image: {
base: 'node',
groupName: '图片',
alias: '图片',
props: {
source: {
title: '来源',
alias: '来源',
type: 'source',
value: ''
default: ''
},
imageWidth: {
title: '原图宽度',
type: 'input',
value: '',
alias: '原图宽度',
type: 'text',
default: '',
desc: '原图片的宽度',
props: {
disabled: true
}
},
imageHeight: {
title: '原图高度',
type: 'input',
value: '',
alias: '原图高度',
type: 'text',
default: '',
desc: '原图片的高度',
props: {
disabled: true
}
}
},
svga: {
base: 'node',
groupName: 'SVGA',
alias: 'SVGA',
props: {
source: {
title: '来源',
alias: '来源',
type: 'source',
value: ''
default: ''
},
lockStep: {
title: '锁步',
type: 'switch',
props: {
width: 40
},
value: false
alias: '锁步',
type: 'boolean',
default: false
},
autoPlay: {
title: '自动播放',
type: 'switch',
props: {
width: 40
},
value: false
alias: '自动播放',
type: 'boolean',
default: false
},
}
},
shape: {
base: 'node',
alias: '形状',
props: {
fillColor: {
title: '填充色',
type: 'colorPicker',
value: '#fff'
alias: '填充色',
type: 'color',
default: '#fff'
},
strokeColor: {
title: '边框颜色',
type: 'colorPicker',
value: '#000'
alias: '边框颜色',
type: 'color',
default: '#000'
},
strokeWidth: {
title: '边框宽度',
type: 'inputNumber',
value: 0,
props: {
min: 0
alias: '边框宽度',
type: 'number',
default: 0,
}
}
},
rect: {
base: 'shape',
groupName: '矩形',
borderRadius: {
title: '圆角',
type: 'inputNumber',
value: 0,
alias: '矩形',
props: {
min: 0
borderRadius: {
alias: '圆角',
type: 'number',
default: 0,
}
}
},
circle: {
base: 'shape',
groupName: '圆形',
alias: '圆形',
props: {}
},
scrollView: {
base: 'node',
groupName: '滚动视图',
alias: '滚动视图',
props: {
direction: {
title: '滚动方向',
type: 'select',
options: [
{ label: '纵向', value: 'vertical' },
{ label: '横向', value: 'horizontal' }
alias: '滚动方向',
type: 'enum',
enum: [
{label: '纵向', value: 'vertical'},
{label: '横向', value: 'horizontal'}
],
value: 'vertical',
default: 'vertical',
},
isSpringBack: {
title: '回弹效果',
type: 'switch',
props: {
width: 40
},
value: true,
alias: '回弹效果',
type: 'boolean',
default: true,
},
maxSpeed: {
title: '最大速度',
type: 'inputNumber',
value: 100,
alias: '最大速度',
type: 'number',
default: 100,
},
fSpeed: {
title: '摩擦力',
type: 'inputNumber',
value: 20,
alias: '摩擦力',
type: 'number',
default: 20,
},
}
},
scrollList: {
base: 'scrollView',
groupName: '滚动列表',
alias: '滚动列表',
props: {
itemWidth: {
title: '单项宽度',
type: 'inputNumber',
value: 0,
alias: '单项宽度',
type: 'number',
default: 0,
},
itemHeight: {
title: '单项高度',
type: 'inputNumber',
value: 0,
alias: '单项高度',
type: 'number',
default: 0,
},
cols: {
title: '行列数',
type: 'inputNumber',
value: 1,
alias: '行列数',
type: 'number',
default: 1,
},
cloneEvents: {
title: '克隆事件',
type: 'switch',
props:{
alias: '克隆事件',
type: 'boolean',
props: {
width: 40,
},
value: true,
default: true,
},
cloneScripts: {
title: '克隆脚本',
type: 'switch',
props:{
alias: '克隆脚本',
type: 'boolean',
props: {
width: 40,
},
value: true,
default: true,
},
}
},
htmlView: {
base: 'node',
groupName: 'HTML视图',
htmlElement: {
title: 'HTML内容',
type: 'input',
alias: 'HTML视图',
props: {
clearable: true,
},
htmlElement: {
alias: 'HTML内容',
type: 'string',
},
}
},
}
......@@ -122,8 +122,8 @@
methods: {
prepare() {
return Promise.all([
this.updateEnv(),
db.open('store'),
this.updateEnv(),
])
},
onKeyPress(e) {
......
<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="100px" @submit.native.prevent>
<el-form class="form" ref="form" size="mini" :model="form" label-width="100px" @submit.native.prevent>
<div class="top-bar" v-if="activeComponent.$isRootView">
<el-button size="mini" @click="clickEditStoreExp">编辑数据</el-button>
<el-button size="mini" @click="clickEditStoreComputed">计算属性</el-button>
</div>
<el-form-item label="名称">
<el-input v-model="form.name" @input="v => handleChange('name', v)"></el-input>
</el-form-item>
......@@ -10,85 +13,62 @@
<el-option v-for="(cmp, key) in componentsMap" :key="key" :label="cmp" :value="key"></el-option>
</el-select>
</el-form-item>
<template v-for="(p, key) in cmpProps">
<el-form-item v-if="key !== 'groupName'" :id="activeComponent.uuid + '-' + key" :key="activeComponent.uuid + key" :label="p.title">
<!-- {{key}} -->
<el-tooltip :disabled="!p.desc" placement="top-start">
<div slot="content">{{p.desc}}</div>
<div>
<dynamic-component :component-value="getPropValue(p, key)" :component-props="getPropProps(p)" :component-type="getPropCmpType(p)" @onChange="v => handlePropertiesChange(key, v)"></dynamic-component>
</div>
</el-tooltip>
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden">
<el-collapse v-model="activeNames">
<el-collapse-item title="属性" name="props">
<props-editor
class="all-form"
ref="propsEditor"
:editable="true"
:switchable="true"
mode="cmd"
:data="form.properties"
:meta="propsMeta"
@input="onInput"
/>
</el-collapse-item>
<el-collapse-item title="自定义指令" name="cmd">
<el-form-item v-for="key in customCmdKeys" :label="customCmdNames[key]" :key="key" label-width="50px">
<el-input class="cmd-input" v-model="activeComponent.properties[key]"></el-input>
</el-form-item>
</template>
</el-form>
<div class="add-item-bar">
<el-dropdown trigger="click" @command="addCmd" placement="bottom" size="small">
<el-button size="mini" type="primary" plain>{{$t('Add')}}</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="(cmd, key) of customCmdNames"
:command="key"
:key="key"
:disabled="customCmdKeys.includes(key)"
>{{cmd}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-collapse-item>
</el-collapse>
</el-scrollbar>
</el-form>
<store-editor-dialog ref="storeEditorDialog"/>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import _ from 'lodash';
import { getCmpProps } from '../../../utils/common';
import dynamicComponent from '../components/dynamicComponent';
import {mapGetters, mapState} from 'vuex';
import PropsEditor from "../../../components/PropsEditor";
import {getCmpProps} from "../../../utils/common";
import StoreEditorDialog from "./PropsTab/StoreEditorDialog";
const componentMapper = {
switch: {
component: 'el-switch',
props: {
width: 100
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
},
swSelect: {
component: 'sw-select' // 无需传入options
},
source: {
component: 'sw-source'
},
slider: {
component: 'sw-slider'
},
inputNumber: {
component: 'el-input-number',
props: {
size: 'mini',
'controls-position': 'right'
}
},
textArea: {
component: 'el-input',
props: {
type: 'textarea',
autosize: {
minRows: 3,
maxRows: 10
}
}
},
input: {
component: 'el-input'
},
colorPicker: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
}
};
export default {
export default {
name: 'PropsTab',
components: { 'dynamic-component': dynamicComponent },
components: {StoreEditorDialog, PropsEditor},
data() {
const componentsMap = this.$t('view_node_menu');
const customCmdNames = this.$t('customCmds');
return {
activeNames: 'props',
componentsMap,
customCmdNames,
form: {
name: '',
type: '',
......@@ -98,15 +78,24 @@ export default {
},
computed: {
...mapGetters(['activeComponent', 'activeComponentCopy', 'componentList']),
cmpProps: function() {
// 获取properties.js中的默认配置
propsMeta() {
return getCmpProps(this.activeComponent.type);
},
customCmdKeys() {
let cmdNames = Object.keys(this.customCmdNames);
let keys = [];
for (let key in this.activeComponent.properties) {
if (cmdNames.includes(key)) {
keys.push(key);
}
}
return keys;
}
},
watch: {
activeComponent: {
deep: true,
handler: function(val) {
handler: function (val) {
this.form.name = val.name || '';
this.form.type = val.type || '';
this.form.properties = val.properties || {};
......@@ -119,57 +108,27 @@ export default {
_view[label] = v;
this.$store.dispatch('modifyActiveView', _view);
},
/**
* 基础属性发生改变
*/
handlePropertiesChange(key, v) {
console.log('handlePropertiesChange', key, v);
onInput(value, container, propName, oldValue) {
console.log('propsChange', propName, value);
let _prop = {};
_prop[key] = v;
_prop[propName] = value;
this.$store.dispatch('modifyProperties', _prop);
},
/**
* 获取动态组件的类型
*/
getPropCmpType(item) {
return componentMapper[item.type].component;
clickEditStoreExp() {
this.$refs.storeEditorDialog.edit('exp', this.activeComponent);
},
/**
* 获取动态组件的属性v-bind
*/
getPropProps(item) {
let _cmp = componentMapper[item.type];
return {
size: 'mini',
...(_cmp.props || {}),
...item.props,
options: item.options || {}
};
clickEditStoreComputed() {
this.$refs.storeEditorDialog.edit('computed', this.activeComponent);
},
/**
* 获取当前选中节点对应的属性的值
*/
getPropValue(item, key) {
let _properties = this.activeComponentCopy.properties;
return _properties[key] === undefined || _properties[key] === null ? item.value : _properties[key];
addCmd(cmd) {
let props = this.activeComponent.properties;
this.$set(props, cmd, '');
},
}
};
};
</script>
<style lang="scss">
.zero-inspector-props-form {
width: 100%;
padding-right: 10px;
.el-divider__text {
background-color: #e9e9e9;
}
.zero-inspector-props-group {
max-height: 500px;
}
}
.script-config-dialog {
height: 350px;
}
</style>
\ No newline at end of file
<template>
<el-dialog
:title="$t('Store editor')"
width="80vw"
:visible.sync="visible"
:append-to-body="true"
:close-on-click-modal="false"
:show-close="false"
:close-on-press-escape="false"
custom-class="store-editor-dialog"
>
<div class="wrapper">
<el-tabs v-model="tab" type="border-card" class="tabs">
<el-tab-pane :label="$t('Store')" name="exp">
<monaco-editor
v-if="showEditor && tab === 'exp'"
class="editor"
v-model="store.exp"
language="javascript"
:options="monacoEditorOptions"
/>
</el-tab-pane>
<el-tab-pane :label="$t('Computed')" name="computed">
<el-table class="computed-editor" :data="store.computed" height="100%" stripe size="mini">
<el-table-column type="expand">
<template slot-scope="scope">
<monaco-editor
class="editor"
v-model="scope.row.script"
language="javascript"
:options="monacoEditorOptions"
/>
</template>
</el-table-column>
<el-table-column
prop="name"
:label="$t('Name')">
<template slot-scope="scope">
<el-input v-model="scope.row.name" size="mini"/>
</template>
</el-table-column>
<el-table-column
width="50"
:label="$t('Operate')">
<template slot-scope="scope">
<el-button circle size="mini" type="danger" icon="el-icon-delete" plain
@click="toDeleteItem(scope.$index)"/>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-button v-show="tab === 'computed'" size="mini" @click="onAdd">{{$t('Add')}}</el-button>
</div>
<div>
<el-popconfirm @onConfirm="clickClose" placement="top"
:title="$t('Are you sure to close?')">
<el-button slot="reference" size="mini">{{ $t("Close") }}</el-button>
</el-popconfirm>
<el-button class="save-button" type="primary" size="mini" @click="clickSave">{{ $t("Save") }}
</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import {mapMutations} from 'vuex';
import MonacoEditor from "vue-monaco";
import {clonePureObj, monacoEditorOptions} from "../../../../utils";
const storeExp = `return {
}
`;
export default {
name: "StoreEditorDialog",
components: {MonacoEditor},
data() {
return {
visible: false,
tab: 'exp',
monacoEditorOptions,
showEditor: false,
store: {},
}
},
computed: {
},
methods: {
async edit(type, view) {
this.view = view;
console.log(view.storeExp);
this.store = view.store ? clonePureObj(view.store) : {
exp: storeExp,
computed: [],
};
this.visible = true;
this.$nextTick(()=>{
this.showEditor = true;
this.tab = type;
});
},
onAdd() {
this.store.computed.push({
name: '',
script: '',
});
},
onDelete(index) {
this.store.computed.splice(index, 1);
},
toDeleteItem(index) {
this.$confirm(this.$t('Are you sure to delete this item'), this.$t('Alert'), {
confirmButtonText: this.$t('Confirm'),
cancelButtonText: this.$t('Cancel'),
type: 'warning'
}).then(() => {
this.onDelete(index);
}).catch((e) => {
});
},
clickSave() {
this.modifyViewStore({
view: this.view,
store: this.store,
});
this.visible = false;
},
clickClose() {
this.visible = false;
},
...mapMutations(['modifyViewStore'])
}
}
</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="100px" @submit.native.prevent>
<el-form class="all-form" ref="form" size="mini" :model="form" label-width="100px" @submit.native.prevent>
<el-collapse accordion v-if="activeComponent.scripts && activeComponent.scripts.length">
<template v-for="(script, index) in activeComponent.scripts">
<el-collapse-item :title="getScriptName(script.script)" :key="script + index">
<template v-for="(p, key) in getScriptOptions(script.script)">
<el-form-item :key="activeComponent.uuid + index + key" :label="p.alias|| key">
<dynamic-component :component-value="getScriptValue(p, key, index)" :component-props="getScriptProps(p, index)" :component-type="getScriptType(p, index)" @onChange="v => handleScriptChange(index, key, v)"></dynamic-component>
</el-form-item>
</template>
<props-editor
ref="propsEditor"
:editable="true"
:data="script.props"
:meta="getScriptOptions(script.script)"
@input="(value, container, propName)=>onInput(index, value, propName)"
/>
<el-form-item label="">
<el-button @click="deleteNodeScript(index)">删除</el-button>
<el-button @click="deleteNodeScript(index)" type="danger" plain>删除</el-button>
</el-form-item>
</el-collapse-item>
</template>
</el-collapse>
<div style="padding-top: 15px;text-align: center;">
<el-dropdown trigger="click" @command="handleAddScript" placement="top" size="small">
<el-button size="mini">{{$t('Add')}}</el-button>
</el-form>
<div class="add-item-bar">
<el-dropdown trigger="click" @command="handleAddScript" placement="bottom" size="small">
<el-button size="mini" type="primary" plain>{{$t('Add')}}</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(script, key) of scriptPackages" :command="script.id" :key="key">{{script.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-form>
</el-scrollbar>
</div>
</template>
......@@ -32,41 +34,11 @@
<script>
import { mapGetters, mapState } from 'vuex';
import _ from 'lodash';
import dynamicComponent from '../components/dynamicComponent';
const scriptTypeMap = {
number: {
component: 'el-input-number',
props: {
size: 'mini'
}
},
string: {
component: 'el-input'
},
boolean: {
component: 'el-switch',
props: {
width: 40
}
},
color: {
component: 'el-color-picker',
props: {
'show-alpha': true
}
},
select: {
component: 'el-select',
props: {
slotComponent: 'el-option'
}
}
};
import PropsEditor from "../../../components/PropsEditor";
export default {
name: 'ScriptsTab',
components: { 'dynamic-component': dynamicComponent },
components: {PropsEditor},
data() {
return {
form: {
......@@ -92,7 +64,7 @@ export default {
/**
* 事件属性发生改变
*/
handleScriptChange(index, key, v) {
onInput(index, v, key) {
let _props = {};
_props[key] = v;
let _scripts = _.cloneDeep(this.activeComponent.scripts);
......@@ -143,7 +115,7 @@ export default {
},
getScriptOptions(id) {
let _script = this.scriptPackages[id];
return _script ? _script.props : {};
return _script ? _script : {};
},
/**
* 删除节点脚本
......@@ -163,17 +135,5 @@ export default {
</script>
<style lang="scss">
.zero-inspector-props-form {
width: 100%;
padding-right: 10px;
.el-divider__text {
background-color: #e9e9e9;
}
.zero-inspector-props-group {
max-height: 500px;
}
}
.script-config-dialog {
height: 350px;
}
</style>
\ No newline at end of file
......@@ -4,13 +4,14 @@
ref="editor"
v-model="meta.script"
language="javascript"
:options="monacoConfig"
:options="monacoEditorOptions"
@editorWillMount="editorWillMount"
/>
</template>
<script>
import MonacoEditor from "vue-monaco";
import {monacoEditorOptions} from "../../../utils";
const typesUrl = [
"http://yun.duiba.com.cn/editor/zeroing/types/types.v2.d.ts",
......@@ -36,7 +37,7 @@ $ENV_PROPS$
props: ['meta'],
data() {
return {
monacoConfig: {},
monacoEditorOptions,
}
},
mounted() {
......
......@@ -5,7 +5,7 @@
<template slot="prepend">{{$t('Name')}}</template>
</el-input>
<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"/>
<props-editor ref="propsEditor" :editable="editable" :switchable="true" mode="linkable" :data="process.data.props" :meta="process.meta"/>
</el-scrollbar>
<div class="inside-code">
<el-scrollbar class="scrollbar" wrap-class="wrap-x-hidden" view-class="scrollbar-view">
......
<template>
<component v-if="cmpValue !== null" :is="componentType" v-model="cmpValue" v-bind="componentProps" @change="v => handleChange(v)" @input="v=>handleInput(v)">
<d-slot
v-for="oitem in componentProps.options"
:is="componentProps.slotComponent"
:key="oitem.value"
:label="oitem.label || oitem.value"
:value="oitem.value"
>
</d-slot>
</component>
</template>
<script>
import swSlider from '../../../components/customSettings/slider';
import swSelect from '../../../components/customSettings/selector';
import swSource from '../../../components/customSettings/source';
export default {
components: {
swSlider,
swSelect,
swSource
},
props: {
componentValue: [String, Number, Boolean],
componentType: {
type: String,
default: ''
},
componentProps: {
type: Object,
default: () => {}
}
},
data() {
return {
cmpValue: null
};
},
mounted() {
this.cmpValue = this.componentValue;
},
watch: {
componentValue: function(val) {
this.cmpValue = val;
}
},
methods: {
/**
* 组件值发生改变
*/
handleChange(v) {
// console.log('handleChange', v);
this.$emit('onChange', v);
// let _prop = {};
// _prop[this.label] = v;
// this.$store.dispatch('modifyProperties', _prop);
},
handleInput(v) {
if (this.componentType === 'el-input') {
this.handleChange(v);
}
}
}
};
</script>
......@@ -55,13 +55,13 @@ export default {
},
position() {
let _props = this.activeComponentCopy.properties || {};
const _node = properties.node;
const props = properties.node.props;
// console.log('********', _props);
let result = {
x: _props.x || _node.x.value,
y: _props.y || _node.y.value,
w: _props.width || _node.width.value,
h: _props.height || _node.height.value
x: _props.x || props.x.default,
y: _props.y || props.y.default,
w: _props.width || props.width.default,
h: _props.height || props.height.default,
};
// console.log('####position', result);
......
......@@ -127,10 +127,10 @@ export default {
const _node = properties.node;
// console.log('********', _props);
let result = {
x: _props.x || _node.x.value,
y: _props.y || _node.y.value,
w: _props.width || _node.width.value,
h: _props.height || _node.height.value
x: _props.x || _node.x.default,
y: _props.y || _node.y.default,
w: _props.width || _node.width.default,
h: _props.height || _node.height.default
};
console.log('####position', result);
......
......@@ -18,7 +18,7 @@
class="editor"
v-model="props.row.data"
language="json"
:options="monacoConfig"
:options="monacoEditorOptions"
/>
</template>
</el-table-column>
......@@ -84,7 +84,7 @@
<script>
import {mapState, mapMutations, mapActions} from 'vuex'
import EnabledSetter from "../components/EnabledSetter";
import {clonePureObj} from "../../../utils";
import {clonePureObj, monacoEditorOptions} from "../../../utils";
import MonacoEditor from "vue-monaco";
export default {
......@@ -94,9 +94,7 @@
return {
visible: false,
mocks: [],
monacoConfig: {
}
monacoEditorOptions,
}
},
mounted() {
......
<template>
<el-dialog :title="$t('Process Search')" width="80%" :visible.sync="visible"
:append-to-body="true"
:close-on-click-modal="false"
custom-class="meta-search-dialog"
>
<div class="wrapper">
......
......@@ -19,6 +19,7 @@
class="editor"
v-model="skin.html"
language="html"
:options="monacoEditorOptions"
/>
</el-form-item>
</el-form>
......@@ -40,7 +41,7 @@
<script>
import MonacoEditor from "vue-monaco";
import {clonePureObj} from "../../../utils";
import {clonePureObj, monacoEditorOptions} from "../../../utils";
import ElFormItem from "../../../components/inputs/form-item";
export default {
......@@ -52,6 +53,7 @@
pxProjectName: '',
skin: null,
operate: 0,
monacoEditorOptions,
rules: {
name: [
{required: true, message: this.$t('Skin name required'), trigger: 'blur'},
......
......@@ -8,7 +8,7 @@
<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"/>
<props-editor v-if="data" ref="propsEditor" :data="data.props" :meta="meta" label-width="180px"/>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<div></div>
......
......@@ -3,7 +3,7 @@
<el-tabs style="flex: 1;height: 0;" class="tabs" v-model="activeName">
<el-tab-pane v-for="(group, key, index) in packageInfos" :label="$t('dependenciesTypes')[key]" :name="key" :key="key">
<el-scrollbar v-if="editData" class="scrollbar" wrap-class="wrap-x-hidden" view-class="view package-manager">
<div class="mapping-list">
<div class="package-list">
<div class="list">
<div class="item" v-for="packageInfo in group" :key="packageInfo.id">
<div style="flex: 1;">
......
......@@ -49,7 +49,7 @@
class="editor"
v-model="editData.tpl"
language="html"
:options="monacoConfig"
:options="monacoEditorOptions"
/>
</el-form-item>
</el-form>
......@@ -58,7 +58,7 @@
<script>
import {mapState, mapGetters, mapMutations} from 'vuex';
import {clonePureObj} from "../../../../utils";
import {clonePureObj, monacoEditorOptions} from "../../../../utils";
import MonacoEditor from "vue-monaco";
export default {
......@@ -72,9 +72,7 @@
editData: null,
scaleMode,
rendererType,
monacoConfig: {
},
monacoEditorOptions,
}
},
computed: {
......
......@@ -92,7 +92,6 @@
components: {ElFormItem, ProjectHistoryDialog, DuplicateProjectDialog, CreateProjectDialog},
data() {
return {
appVersion: 'v1.0.0',
currentPage: 1,
pageSize: PROJECT_PAGE_SIZE,
searchWord: '',
......
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