diff --git a/@rbv b/@rbv index 5077481be..cf372ef8f 160000 --- a/@rbv +++ b/@rbv @@ -1 +1 @@ -Subproject commit 5077481be27b5c21e2ecc687149718f9498c19a8 +Subproject commit cf372ef8fec69b191700374676b2c994d12ae8b7 diff --git a/src/main/java/com/rebuild/core/metadata/impl/EasyMeta.java b/src/main/java/com/rebuild/core/metadata/impl/EasyMeta.java index 78fdc8871..aa160916e 100644 --- a/src/main/java/com/rebuild/core/metadata/impl/EasyMeta.java +++ b/src/main/java/com/rebuild/core/metadata/impl/EasyMeta.java @@ -118,6 +118,7 @@ public class EasyMeta implements BaseMeta { * * @param name * @return + * @see FieldExtConfigProps */ public String getExtraAttr(String name) { return getExtraAttrs().getString(name); diff --git a/src/main/java/com/rebuild/web/commons/MetadataGetting.java b/src/main/java/com/rebuild/web/commons/MetadataGetting.java index 36730269d..d115c4832 100644 --- a/src/main/java/com/rebuild/web/commons/MetadataGetting.java +++ b/src/main/java/com/rebuild/web/commons/MetadataGetting.java @@ -19,6 +19,7 @@ import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.metadata.MetadataSorter; import com.rebuild.core.metadata.impl.DisplayType; import com.rebuild.core.metadata.impl.EasyMeta; +import com.rebuild.core.metadata.impl.FieldExtConfigProps; import com.rebuild.core.privileges.PrivilegesManager; import com.rebuild.core.support.state.StateHelper; import com.rebuild.web.BaseController; @@ -167,12 +168,14 @@ public class MetadataGetting extends BaseController { map.put("updatable", field.isUpdatable()); DisplayType dt = EasyMeta.getDisplayType(field); - if (dt == DisplayType.REFERENCE) { + if (dt == DisplayType.REFERENCE || dt == DisplayType.N2NREFERENCE) { Entity refEntity = field.getReferenceEntity(); Field nameField = MetadataHelper.getNameField(refEntity); map.put("ref", new String[]{refEntity.getName(), EasyMeta.getDisplayType(nameField).name()}); } else if (dt == DisplayType.STATE) { map.put("stateClass", StateHelper.getSatetClass(field).getName()); + } else if (dt == DisplayType.CLASSIFICATION) { + map.put("classification", easyField.getExtraAttr(FieldExtConfigProps.CLASSIFICATION_USE)); } return map; } diff --git a/src/main/resources/web/.eslintrc.js b/src/main/resources/web/.eslintrc.js index 6a4c52897..f916eb44e 100644 --- a/src/main/resources/web/.eslintrc.js +++ b/src/main/resources/web/.eslintrc.js @@ -91,7 +91,6 @@ module.exports = { ConfigFormDlg: true, RbPreview: true, $countdownButton: true, - ChartSelect: true, Share2: true, $stopEvent: true, $addResizeHandler: true, @@ -105,6 +104,7 @@ module.exports = { $fromNow: true, $expired: true, $L: true, - $isTrue: true + $isTrue: true, + $fieldIsCompatible: true }, } diff --git a/src/main/resources/web/admin/metadata/auto-fillin.html b/src/main/resources/web/admin/metadata/auto-fillin.html index 0fff66c3b..cb50e615b 100644 --- a/src/main/resources/web/admin/metadata/auto-fillin.html +++ b/src/main/resources/web/admin/metadata/auto-fillin.html @@ -114,6 +114,7 @@ referenceEntity: '[[${referenceEntity}]]', } + diff --git a/src/main/resources/web/assets/js/charts/dashboard.js b/src/main/resources/web/assets/js/charts/dashboard.js index c6b73f947..1a404093d 100644 --- a/src/main/resources/web/assets/js/charts/dashboard.js +++ b/src/main/resources/web/assets/js/charts/dashboard.js @@ -111,6 +111,7 @@ $(document).ready(function () { chart.w = chart.h = 4 add_widget(chart) } + // eslint-disable-next-line react/jsx-no-undef renderRbcomp(, null, function () { dlgChartSelect = this this.setState({ appended: appended }) diff --git a/src/main/resources/web/assets/js/metadata/auto-fillin.js b/src/main/resources/web/assets/js/metadata/auto-fillin.js index d30330fad..cb5772730 100644 --- a/src/main/resources/web/assets/js/metadata/auto-fillin.js +++ b/src/main/resources/web/assets/js/metadata/auto-fillin.js @@ -16,10 +16,10 @@ $(document).ready(() => { }) const loadRules = () => { - $.get('../auto-fillin-list?field=' + wpc.fieldName, (res) => { - const tbody = $('#dataList tbody').empty() + $.get(`../auto-fillin-list?field=${wpc.fieldName}`, (res) => { + const $tbody = $('#dataList tbody').empty() $(res.data).each(function () { - let tr = $('').appendTo(tbody) + let tr = $('').appendTo($tbody) $('
' + this.targetFieldLabel + '
').appendTo(tr) $('' + this.sourceFieldLabel + '').appendTo(tr) const extc = this.extConfig @@ -63,7 +63,7 @@ class DlgRuleEdit extends RbFormHandler { render() { return ( - (this._dlg = c)} disposeOnHide={true}> + (this._dlg = c)} disposeOnHide={true}>
@@ -150,7 +150,7 @@ class DlgRuleEdit extends RbFormHandler { placeholder: $L('SelectSome,Field'), allowClear: false, }) - .on('change', (e) => this.__renderTargetFields(e.target.value)) + .on('change', (e) => this._renderTargetFields(e.target.value)) this.__select2.push(s2source) if (this.props.sourceField) { @@ -168,40 +168,20 @@ class DlgRuleEdit extends RbFormHandler { }) }) } - __renderTargetFields(s) { - const source = this.__sourceFieldsCache.find((x) => { - return s === x.name - }) - let canFillinByType = CAN_FILLIN_MAPPINGS[source.type] || [] - canFillinByType.push('TEXT') - canFillinByType.push('NTEXT') + + _renderTargetFields(s) { + const source = this.__sourceFieldsCache.find((x) => s === x.name) // 显示兼容的目标字段 - let tFields = [] + const targetFields = [] $(this.__targetFieldsCache).each(function () { - if ( - !this.creatable || - this.name === wpc.fieldName || - this.type === 'SERIES' || - this.type === 'MULTISELECT' || - this.type === 'PICKLIST' || - (source.type === 'FILE' && this.type !== 'FILE') || - (source.type === 'IMAGE' && this.type !== 'IMAGE') || - (source.type === 'AVATAR' && this.type !== 'AVATAR') - ) - return - - if (source.type === this.type || canFillinByType.includes(this.type)) { - if (source.type === 'REFERENCE') { - if (source.ref && this.ref && source.ref[0] === this.ref[0]) tFields.push(this) - } else if (source.type === 'STATE') { - if (source.stateClass && source.stateClass === this.stateClass) tFields.push(this) - } else { - tFields.push(this) - } + if (this.creatable && this.name !== wpc.fieldName && $fieldIsCompatible(source, this)) { + targetFields.push(this) } }) - this.setState({ targetFields: tFields }) + this.setState({ targetFields: targetFields }, () => { + if (targetFields.length > 0) this.__select2[0].val(targetFields[0].name) + }) } handleChange(e) { @@ -237,10 +217,3 @@ class DlgRuleEdit extends RbFormHandler { }) } } - -const CAN_FILLIN_MAPPINGS = { - NUMBER: ['DECIMAL'], - DECIMAL: ['NUMBER'], - DATE: ['DATETIME'], - DATETIME: ['DATE'], -} diff --git a/src/main/resources/web/assets/js/metadata/field-compatible.js b/src/main/resources/web/assets/js/metadata/field-compatible.js new file mode 100644 index 000000000..8044fce92 --- /dev/null +++ b/src/main/resources/web/assets/js/metadata/field-compatible.js @@ -0,0 +1,53 @@ +/* +Copyright (c) REBUILD and/or its owners. All rights reserved. + +rebuild is dual-licensed under commercial and open source licenses (GPLv3). +See LICENSE and COMMERCIAL in the project root for license information. +*/ + +// 字段类型兼容 + +const FT_COMPATIBLE = { + NUMBER: ['DECIMAL'], + DECIMAL: ['NUMBER'], + DATE: ['DATETIME'], + DATETIME: ['DATE'], + TEXT: ['*'], + NTEXT: ['*'], +} + +/** + * 字段兼容判断 + * see backend `FieldValueCompatibleConversion.java` + * + * @param s 源字段 + * @param t 目标字段 + * @returns {boolean} + */ +// eslint-disable-next-line no-unused-vars +function $fieldIsCompatible(s, t) { + // 不支持 + if (t.type === 'SERIES') return false + if (t.type === 'MULTISELECT') return false + if (t.type === 'PICKLIST') return false + + // 必须对应 + if (s.type === 'FILE' && t.type !== 'FILE') return false + if (s.type === 'IMAGE' && t.type !== 'IMAGE') return false + if (s.type === 'AVATAR' && t.type !== 'AVATAR') return false + + // 判断附加参数 + if (t.type === 'REFERENCE' || t.type === 'N2NREFERENCE') { + return t.ref && s.ref && t.ref[0] === s.ref[0] + } + if (t.type === 'CLASSIFICATION') { + return t.classification && t.classification === s.classification + } + if (t.type === 'STATE') { + return t.stateClass && t.stateClass === s.stateClass + } + + if (t.type === s.type) return true + const allow = FT_COMPATIBLE[t.type] || [] + return allow.includes('*') || allow.includes(s.type) +} diff --git a/src/main/resources/web/assets/js/print-preview.js b/src/main/resources/web/assets/js/print-preview.js index e6cc34e49..7c73c6789 100644 --- a/src/main/resources/web/assets/js/print-preview.js +++ b/src/main/resources/web/assets/js/print-preview.js @@ -4,6 +4,7 @@ Copyright (c) REBUILD and/or its owners. All rights re rebuild is dual-licensed under commercial and open source licenses (GPLv3). See LICENSE and COMMERCIAL in the project root for license information. */ +// 打印视图 const wpc = window.__PageConfig $(document).ready(() => { @@ -32,8 +33,8 @@ class PreviewTable extends React.Component { {rows.map((row, idx) => { - let c1 = row[0] - let c2 = row[1] || {} + const c1 = row[0] + const c2 = row[1] || {} if (row.length === 1) { if (c1.field === '$DIVIDER$') { return ( @@ -72,7 +73,7 @@ class PreviewTable extends React.Component { return (
- + Avatar
) @@ -84,7 +85,7 @@ class PreviewTable extends React.Component { return (
    {item.value.map((x) => { - return
  • {$fileCutName(x)}
  • + return
  • {$fileCutName(x)}
  • })}
) @@ -93,8 +94,8 @@ class PreviewTable extends React.Component {
    {item.value.map((x) => { return ( -
  • - +
  • + IMG
  • ) })} @@ -104,7 +105,7 @@ class PreviewTable extends React.Component { return (
    - + Avatar
    ) @@ -132,12 +133,24 @@ class PreviewTable extends React.Component { ) + } else if (item.type === 'N2NREFERENCE') { + return ( +
      + {item.value.map((x) => { + return
    • {__formatRefText(x)}
    • + })} +
    + ) } else if (typeof item.value === 'object') { - let text = item.value.text - if (!text && item.value.id) text = `@${item.value.id.toUpperCase()}` - return text + return __formatRefText(item.value) } else { return item.value } } } + +const __formatRefText = function (value) { + const text = value.text + if (!text && value.id) return `@${value.id.toUpperCase()}` + else return text +} diff --git a/src/main/resources/web/assets/js/rb-advfilter.js b/src/main/resources/web/assets/js/rb-advfilter.js index b4032cb78..06657d5d1 100644 --- a/src/main/resources/web/assets/js/rb-advfilter.js +++ b/src/main/resources/web/assets/js/rb-advfilter.js @@ -398,7 +398,10 @@ class FilterItem extends React.Component { } } else if (fieldType === 'BOOL') { op = ['EQ'] + } else if (fieldType === 'N2NREFERENCE') { + op = [] } + op.push('NL', 'NT') if (this.isApprovalState()) op = ['IN', 'NIN'] diff --git a/src/main/resources/web/assets/js/rb-datalist.append.js b/src/main/resources/web/assets/js/rb-datalist.append.js index 375e28de3..dd562b83b 100644 --- a/src/main/resources/web/assets/js/rb-datalist.append.js +++ b/src/main/resources/web/assets/js/rb-datalist.append.js @@ -277,7 +277,7 @@ class BatchUpdateEditor extends React.Component { componentWillUnmount() { this.__select2.forEach((item) => item.select2('destroy')) this.__select2 = null - this.__destroyLastValueComp() + this._destroyLastValueComp() } render() { @@ -341,7 +341,7 @@ class BatchUpdateEditor extends React.Component { } } - __destroyLastValueComp() { + _destroyLastValueComp() { if (this.__lastSelect2) { this.__lastSelect2.select2('destroy') this.__lastSelect2 = null @@ -356,7 +356,7 @@ class BatchUpdateEditor extends React.Component { // Unchanged if (prevState.selectField === this.state.selectField && prevState.selectOp === this.state.selectOp) return if (this.state.selectOp === 'NULL') return - this.__destroyLastValueComp() + this._destroyLastValueComp() const field = this.props.fields.find((item) => { return this.state.selectField === item.name @@ -365,7 +365,7 @@ class BatchUpdateEditor extends React.Component { if (field.type === 'REFERENCE' || field.type === 'CLASSIFICATION') { this.__lastSelect2 = $initReferenceSelect2(this._value, { name: field.name, - label: field.label, + placeholder: $L('NewValue'), entity: this.props.entity, searchType: field.type === 'CLASSIFICATION' ? 'classification' : null, }) diff --git a/src/main/resources/web/assets/js/rb-datalist.js b/src/main/resources/web/assets/js/rb-datalist.js index 740bd73f6..35a370ca4 100644 --- a/src/main/resources/web/assets/js/rb-datalist.js +++ b/src/main/resources/web/assets/js/rb-datalist.js @@ -1237,6 +1237,7 @@ const ChartsWidget = { this.__chartSelect.setState({ appended: ChartsWidget.__currentCharts() }) return } + // eslint-disable-next-line react/jsx-no-undef renderRbcomp( this.renderChart(c, true)} entity={wpc.entity[0]} />, null, function () { ChartsWidget.__chartSelect = this this.setState({ appended: ChartsWidget.__currentCharts() }) diff --git a/src/main/resources/web/assets/js/rb-page.js b/src/main/resources/web/assets/js/rb-page.js index 5ae689b65..5b4023b4f 100644 --- a/src/main/resources/web/assets/js/rb-page.js +++ b/src/main/resources/web/assets/js/rb-page.js @@ -490,7 +490,7 @@ var $unmount = function (container, delay, keepContainer) { var $initReferenceSelect2 = function (el, field) { var search_input = null return $(el).select2({ - placeholder: $L('SelectSome').replace('{0}', field.label), + placeholder: field.placeholder || $L('SelectSome').replace('{0}', field.label), minimumInputLength: 0, maximumSelectionLength: $(el).attr('multiple') ? 999 : 2, ajax: {