mirror of
https://github.com/vxcontrol/ncform.git
synced 2026-07-19 18:23:32 -04:00
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:
@@ -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)
|
||||
});
|
||||
});
|
||||
|
||||
+61
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+35
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
+45
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user