mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-21 07:55:56 +08:00
FieldAggregation calc
This commit is contained in:
parent
ad02c47a4b
commit
948afddcb1
|
@ -54,6 +54,11 @@ public class FieldAggregation implements TriggerAction {
|
|||
|
||||
private static final Log LOG = LogFactory.getLog(FieldAggregation.class);
|
||||
|
||||
/**
|
||||
* 归集到自己
|
||||
*/
|
||||
public static final String SOURCE_SELF = "$SELF$";
|
||||
|
||||
// 此触发器可能产生连锁反应
|
||||
// 如触发器 A 调用 B,而 B 又调用了 C ... 以此类推。此处记录其深度
|
||||
private static final ThreadLocal<Integer> CALL_CHAIN_DEPTH = new ThreadLocal<>();
|
||||
|
|
|
@ -21,6 +21,7 @@ package com.rebuild.web.admin.robot;
|
|||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.rebuild.server.business.trigger.impl.FieldAggregation;
|
||||
import com.rebuild.server.configuration.RobotApprovalManager;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
import com.rebuild.server.metadata.MetadataSorter;
|
||||
|
@ -36,9 +37,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author devezhao zhaofang123@gmail.com
|
||||
|
@ -53,7 +52,6 @@ public class FieldAggregationControll extends BaseControll {
|
|||
Entity sourceEntity = MetadataHelper.getEntity(getParameterNotNull(request, "source"));
|
||||
|
||||
List<String[]> entities = new ArrayList<>();
|
||||
Map<String, Integer> hasMany = new HashMap<>();
|
||||
for (Field refField : MetadataSorter.sortFields(sourceEntity, DisplayType.REFERENCE)) {
|
||||
if (MetadataHelper.isApprovalField(refField.getName())) {
|
||||
continue;
|
||||
|
@ -62,27 +60,11 @@ public class FieldAggregationControll extends BaseControll {
|
|||
Entity refEntity = refField.getReferenceEntity();
|
||||
String entityLabel = EasyMeta.getLabel(refEntity) + " (" + EasyMeta.getLabel(refField) + ")";
|
||||
entities.add(new String[] { refEntity.getName(), entityLabel, refField.getName() });
|
||||
|
||||
Integer many = hasMany.get(refEntity.getName());
|
||||
if (many == null) {
|
||||
many = 0;
|
||||
}
|
||||
hasMany.put(refEntity.getName(), many + 1);
|
||||
}
|
||||
|
||||
// 会出现同实体中多个字段引用同一实体的情况
|
||||
// 只有一个引用则不显示字段名称
|
||||
for (Map.Entry<String, Integer> e : hasMany.entrySet()) {
|
||||
if (e.getValue() == 1) {
|
||||
String entityName = e.getKey();
|
||||
for (String[] item : entities) {
|
||||
if (entityName.equals(item[0])) {
|
||||
item[1] = EasyMeta.getLabel(MetadataHelper.getEntity(entityName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 可归集到自己(通过主键字段)
|
||||
entities.add(new String[] { sourceEntity.getName(), EasyMeta.getLabel(sourceEntity) + " (源实体)", FieldAggregation.SOURCE_SELF});
|
||||
|
||||
writeSuccess(response, entities);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,52 @@
|
|||
color: #222;
|
||||
}
|
||||
|
||||
.field-aggregation .form-control-plaintext.FORMULA {
|
||||
border: 1px dotted #4c8bf5 !important;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
padding: 9px 10px;
|
||||
height: 37px !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.formula-calc ul li {
|
||||
width: 23%;
|
||||
display: inline-block;
|
||||
font-size: 0;
|
||||
padding: 0;
|
||||
margin: 1% !important;
|
||||
}
|
||||
|
||||
.formula-calc ul li>a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background-color: #eee;
|
||||
border-radius: 2px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.formula-calc ul li>a:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.formula-calc ul.fields li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formula-calc ul.fields li>a {
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.field-aggregation .form-control-plaintext.FORMULA:hover {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.auto-assign .select2-selection__rendered,
|
||||
.auto-share .select2-selection__rendered {
|
||||
display: block !important;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
const CALC_MODES = { 'SUM': '求和', 'COuNT': '计数', 'AVG': '平均值', 'MAX': '最大', 'MIN': '最小' }
|
||||
const CALC_MODES = { 'SUM': '求和', 'COUNT': '计数', 'AVG': '平均值', 'MAX': '最大', 'MIN': '最小', 'FORMULA': '计算公式' }
|
||||
|
||||
// ~~ 数据聚合
|
||||
// eslint-disable-next-line no-undef
|
||||
class ContentFieldAggregation extends ActionContentSpec {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className="field-aggregation">
|
||||
<form className="simple">
|
||||
|
@ -30,13 +32,13 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
<div className="items">
|
||||
{(!this.state.items || this.state.items.length === 0) ? null : this.state.items.map((item) => {
|
||||
return (<div key={'item-' + item.targetField}><div className="row">
|
||||
<div className="col-5"><span className="badge badge-warning">{this.__getFieldLabel(this.state.targetFields, item.targetField)}</span></div>
|
||||
<div className="col-5"><span className="badge badge-warning">{this.getFieldLabel(this.state.targetFields, item.targetField)}</span></div>
|
||||
<div className="col-2">
|
||||
<span className="zmdi zmdi-forward zmdi-hc-rotate-180"></span>
|
||||
<span className="badge badge-warning">{CALC_MODES[item.calcMode]}</span>
|
||||
</div>
|
||||
<div className="col-5">
|
||||
<span className="badge badge-warning">{this.__getFieldLabel(this.state.sourceFields, item.sourceField)}</span>
|
||||
<span className="badge badge-warning">{this.getFieldLabel(this.state.sourceFields, item.sourceField)}</span>
|
||||
<a className="del" title="移除" onClick={() => this.delItem(item.targetField)}><span className="zmdi zmdi-close"></span></a>
|
||||
</div>
|
||||
</div></div>)
|
||||
|
@ -61,12 +63,18 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
<p>聚合方式</p>
|
||||
</div>
|
||||
<div className="col-5">
|
||||
<select className="form-control form-control-sm" ref={(c) => this._sourceField = c}>
|
||||
{(this.state.sourceFields || []).map((item) => {
|
||||
return <option key={'sf-' + item[0]} value={item[0]}>{item[1]}</option>
|
||||
})}
|
||||
</select>
|
||||
<p>源字段</p>
|
||||
<div className={this.state.calcMode === 'FORMULA' ? '' : 'hide'}>
|
||||
<div className="form-control-plaintext FORMULA" onClick={() => renderRbcomp(<FormulaCalc fields={this.state.sourceFields} />)}>计算公式</div>
|
||||
<p>计算公式</p>
|
||||
</div>
|
||||
<div className={this.state.calcMode === 'FORMULA' ? 'hide' : ''}>
|
||||
<select className="form-control form-control-sm" ref={(c) => this._sourceField = c}>
|
||||
{(this.state.sourceFields || []).map((item) => {
|
||||
return <option key={'sf-' + item[0]} value={item[0]}>{item[1]}</option>
|
||||
})}
|
||||
</select>
|
||||
<p>源字段</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
|
@ -101,9 +109,7 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
$.get(`${rb.baseUrl}/admin/robot/trigger/field-aggregation-entities?source=${this.props.sourceEntity}`, (res) => {
|
||||
this.setState({ targetEntities: res.data }, () => {
|
||||
let s2te = $(this._targetEntity).select2({ placeholder: '选择聚合目标实体' })
|
||||
.on('change', () => {
|
||||
this.__changeTargetEntity()
|
||||
})
|
||||
.on('change', () => this.changeTargetEntity())
|
||||
s2te.trigger('change')
|
||||
|
||||
if (this.props.content && this.props.content.targetEntity) {
|
||||
|
@ -123,7 +129,7 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
}
|
||||
}
|
||||
|
||||
__changeTargetEntity() {
|
||||
changeTargetEntity() {
|
||||
// 清空现有规则
|
||||
this.setState({ items: [] })
|
||||
|
||||
|
@ -138,6 +144,7 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
this.setState({ sourceFields: res.data.source, targetFields: res.data.target }, () => {
|
||||
let s2sf = $(this._sourceField).select2({ placeholder: '选择源字段' })
|
||||
let s2cm = $(this._calcMode).select2({ placeholder: '选择聚合方式' })
|
||||
.on('change', (e) => this.setState({ calcMode: e.target.value }))
|
||||
let s2tf = $(this._targetField).select2({ placeholder: '选择目标字段' })
|
||||
this.__select2.push(s2sf)
|
||||
this.__select2.push(s2cm)
|
||||
|
@ -150,7 +157,8 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
}
|
||||
})
|
||||
}
|
||||
__getFieldLabel(list, field) {
|
||||
|
||||
getFieldLabel(list, field) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i][0] === field) {
|
||||
return list[i][1]
|
||||
|
@ -179,6 +187,7 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
this.setState({ items: items })
|
||||
}
|
||||
}
|
||||
|
||||
delItem(targetField) {
|
||||
let items = (this.state.items || []).filter((item) => {
|
||||
return item.targetField !== targetField
|
||||
|
@ -206,6 +215,7 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
filter={that._advFilter__data}
|
||||
confirm={that._saveAdvFilter} />, null, function () { that._advFilter = this })
|
||||
}
|
||||
|
||||
_saveAdvFilter = (filter) => {
|
||||
this._advFilter__data = filter
|
||||
let num = filter && filter.items ? filter.items.length : 0
|
||||
|
@ -213,6 +223,45 @@ class ContentFieldAggregation extends ActionContentSpec {
|
|||
}
|
||||
}
|
||||
|
||||
// ~公式计算器
|
||||
class FormulaCalc extends RbAlert {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { ...props }
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
return (
|
||||
<div className="row formula-calc">
|
||||
<div className="col-6">
|
||||
<ul className="list-unstyled fields">
|
||||
{this.props.fields.map((item) => {
|
||||
return <li key={`flag-${item}`}><a onClick={() => this.handleInput(item)}>{item[1]}</a></li>
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<ul className="list-unstyled numbers">
|
||||
{['+', 1, 2, 3, '-', 4, 5, 6, '×', 7, 8, 9, '÷', '(', ')', 0].map((item) => {
|
||||
return <li className="list-inline-item" key={`flag-${item}`}><a onClick={() => this.handleInput(item)}>{item}</a></li>
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleInput(v) {
|
||||
console.log(v)
|
||||
}
|
||||
|
||||
confirm = () => {
|
||||
typeof this.props.call === 'function' && this.props.call(this.state || {})
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
renderContentComp = function (props) {
|
||||
// eslint-disable-next-line no-undef
|
||||
|
|
Loading…
Reference in a new issue