feat: widgetConfig support dx: input / checkbox / date-picker

BREAKING CHANGE: all widget config fields auto support dx expression, mergeConfig is readonly
computed prop. warning again: mergeConfig is readonly
This commit is contained in:
daniel-dx
2019-03-18 00:12:02 +08:00
parent 1dfbcebe82
commit 6b28bb6b9f
9 changed files with 264 additions and 72 deletions
@@ -19,22 +19,6 @@ export default {
this.$http = this.$axios || this.axios || axios;
}
this.$data.mergeConfig = extend(
true,
{},
this.$data.defaultConfig,
this.config
);
this.$watch("config", () => {
this.$data.mergeConfig = extend(
true,
{},
this.$data.defaultConfig,
this.config
);
});
},
props: {
@@ -70,7 +54,6 @@ export default {
data() {
return {
mergeConfig: {},
defaultConfig: {},
modelVal: this.value,
i18n: {},
@@ -89,6 +72,20 @@ export default {
},
hidden() {
return this._analyzeVal(this.config.hidden);
},
mergeConfig() {
let newConfig = extend(
true,
{},
this.$data.defaultConfig,
this.config
)
return ncformUtils.traverseJSON(newConfig, (...params) => {
let val = params[1];
if (val !== null && typeof val !== 'object')
return this._analyzeVal(val);
else return val;
})
}
},
@@ -558,6 +558,22 @@ const ncformUtils = {
return Math.random()
.toString(36)
.substring(2, num + 2);
},
/**
* Traversing JSON
* @param {*} json
* @param {*} func
*/
traverseJSON(json, func) {
let newJson = json;
for (var i in newJson) {
newJson[i] = func.apply(this, [i, newJson[i]]);
if (newJson[i] !== null && typeof (newJson[i]) == "object") {
newJson[i] = ncformUtils.traverseJSON(newJson[i], func);
}
}
return newJson;
}
};
@@ -989,4 +989,52 @@ describe('/src/ncform-utils.js', () => {
result = ncformUtils.genRandomId(11);
assert(result.length === 10);
});
// --- traverseJSON
it("traverseJSON", () => {
let json = { a: 1, b: null };
let result = ncformUtils.traverseJSON(json, (key, val) => {
if (val !== null && typeof val !== 'object')
return val + 1;
else return val;
});
assert(result.a === 2)
assert(result.b === null)
json = { a: { b: 1, c: { d: 2 } } };
result = ncformUtils.traverseJSON(json, (key, val) => {
if (val !== null && typeof val !== 'object')
return val + 1;
else return val;
});
assert(result.a.b === 2)
assert(result.a.c.d === 3)
json = { a: [1, [2]] };
result = ncformUtils.traverseJSON(json, (key, val) => {
if (val !== null && typeof val !== 'object')
return val + 1;
else return val;
});
assert(result.a[0] === 2)
assert(result.a[1][0] === 3)
json = { a: [1, { b: 2 }] };
result = ncformUtils.traverseJSON(json, (key, val) => {
if (val !== null && typeof val !== 'object')
return val + 1;
else return val;
});
assert(result.a[0] === 2)
assert(result.a[1].b === 3)
json = [1, {a: 2}];
result = ncformUtils.traverseJSON(json, (key, val) => {
if (val !== null && typeof val !== 'object')
return val + 1;
else return val;
});
assert(result[0] === 2)
assert(result[1].a === 3)
});
});
@@ -192,4 +192,65 @@ context('Checkbox', () => {
// common.submitForm();
});
});
it('dx config', () => {
cy.server();
cy.route(() => {
return {
method: 'GET',
url: '/100/users',
response: {
data: [
{
value: '1',
label: 'daniel'
},
{
value: '2',
label: 'sarah'
}
]
}
};
}).as('users');
let formSchema = {
type: 'object',
properties: {
name0: {
type: 'number',
value: 100
},
name1: {
type: 'array',
ui: {
widget: 'checkbox',
widgetConfig: {
enumSourceRemote: {
remoteUrl: 'dx: "/" + {{$root.name0}} + "/users"',
resField: 'data'
}
}
}
}
}
};
cy.window()
.its('editor')
.invoke('setValue', JSON.stringify(formSchema, null, 2));
common.startRun();
cy.get('.previewArea').within(() => {
// Declare action elements
cy.get('label')
.contains('name1')
.parent()
.within(() => {
cy.get('label.el-checkbox').contains('daniel')
cy.get('label.el-checkbox').contains('sarah')
});
// common.submitForm();
});
});
});
@@ -243,4 +243,39 @@ context('data-picker', () => {
// common.submitForm();
});
});
it('dx config', () => {
let formSchema = {
type: 'object',
properties: {
name1: {
type: 'string',
value: '1512284108066',
ui: {
widget: 'date-picker',
widgetConfig: {
format: 'dx: "(yyyy)MM-dd"'
}
}
}
}
};
cy.window()
.its('editor')
.invoke('setValue', JSON.stringify(formSchema, null, 2));
common.startRun();
cy.get('.previewArea').within(() => {
// Declare action elements
cy.get('label')
.contains('name1')
.parent()
.within(() => {
// format
cy.get('input').should('have.value', '(2017)12-03');
});
// common.submitForm();
});
});
});
@@ -457,7 +457,7 @@ context('input', () => {
remoteUrl: '/autocomplete',
paramName: 'keyword',
otherParams: {
name: 'daniel'
name: 'dx: "daniel"'
},
resField: 'data'
}
@@ -761,4 +761,48 @@ context('input', () => {
// common.submitForm();
});
});
it('dx config', () => {
let formSchema = {
type: 'object',
properties: {
name0: {
type: 'string',
},
name1: {
type: 'string',
ui: {
widgetConfig: {
compound: {
appendLabel: 'dx: {{$root.name0}}'
}
}
}
}
}
};
cy.window()
.its('editor')
.invoke('setValue', JSON.stringify(formSchema, null, 2));
common.startRun();
cy.get('.previewArea').within(() => {
// Declare action elements
cy.get('label')
.contains('name0')
.parent()
.within(() => {
cy.get('input').type('daniel')
});
cy.get('label')
.contains('name1')
.parent()
.within(() => {
cy.get('.el-input-group__append').contains('daniel')
});
// common.submitForm();
});
});
});
@@ -8,7 +8,7 @@
:class="'check-all'"
:disabled="disabled"
:indeterminate="isIndeterminate"
v-model="mergeConfig.checkAll"
v-model="isCheckAll"
@change="handleCheckAllChange"
>{{$t('all')}}</el-checkbox>
@@ -20,7 +20,7 @@
@change="handleCheckedOptChange"
>
<component :is="'el-checkbox' + (mergeConfig.type === 'button' ? '-button' : '')"
v-for="opt in mergeConfig.enumSource"
v-for="opt in dataSource"
:key="opt[mergeConfig.itemValueField]"
:label="opt[mergeConfig.itemValueField]"
:class="mergeConfig.type === 'checkbox' && mergeConfig.arrangement === 'v' ? 'is-vertical' : ''"
@@ -123,6 +123,8 @@
data() {
return {
dataSource: [],
isCheckAll: false,
isIndeterminate: false,
// 组件特有的配置属性
defaultConfig: {
@@ -174,7 +176,7 @@
const mergeConfig = vm.mergeConfig;
const itemValueField = mergeConfig.itemValueField;
const arrResAll = [];
mergeConfig.enumSource.map(obj => {
vm.$data.dataSource.map(obj => {
arrResAll.push(obj[itemValueField]);
});
vm.modelVal = val ? arrResAll : [];
@@ -183,8 +185,8 @@
handleCheckedOptChange(value) {
const vm = this;
let checkedCount = value.length;
vm.mergeConfig.checkAll = checkedCount === vm.mergeConfig.enumSource.length;
vm.isIndeterminate = checkedCount > 0 && checkedCount < vm.mergeConfig.enumSource.length;
vm.$data.isCheckAll = checkedCount === vm.$data.dataSource.length;
vm.isIndeterminate = checkedCount > 0 && checkedCount < vm.$data.dataSource.length;
},
getRemoteSource() {
try {
@@ -201,10 +203,10 @@
}).then(res => {
if (res.status === 200 ) {
let data = res.data;
vm.mergeConfig.enumSource = _get(data, enumSourceRemote.resField || '', []);
vm.$data.dataSource = _get(data, enumSourceRemote.resField || '', []);
}
}).catch(err => {
vm.mergeConfig.enumSource = [];
vm.$data.dataSource = [];
});
} catch(err) {
console.error(err);
@@ -217,7 +219,9 @@
if (enumSourceRemote && enumSourceRemote.remoteUrl) {
vm.getRemoteSource();
} else if (!vm.mergeConfig.enumSource.length) {
vm.mergeConfig.enumSource = [ {label: this.$t('yes'), value: true}];
vm.$data.dataSource = [ {label: this.$t('yes'), value: true}];
} else {
vm.$data.dataSource = vm.mergeConfig.enumSource;
}
}
}
@@ -1,14 +1,14 @@
<template>
<el-date-picker class="ncform-date-picker"
v-if="mergeConfig.type && typeOptions[mergeConfig.type]"
:placeholder="placeholder || $t(typeOptions[mergeConfig.type].placeholder)"
v-if="type && typeOptions[type]"
:placeholder="placeholder || $t(typeOptions[type].placeholder)"
:disabled="disabled"
:readonly="readonly"
:clearable="mergeConfig.clearable"
v-show="!hidden"
v-model="modelVal"
:type="mergeConfig.type"
:format="mergeConfig.format || $t(typeOptions[mergeConfig.type].format)"
:type="type"
:format="mergeConfig.format || $t(typeOptions[type].format)"
>
</el-date-picker>
</template>
@@ -71,6 +71,7 @@ export default {
}
},
created() {
this.$data.type = this.mergeConfig.type;
},
mounted() {
@@ -79,14 +80,15 @@ export default {
}
this.$nextTick(()=>{
if(!this.$data.typeOptions[this.$data.mergeConfig.type]){
this.$data.mergeConfig.type = 'date';
if(!this.$data.typeOptions[this.$data.type]){
this.$data.type = 'date';
}
});
},
data() {
return {
type: 'date',
typeOptions: {
year: {
format: '',
@@ -232,34 +232,34 @@ export default {
this.$data.inputVal =
["string", "number"].indexOf(typeof this.$data.modelVal) >= 0
? this.$data.modelVal
: this.$data.modelVal[this.$data.mergeConfig.modelField];
: this.$data.modelVal[this.mergeConfig.modelField];
}
if (_get(this.$data.mergeConfig, "autocomplete.itemTemplate")) {
if (_get(this.mergeConfig, "autocomplete.itemTemplate")) {
this.$data.itemTemplate.template = _get(
this.$data.mergeConfig,
this.mergeConfig,
"autocomplete.itemTemplate"
);
}
if (_get(this.$data.mergeConfig, "compound.prependSelect")) {
if (_get(this.$data.mergeConfig, "compound.prependSelect.enumSource")) {
if (_get(this.mergeConfig, "compound.prependSelect")) {
if (_get(this.mergeConfig, "compound.prependSelect.enumSource")) {
this.$data.prependSelectOptions = _get(
this.$data.mergeConfig,
this.mergeConfig,
"compound.prependSelect.enumSource"
);
} else {
this.$http({
url: _get(
this.$data.mergeConfig,
this.mergeConfig,
"compound.prependSelect.enumSourceRemote.remoteUrl"
)
}).then(res => {
this.$data.prependSelectOptions = this.$data.mergeConfig.compound
this.$data.prependSelectOptions = this.mergeConfig.compound
.prependSelect.enumSourceRemote.resField
? _get(
res.data,
this.$data.mergeConfig.compound.prependSelect.enumSourceRemote
this.mergeConfig.compound.prependSelect.enumSourceRemote
.resField
)
: res.data;
@@ -267,7 +267,7 @@ export default {
}
this.$data.prependSelectVal = _get(
this.value,
_get(this.$data.mergeConfig, "compound.prependSelect.modelField")
_get(this.mergeConfig, "compound.prependSelect.modelField")
);
this.$watch("prependSelectVal", function() {
let val = this._processModelVal();
@@ -275,24 +275,24 @@ export default {
});
}
if (_get(this.$data.mergeConfig, "compound.appendSelect")) {
if (_get(this.$data.mergeConfig, "compound.appendSelect.enumSource")) {
if (_get(this.mergeConfig, "compound.appendSelect")) {
if (_get(this.mergeConfig, "compound.appendSelect.enumSource")) {
this.$data.appendSelectOptions = _get(
this.$data.mergeConfig,
this.mergeConfig,
"compound.appendSelect.enumSource"
);
} else {
this.$http({
url: _get(
this.$data.mergeConfig,
this.mergeConfig,
"compound.appendSelect.enumSourceRemote.remoteUrl"
)
}).then(res => {
this.$data.appendSelectOptions = this.$data.mergeConfig.compound
this.$data.appendSelectOptions = this.mergeConfig.compound
.appendSelect.enumSourceRemote.resField
? _get(
res.data,
this.$data.mergeConfig.compound.appendSelect.enumSourceRemote
this.mergeConfig.compound.appendSelect.enumSourceRemote
.resField
)
: res.data;
@@ -300,7 +300,7 @@ export default {
}
this.$data.appendSelectVal = _get(
this.value,
_get(this.$data.mergeConfig, "compound.appendSelect.modelField")
_get(this.mergeConfig, "compound.appendSelect.modelField")
);
this.$watch("appendSelectVal", function() {
@@ -396,22 +396,9 @@ export default {
};
},
computed: {
autocompleteOtherParams() {
let otherParams = _cloneDeep(
_get(this.mergeConfig, "autocomplete.enumSourceRemote.otherParams"),
{}
);
for (let key in otherParams) {
otherParams[key] = this._analyzeVal(otherParams[key]);
}
return otherParams;
}
},
methods: {
querySearch(queryString, cb) {
const autoCpl = this.$data.mergeConfig.autocomplete;
const autoCpl = this.mergeConfig.autocomplete;
// 本地数据源的处理
if (autoCpl.enumSource) {
@@ -429,9 +416,7 @@ export default {
// 下面是远程数据源的处理
const options = {
url: autoCpl.enumSourceRemote.remoteUrl,
params: this.autocompleteOtherParams
? JSON.parse(JSON.stringify(this.autocompleteOtherParams))
: {}
params: _get(this.mergeConfig, "autocomplete.enumSourceRemote.otherParams")
};
options.params[autoCpl.enumSourceRemote.paramName] = queryString;
@@ -592,7 +577,7 @@ export default {
if (newVal !== undefined) {
// mixin调用的
if (typeof this.value === "object") {
val = newVal[this.$data.mergeConfig.modelField];
val = newVal[this.mergeConfig.modelField];
} else {
val = newVal;
}
@@ -600,11 +585,11 @@ export default {
val = this.$data.inputVal;
}
if (this.$data.mergeConfig.trim) {
if (this.mergeConfig.trim) {
val = val ? val.toString().trim() : val;
}
switch (this.$data.mergeConfig.type) {
switch (this.mergeConfig.type) {
case "number":
val = parseFloat(val);
val = isNaN(val) ? "" : val;
@@ -619,13 +604,13 @@ export default {
if (typeof this.value === "object") {
const obj = {};
obj[this.$data.mergeConfig.modelField] = val;
if (_get(this.$data.mergeConfig, "compound.prependSelect")) {
obj[this.mergeConfig.modelField] = val;
if (_get(this.mergeConfig, "compound.prependSelect")) {
obj[
this.mergeConfig.compound.prependSelect.modelField
] = this.$data.prependSelectVal;
}
if (_get(this.$data.mergeConfig, "compound.appendSelect")) {
if (_get(this.mergeConfig, "compound.appendSelect")) {
obj[
this.mergeConfig.compound.appendSelect.modelField
] = this.$data.appendSelectVal;