diff --git a/README.md b/README.md index 9f659a2..6d41c5b 100644 --- a/README.md +++ b/README.md @@ -260,12 +260,13 @@ globalConfig: { > dx expressions can also be replaced with `function` : -function(formData, constData, selfData, tempData, itemIdxChain) { ... } +function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { ... } - formData: corresponds to `{{$root}}`. Form data - constData: corresponds to `{{$const}}`. Constant data in global configuration - selfData: corresponds to `{{$self}}`. Used only for `ui.preview.value`, which refers to its own value - tempData: corresponds to `{{$temp}}`. Temporarily stored value +- selfPath: corresponds to `{{$path}}`. To use self object type the construction into dx: `__get({{$root}}, {{$path}})` - itemIdxChain: useful only for array items, refers to the index path of the current array, such as [1, 0] Some common examples are as follows: @@ -277,7 +278,7 @@ disabled: function(formData) { } // array item -disabled: function(formData, constData, selfData, tempData, itemIdxChain) { +disabled: function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { const [ i ] = itemIdxChain; return formData.persons[i].age < 18; } diff --git a/README_CN.md b/README_CN.md index 48d1467..d194b64 100644 --- a/README_CN.md +++ b/README_CN.md @@ -260,12 +260,13 @@ globalConfig: { > dx表达式也可用 `函数` 代替: -function(formData, constData, selfData, tempData, itemIdxChain) { ... } +function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { ... } - formData:对应于 `{{$root}}`。表单的数据 - constData: 对应于 `{{$const}}`。全局配置中的常量数据 - selfData:对应于 `{{$self}}`。只用于 `ui.preview.value`,指代本身的值 - tempData:对应于 `{{$temp}}`。临时存储的值 +- selfPath:对应于 `{{$path}}`。要使用自对象,请将结构键入dx:`__get({{$root}}, {{$path}})` - itemIdxChain:仅对数组项有用,指代当前所在的数组的索引路径,如[1, 0] 一些常见的例子如下: @@ -277,7 +278,7 @@ disabled: function(formData) { } // 数组项 -disabled: function(formData, constData, selfData, tempData, itemIdxChain) { +disabled: function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { const [ i ] = itemIdxChain; return formData.persons[i].age < 18; } diff --git a/packages/ncform-common/src/mixins/vue/control-mixin.js b/packages/ncform-common/src/mixins/vue/control-mixin.js index 18cb838..5249eef 100755 --- a/packages/ncform-common/src/mixins/vue/control-mixin.js +++ b/packages/ncform-common/src/mixins/vue/control-mixin.js @@ -56,6 +56,11 @@ export default { default: "" }, + paths: { + type: String, + default: "" + }, + value: { type: [String, Number, Boolean, Object, Array] }, @@ -160,7 +165,8 @@ export default { data: { rootData: this.formData, constData: this.globalConst, - tempData: this.tempData + tempData: this.tempData, + selfPath: this.paths } }); }, diff --git a/packages/ncform-common/src/mixins/vue/layout-array-mixin.js b/packages/ncform-common/src/mixins/vue/layout-array-mixin.js index d0a6675..51ae16a 100755 --- a/packages/ncform-common/src/mixins/vue/layout-array-mixin.js +++ b/packages/ncform-common/src/mixins/vue/layout-array-mixin.js @@ -151,7 +151,8 @@ export default { data: { rootData: this.formData, constData: this.globalConst, - tempData: this.tempData + tempData: this.tempData, + selfPath: this.paths + `[${(idx || "").split(",").slice(-1)[0]}]` } }); }, diff --git a/packages/ncform-common/src/mixins/vue/layout-object-mixin.js b/packages/ncform-common/src/mixins/vue/layout-object-mixin.js index f85d9c0..ebdf777 100755 --- a/packages/ncform-common/src/mixins/vue/layout-object-mixin.js +++ b/packages/ncform-common/src/mixins/vue/layout-object-mixin.js @@ -72,13 +72,14 @@ export default { }, methods: { - _analyzeVal(val) { + _analyzeVal(val, key = "") { return ncformUtils.smartAnalyzeVal(val, { idxChain: this.idxChain, data: { rootData: this.formData, constData: this.globalConst, - tempData: this.tempData + tempData: this.tempData, + selfPath: this.paths + (key !== "" ? `.${key}` : "") } }); }, diff --git a/packages/ncform-common/src/ncform-utils.js b/packages/ncform-common/src/ncform-utils.js index 6591a5b..452729d 100755 --- a/packages/ncform-common/src/ncform-utils.js +++ b/packages/ncform-common/src/ncform-utils.js @@ -417,7 +417,7 @@ const ncformUtils = { * @param {*} val * @param {*} * idxChain: 该值的索引链,即所在的路径中的所有数组中的索引,比如 persons[0].name[1].firstname,即该值为"0,1" - * data: {rootData: 代表$root的值, constData: 代表$const的值, selfData: 代表$self的值, tempData: 代表$tempData的值 } + * data: {rootData: 代表$root的值, constData: 代表$const的值, selfData: 代表$self的值, tempData: 代表$tempData的值, selfPath: 代表$path的值 } * 规则: * 1. 普通值直接返回 * 2. 函数类型返回执行后的值 @@ -427,7 +427,7 @@ const ncformUtils = { val, { idxChain = "", - data = { rootData: {}, constData: {}, selfData: {}, tempData: {} } + data = { rootData: {}, constData: {}, selfData: {}, tempData: {}, selfPath: "" } } = {} ) { return ncformUtils.smartAnalyze(val, { @@ -448,6 +448,10 @@ const ncformUtils = { { symbol: "$temp", value: data.tempData + }, + { + symbol: "$path", + value: data.selfPath } ] }); @@ -468,15 +472,68 @@ const ncformUtils = { */ smartAnalyze(val, { idxChain = "", data = [], expPrefix = "dx:" } = {}) { const valType = typeof val; + const idxChains = idxChain.split(","); let result; const __get = _get; const __map = _map; + const getSpec = tempVal => { + data.forEach((dataItem, idx) => { + if (tempVal.indexOf("[e]") >= 0) { + tempVal = tempVal.replace( + new RegExp(`\\{{\\s*\\${dataItem.symbol}(.*)}}`), + `__map(data[${idx}].value._value, '$1')` + ); + } else { + tempVal = tempVal.replace( + new RegExp(`\\{{\\s*\\${dataItem.symbol}(\\.?.*)}}`), + `__get(data[${idx}].value, '_value$1')` + ); // tempVal值:__get(_formData, 'persons[i].age') + } + }); + return tempVal; + } + + const fixSpec = tempVal => { + const brackets = tempVal.match(/\[.*?\]/g) || []; // brackets值:["[i]"] + brackets.forEach((bItem, idx) => { + // bItem值:"[i]" + if (bItem === "[e]") { + // e表达式 [e] + // before _map(data[0].value, '[e].id') + tempVal = tempVal + .replace(", '", "") + .replace(/\[e\]\.{0,1}/, ", '") + .replace(", ''", ""); + // after __map(data[0].value, 'id') + } else { + // i表达式或者索引数字 [i] or [0] + const bItemTemp = eval(bItem.replace(/i/g, idxChains[idx - 1])); // bItemTemp值:[0] (假设idxChain[0] == 0) + tempVal = tempVal.replace(bItem, `[${bItemTemp}]`); // tempVal值:__get(_formData, 'persons[0].age') + } + }); + return tempVal; + } + + const fixPath = tempVal => { + const brackets = tempVal.match(/\[.*?\]/g) || []; // brackets值:["[i]"] + brackets.forEach((bItem, idx) => { + if (bItem === "[i]") { + const bItemTemp = eval(bItem.replace(/i/g, idxChains[idx])); // bItemTemp值:[0] (假设idxChain[0] == 0) + tempVal = tempVal.replace(bItem, `[${bItemTemp}]`); // tempVal值:'persons[0].age' + } + }); + return tempVal; + } + data = data.map(( dataItem // 套多一层是为了支持原始类型,如string, number ) => Object.assign({}, dataItem, { - value: { _value: dataItem.value } + value: { + _value: dataItem.symbol === "$path" && typeof dataItem.value === "string" ? + fixPath(dataItem.value) : dataItem.value + } }) ); @@ -484,43 +541,11 @@ const ncformUtils = { case "string": if (val.indexOf(expPrefix) === 0) { // TODO daniel: 这里的替换可能需要再完善一下,可能会出错 - const idxChains = idxChain.split(","); // 假设val为:dx: {{$root.persons[i].age}} > 1 && {{$root.persons[i].age}} < 18 const matchs = val.match(/\{{.*?}}/g) || []; // matchs值:["{{$root.persons[i].age}}", "{{$root.persons[i].age}}"] matchs.forEach(mItem => { // mItem值:"{{$root.persons[i].age}}" - let tempVal = mItem; - data.forEach((dataItem, idx) => { - if (tempVal.indexOf("[e]") >= 0) { - tempVal = tempVal.replace( - new RegExp(`\\{{\\s*\\${dataItem.symbol}(.*)}}`), - `__map(data[${idx}].value._value, '$1')` - ); - } else { - tempVal = tempVal.replace( - new RegExp(`\\{{\\s*\\${dataItem.symbol}(\\.?.*)}}`), - `__get(data[${idx}].value, '_value$1')` - ); // tempVal值:__get(_formData, 'persons[i].age') - } - }); - const brackets = tempVal.match(/\[.*?\]/g) || []; // brackets值:["[i]"] - brackets.forEach((bItem, idx) => { - // bItem值:"[i]" - if (bItem === "[e]") { - // e表达式 [e] - // before _map(data[0].value, '[e].id') - tempVal = tempVal - .replace(", '", "") - .replace(/\[e\]\.{0,1}/, ", '") - .replace(", ''", ""); - // after __map(data[0].value, 'id') - } else { - // i表达式或者索引数字 [i] or [0] - const bItemTemp = eval(bItem.replace(/i/g, idxChains[idx - 1])); // bItemTemp值:[0] (假设idxChain[0] == 0) - tempVal = tempVal.replace(bItem, `[${bItemTemp}]`); // tempVal值:__get(_formData, 'persons[0].age') - } - }); - val = val.replace(mItem, tempVal); + val = val.replace(mItem, fixSpec(getSpec(mItem))); }); result = eval(val); } else { @@ -528,12 +553,10 @@ const ncformUtils = { } break; case "function": - const idxChains = idxChain - .split(",") - .filter(item => item) - .map(item => parseInt(item)); result = val( - ...data.map(item => item.value._value).concat([idxChains]) + ...data.map(item => item.value._value).concat([idxChains + .filter(item => item) + .map(item => parseInt(item))]) ); break; default: diff --git a/packages/ncform-common/test/unit/ncform-utils.js b/packages/ncform-common/test/unit/ncform-utils.js index 6188deb..9d1778d 100755 --- a/packages/ncform-common/test/unit/ncform-utils.js +++ b/packages/ncform-common/test/unit/ncform-utils.js @@ -887,11 +887,22 @@ describe('/src/ncform-utils.js', () => { assert(result === true); }); + it("smartAnalyzeVal - function get path", () => { + const rootData = { name: 'daniel', sign: '!' }; + const sayHi = 'hi'; + + const val = function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { + return `${sayHi} ${formData.name}${formData[selfPath]}` === 'hi daniel!'; + }; + const result = ncformUtils.smartAnalyzeVal(val, { data: { rootData, selfPath: "sign" } }); + assert(result === true); + }); + it("smartAnalyzeVal - function value array item", () => { let rootData = { users: [{ name: 'daniel' }, { name: 'sarah' }] }; const sayHi = 'hi'; - let val = function(formData, constData, selfData, tempData, itemIdxChain) { + let val = function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { return `${sayHi} ${formData.users[itemIdxChain[0]].name}` === 'hi sarah'; }; let result = ncformUtils.smartAnalyzeVal(val, { @@ -904,7 +915,7 @@ describe('/src/ncform-utils.js', () => { users: [{ address: [{ name: 'beijing' }, { name: 'shanghai' }] }] }; - val = function(formData, constData, selfData, tempData, itemIdxChain) { + val = function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { const [i, j] = itemIdxChain; return `${sayHi} ${formData.users[i].address[j].name}` === 'hi shanghai'; }; @@ -913,6 +924,15 @@ describe('/src/ncform-utils.js', () => { data: { rootData } }); assert(result === true); + + val = function(formData, constData, selfData, tempData, selfPath, itemIdxChain) { + return `${selfPath}` === 'users[0].address[1].name'; + }; + result = ncformUtils.smartAnalyzeVal(val, { + idxChain: '0,1', + data: { rootData, selfPath: "users[i].address[i].name" } + }); + assert(result === true); }); it("smartAnalyzeVal - special string", () => { @@ -950,6 +970,20 @@ describe('/src/ncform-utils.js', () => { data: { selfData: 'hello daniel' } }); assert(result === 'hello daniel'); + + val = 'dx: {{$path}}'; + result = ncformUtils.smartAnalyzeVal(val, { + idxChain: '0', + data: { selfPath: 'persons[i].age' } + }); + assert(result === 'persons[0].age'); + + val = 'dx: __get({{$root}}, {{$path}})'; + result = ncformUtils.smartAnalyzeVal(val, { + idxChain: '1', + data: { rootData, selfPath: 'persons[i].age' } + }); + assert(result === 20); }); it("smartAnalyzeVal - special string nested array", () => { @@ -957,12 +991,26 @@ describe('/src/ncform-utils.js', () => { persons: [[{ age: 12 }, { age: 18 }], [{ age: 50 }, { age: 80 }]] }; - const val = 'dx: {{$root.persons[i][i].age}} === 50'; - const result = ncformUtils.smartAnalyzeVal(val, { + let val = 'dx: {{$root.persons[i][i].age}} === 50'; + let result = ncformUtils.smartAnalyzeVal(val, { idxChain: '1,0', data: { rootData } }); assert(result === true); + + val = 'dx: __get({{$root}}, {{$path}}) === 50'; + result = ncformUtils.smartAnalyzeVal(val, { + idxChain: '1,0', + data: { rootData, selfPath: 'persons[i][i].age' } + }); + assert(result === true); + + val = 'dx: __get({{$root}}, {{$path}}) === 18'; + result = ncformUtils.smartAnalyzeVal(val, { + idxChain: '0,1', + data: { rootData, selfPath: 'persons[i][i].age' } + }); + assert(result === true); }); // --- smartAnalyze diff --git a/packages/ncform-theme-elementui/src/components/layout-comps/array-table.vue b/packages/ncform-theme-elementui/src/components/layout-comps/array-table.vue index d21af2d..3447201 100755 --- a/packages/ncform-theme-elementui/src/components/layout-comps/array-table.vue +++ b/packages/ncform-theme-elementui/src/components/layout-comps/array-table.vue @@ -175,8 +175,16 @@ methods: { analyzeItemVal(val, idxChain) { - return ncformUtils.smartAnalyzeVal(val, { idxChain: idxChain + '', data: { rootData: this.formData, constData: this.globalConst } }); + return ncformUtils.smartAnalyzeVal(val, { + idxChain: idxChain + '', + data: { + rootData: this.formData, + constData: this.globalConst, + selfPath: this.paths + `[${idxChain}]` + } + }); }, + showRequiredFlag(requiredConfig) { if (!requiredConfig) return false; diff --git a/packages/ncform-theme-elementui/src/components/layout-comps/object.vue b/packages/ncform-theme-elementui/src/components/layout-comps/object.vue index 7cdd6a8..de27954 100755 --- a/packages/ncform-theme-elementui/src/components/layout-comps/object.vue +++ b/packages/ncform-theme-elementui/src/components/layout-comps/object.vue @@ -10,15 +10,15 @@
@@ -43,14 +43,14 @@
@@ -179,7 +179,7 @@ export default { const { properties } = this.schema return Object.keys(properties).reduce((result, curkey) => { const curval = properties[curkey] - const remove = this._analyzeVal(curval.ui.remove) + const remove = this._analyzeVal(curval.ui.remove, curkey) if (remove) { const fullkey = paths ? paths + '.' + curkey : curkey @@ -196,13 +196,13 @@ export default { legendEnable(fieldSchema) { return fieldSchema.ui && fieldSchema.ui.showLegend && fieldSchema.ui.legend; }, - hidden(fieldSchema) { + hidden(fieldSchema, field) { if ( !fieldSchema || fieldSchema.ui.process === true || fieldSchema.ui.process === undefined ) { - return this._analyzeVal(fieldSchema.ui.hidden); + return this._analyzeVal(fieldSchema.ui.hidden, field); } let nodeCodeArr = this.globalConst.nodeCodeArr || [] if ((nodeCodeArr.includes(fieldSchema.ui.process) || fieldSchema.ui.process === this.globalConst.nodeUId)) { - return this._analyzeVal(fieldSchema.ui.hidden) + return this._analyzeVal(fieldSchema.ui.hidden, field) } else { return true } diff --git a/packages/ncform/src/components/vue-ncform/form-item.vue b/packages/ncform/src/components/vue-ncform/form-item.vue index e7cab45..989f8ca 100755 --- a/packages/ncform/src/components/vue-ncform/form-item.vue +++ b/packages/ncform/src/components/vue-ncform/form-item.vue @@ -6,7 +6,17 @@ @@ -15,7 +25,17 @@ @@ -180,7 +200,8 @@ export default { data: { rootData: this.formData, tempData: this.tempData, - constData: this.globalConfig.constants + constData: this.globalConfig.constants, + selfPath: this.paths } }); @@ -192,7 +213,8 @@ export default { data: { rootData: this.formData, tempData: this.tempData, - constData: this.globalConfig.constants + constData: this.globalConfig.constants, + selfPath: this.paths } }); } @@ -211,7 +233,8 @@ export default { rootData: this.formData, tempData: this.tempData, constData: this.globalConfig.constants, - selfData: modelVal + selfData: modelVal, + selfPath: this.paths } }); }, @@ -245,6 +268,7 @@ export default { .validate(val, rules, { formData: this.formData, tempData: this.tempData, + selfPath: this.paths, idxChain: idxChain, globalConfig: this.globalConfig }) @@ -314,6 +338,7 @@ export default { { formData: this.formData, tempData: this.tempData, + selfPath: this.paths, idxChain: this.idxChain, globalConfig: this.globalConfig }, @@ -334,7 +359,8 @@ export default { data: { rootData: this.formData, tempData: this.tempData, - constData: this.globalConfig.constants + constData: this.globalConfig.constants, + selfPath: this.paths } }) ); @@ -349,6 +375,7 @@ export default { .validate(val, rules, { formData: this.formData, tempData: this.tempData, + selfPath: this.paths, idxChain: this.idxChain, globalConfig: this.globalConfig }) diff --git a/packages/ncform/src/components/vue-ncform/layout-comps/array-table.vue b/packages/ncform/src/components/vue-ncform/layout-comps/array-table.vue index c03a2cb..5634977 100755 --- a/packages/ncform/src/components/vue-ncform/layout-comps/array-table.vue +++ b/packages/ncform/src/components/vue-ncform/layout-comps/array-table.vue @@ -131,7 +131,14 @@ methods: { analyzeItemVal(val, idxChain) { - return ncformUtils.smartAnalyzeVal(val, { idxChain: idxChain + '', data: { rootData: this.formData, constData: this.globalConst } }); + return ncformUtils.smartAnalyzeVal(val, { + idxChain: idxChain + '', + data: { + rootData: this.formData, + constData: this.globalConst, + selfPath: this.paths + `[${idxChain}]` + } + }); }, showRequiredFlag(requiredConfig) { diff --git a/packages/ncform/src/components/vue-ncform/layout-comps/object.vue b/packages/ncform/src/components/vue-ncform/layout-comps/object.vue index 60c5a1b..6a1650c 100755 --- a/packages/ncform/src/components/vue-ncform/layout-comps/object.vue +++ b/packages/ncform/src/components/vue-ncform/layout-comps/object.vue @@ -6,15 +6,15 @@
@@ -34,14 +34,14 @@
@@ -112,7 +112,7 @@ const { properties } = this.schema return Object.keys(properties).reduce((result, curkey) => { const curval = properties[curkey] - const remove = this._analyzeVal(curval.ui.remove) + const remove = this._analyzeVal(curval.ui.remove, curkey) if (!remove) { result[curkey] = curval diff --git a/packages/ncform/src/components/vue-ncform/ncform.vue b/packages/ncform/src/components/vue-ncform/ncform.vue index 3054902..aeea969 100755 --- a/packages/ncform/src/components/vue-ncform/ncform.vue +++ b/packages/ncform/src/components/vue-ncform/ncform.vue @@ -1,7 +1,13 @@