mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
n2nref compatible
This commit is contained in:
parent
918f503f69
commit
2f11f5be2e
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 5077481be27b5c21e2ecc687149718f9498c19a8
|
||||
Subproject commit cf372ef8fec69b191700374676b2c994d12ae8b7
|
|
@ -118,6 +118,7 @@ public class EasyMeta implements BaseMeta {
|
|||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @see FieldExtConfigProps
|
||||
*/
|
||||
public String getExtraAttr(String name) {
|
||||
return getExtraAttrs().getString(name);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@
|
|||
referenceEntity: '[[${referenceEntity}]]',
|
||||
}
|
||||
</script>
|
||||
<script th:src="@{/assets/js/metadata/field-compatible.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/auto-fillin.js}" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -111,6 +111,7 @@ $(document).ready(function () {
|
|||
chart.w = chart.h = 4
|
||||
add_widget(chart)
|
||||
}
|
||||
// eslint-disable-next-line react/jsx-no-undef
|
||||
renderRbcomp(<ChartSelect key="ChartSelect" select={select} />, null, function () {
|
||||
dlgChartSelect = this
|
||||
this.setState({ appended: appended })
|
||||
|
|
|
@ -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 = $('<tr></tr>').appendTo(tbody)
|
||||
let tr = $('<tr></tr>').appendTo($tbody)
|
||||
$('<td><div>' + this.targetFieldLabel + '</div></td>').appendTo(tr)
|
||||
$('<td>' + this.sourceFieldLabel + '</div></td>').appendTo(tr)
|
||||
const extc = this.extConfig
|
||||
|
@ -63,7 +63,7 @@ class DlgRuleEdit extends RbFormHandler {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<RbModal title="回填规则" ref={(c) => (this._dlg = c)} disposeOnHide={true}>
|
||||
<RbModal title={$L('FillbackRule')} ref={(c) => (this._dlg = c)} disposeOnHide={true}>
|
||||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('SourceField')}</label>
|
||||
|
@ -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'],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> 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)
|
||||
}
|
|
@ -4,6 +4,7 @@ Copyright (c) REBUILD <https://getrebuild.com/> 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 {
|
|||
<table className="table table-bordered table-sm table-fixed">
|
||||
<tbody>
|
||||
{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 (
|
||||
<div className="img-field avatar">
|
||||
<span className="img-thumbnail img-upload">
|
||||
<img src={`${rb.baseUrl}/assets/img/avatar.png`} />
|
||||
<img src={`${rb.baseUrl}/assets/img/avatar.png`} alt="Avatar" />
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
@ -84,7 +85,7 @@ class PreviewTable extends React.Component {
|
|||
return (
|
||||
<ul className="m-0 p-0 pl-3">
|
||||
{item.value.map((x) => {
|
||||
return <li key={`file-${x}`}>{$fileCutName(x)}</li>
|
||||
return <li key={x}>{$fileCutName(x)}</li>
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
|
@ -93,8 +94,8 @@ class PreviewTable extends React.Component {
|
|||
<ul className="list-inline m-0">
|
||||
{item.value.map((x) => {
|
||||
return (
|
||||
<li className="list-inline-item" key={`image-${x}`}>
|
||||
<img src={`${rb.baseUrl}/filex/img/${x}?imageView2/2/w/100/interlace/1/q/100`} />
|
||||
<li className="list-inline-item" key={x}>
|
||||
<img src={`${rb.baseUrl}/filex/img/${x}?imageView2/2/w/100/interlace/1/q/100`} alt="IMG" />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
@ -104,7 +105,7 @@ class PreviewTable extends React.Component {
|
|||
return (
|
||||
<div className="img-field avatar">
|
||||
<span className="img-thumbnail img-upload">
|
||||
<img src={`${rb.baseUrl}/filex/img/${item.value}?imageView2/2/w/100/interlace/1/q/100`} />
|
||||
<img src={`${rb.baseUrl}/filex/img/${item.value}?imageView2/2/w/100/interlace/1/q/100`} alt="Avatar" />
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
@ -132,12 +133,24 @@ class PreviewTable extends React.Component {
|
|||
</span>
|
||||
</div>
|
||||
)
|
||||
} else if (item.type === 'N2NREFERENCE') {
|
||||
return (
|
||||
<ul className="m-0 p-0 pl-3">
|
||||
{item.value.map((x) => {
|
||||
return <li key={x.id}>{__formatRefText(x)}</li>
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
} 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
|
||||
}
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -1237,6 +1237,7 @@ const ChartsWidget = {
|
|||
this.__chartSelect.setState({ appended: ChartsWidget.__currentCharts() })
|
||||
return
|
||||
}
|
||||
// eslint-disable-next-line react/jsx-no-undef
|
||||
renderRbcomp(<ChartSelect select={(c) => this.renderChart(c, true)} entity={wpc.entity[0]} />, null, function () {
|
||||
ChartsWidget.__chartSelect = this
|
||||
this.setState({ appended: ChartsWidget.__currentCharts() })
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in a new issue