mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
advfilter
This commit is contained in:
parent
8f0f5b28de
commit
68813aa747
|
@ -25,13 +25,13 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import com.rebuild.server.Application;
|
||||
import com.rebuild.server.metadata.EntityHelper;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
|
||||
import cn.devezhao.commons.ObjectUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.dialect.Dialect;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import cn.devezhao.persist4j.util.StringHelper;
|
||||
import cn.devezhao.persist4j.util.support.Table;
|
||||
|
||||
/**
|
||||
|
@ -61,20 +61,16 @@ public class Entity2Schema extends Field2Schema {
|
|||
* @return
|
||||
*/
|
||||
public String create(String entityLabel, String comments) {
|
||||
String entityName = toPinyinString(entityLabel);
|
||||
String entityName = toPinyinName(entityLabel);
|
||||
while (true) {
|
||||
Object exists = Application.createQueryNoFilter(
|
||||
"select entityId from MetaEntity where entityName = ?")
|
||||
.setParameter(1, entityName)
|
||||
.unique();
|
||||
if (exists != null) {
|
||||
entityName += (1000 + RandomUtils.nextInt(8999));
|
||||
if (MetadataHelper.containsEntity(entityName)) {
|
||||
entityName += (10 + RandomUtils.nextInt(89));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String physicalName = "T__" + StringHelper.hyphenate(entityName).toUpperCase();
|
||||
String physicalName = "T__" + entityName.toUpperCase();
|
||||
|
||||
Object maxTypeCode[] = Application.createQueryNoFilter(
|
||||
"select min(typeCode) from MetaEntity").unique();
|
||||
|
|
|
@ -72,10 +72,10 @@ public class Field2Schema {
|
|||
* @return
|
||||
*/
|
||||
public String create(Entity entity, String fieldLabel, DisplayType type, String comments, String refEntity) {
|
||||
String fieldName = toPinyinString(fieldLabel);
|
||||
String fieldName = toPinyinName(fieldLabel);
|
||||
while (true) {
|
||||
if (entity.containsField(fieldName)) {
|
||||
fieldName += (1000 + RandomUtils.nextInt(8999));
|
||||
fieldName += (10 + RandomUtils.nextInt(89));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ public class Field2Schema {
|
|||
Record record = EntityHelper.forNew(EntityHelper.MetaField, user);
|
||||
record.setString("belongEntity", entity.getName());
|
||||
record.setString("fieldName", fieldName);
|
||||
String physicalName = StringHelper.hyphenate(fieldName).toUpperCase();
|
||||
String physicalName = fieldName.toUpperCase();
|
||||
record.setString("physicalName", physicalName);
|
||||
record.setString("fieldLabel", fieldLabel);
|
||||
record.setString("displayType", displayType.name());
|
||||
|
@ -172,7 +172,7 @@ public class Field2Schema {
|
|||
* @param text
|
||||
* @return
|
||||
*/
|
||||
protected String toPinyinString(final String text) {
|
||||
protected String toPinyinName(final String text) {
|
||||
String identifier = text;
|
||||
try {
|
||||
identifier = PinyinHelper.convertToPinyinString(text, "", PinyinFormat.WITHOUT_TONE);
|
||||
|
@ -188,10 +188,12 @@ public class Field2Schema {
|
|||
if (!CharSet.ASCII_ALPHA.contains(start)) {
|
||||
identifier = "a" + identifier;
|
||||
}
|
||||
|
||||
identifier = identifier.toLowerCase();
|
||||
if (identifier.length() > 42) {
|
||||
identifier = identifier.substring(0, 42);
|
||||
}
|
||||
|
||||
if (!StringHelper.isIdentifier(identifier)) {
|
||||
throw new MetadataException("无效名称 : " + text);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
package com.rebuild.server.metadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections4.map.CaseInsensitiveMap;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.dom4j.Document;
|
||||
|
@ -44,9 +44,9 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
|
|||
private static final Log LOG = LogFactory.getLog(DynamicMetadataFactory.class);
|
||||
|
||||
// <Name, [ID, COMMENTS, ICON]>
|
||||
private static final Map<String, Object[]> ENTITY_EXTMETA = new HashMap<>();
|
||||
private static final Map<String, Object[]> ENTITY_EXTMETA = new CaseInsensitiveMap<>();
|
||||
// <Name, [ID, COMMENTS]>
|
||||
private static final Map<String, Object[]> FIELD_EXTMETA = new HashMap<>();
|
||||
private static final Map<String, Object[]> FIELD_EXTMETA = new CaseInsensitiveMap<>();
|
||||
|
||||
public DynamicMetadataFactory(String configLocation, Dialect dialect) {
|
||||
super(configLocation, dialect);
|
||||
|
@ -69,30 +69,26 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
|
|||
private void appendConfig4Db(Document config) {
|
||||
final Element rootElement = config.getRootElement();
|
||||
|
||||
Object[][] customentity = Application.createQueryNoFilter(
|
||||
Object[][] customEntity = Application.createQueryNoFilter(
|
||||
"select typeCode,entityName,physicalName,entityLabel,entityId,comments,icon,nameField from MetaEntity order by createdOn")
|
||||
.array();
|
||||
for (Object[] custom : customentity) {
|
||||
int typeCode = (int) custom[0];
|
||||
for (Object[] custom : customEntity) {
|
||||
String name = (String) custom[1];
|
||||
String physicalName = (String) custom[2];
|
||||
String description = (String) custom[3];
|
||||
|
||||
Element entity = rootElement.addElement("entity");
|
||||
entity.addAttribute("type-code", typeCode + "")
|
||||
entity.addAttribute("type-code", custom[0] + "")
|
||||
.addAttribute("name", name)
|
||||
.addAttribute("physical-name", physicalName)
|
||||
.addAttribute("description", description)
|
||||
.addAttribute("physical-name", (String) custom[2])
|
||||
.addAttribute("description", (String) custom[3])
|
||||
.addAttribute("parent", "false")
|
||||
.addAttribute("name-field", (String) custom[7]);
|
||||
ENTITY_EXTMETA.put(name, new Object[] { custom[4], custom[5], custom[6] });
|
||||
}
|
||||
|
||||
Object[][] customfield = Application.createQueryNoFilter(
|
||||
"select belongEntity,fieldName,physicalName,fieldLabel,displayType,nullable,creatable,updatable,precision,maxLength,defaultValue,refEntity,cascade,fieldId,comments,extConfig"
|
||||
+ " from MetaField order by createdOn")
|
||||
Object[][] customFields = Application.createQueryNoFilter(
|
||||
"select belongEntity,fieldName,physicalName,fieldLabel,displayType,nullable,creatable,updatable,precision,"
|
||||
+ "maxLength,defaultValue,refEntity,cascade,fieldId,comments,extConfig from MetaField order by createdOn")
|
||||
.array();
|
||||
for (Object[] custom : customfield) {
|
||||
for (Object[] custom : customFields) {
|
||||
String entityName = (String) custom[0];
|
||||
String fieldName = (String) custom[1];
|
||||
Element entityElement = (Element) rootElement.selectSingleNode("entity[@name='" + entityName + "']");
|
||||
|
@ -117,7 +113,7 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
|
|||
DisplayType dt = DisplayType.valueOf((String) custom[4]);
|
||||
field.addAttribute("type", dt.getFieldType().getName());
|
||||
|
||||
FIELD_EXTMETA.put(entityName + "__" + fieldName, new Object[] { custom[13], custom[14], dt, custom[15] });
|
||||
FIELD_EXTMETA.put(entityName + "." + fieldName, new Object[] { custom[13], custom[14], dt, custom[15] });
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
|
@ -139,7 +135,6 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
|
|||
* @return
|
||||
*/
|
||||
protected Object[] getFieldExtmeta(String entity, String field) {
|
||||
String key = entity + "__" + field;
|
||||
return FIELD_EXTMETA.get(key);
|
||||
return FIELD_EXTMETA.get(entity + "." + field);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
package com.rebuild.server.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.rebuild.server.entityhub.DisplayType;
|
||||
|
@ -114,21 +116,16 @@ public class PortalMetaSorter {
|
|||
}
|
||||
|
||||
/**
|
||||
* 排序
|
||||
* 按 Label 排序
|
||||
*
|
||||
* @param metas
|
||||
*/
|
||||
private static void sortBaseMeta(BaseMeta[] metas) {
|
||||
// ArrayUtils.reverse(metas);
|
||||
|
||||
// TODO 元数据排序算法
|
||||
|
||||
// Arrays.sort(metas, new Comparator<BaseMeta>() {
|
||||
// @Override
|
||||
// public int compare(BaseMeta a, BaseMeta b) {
|
||||
// int c = EasyMeta.getLabel(a).compareToIgnoreCase(EasyMeta.getLabel(b));
|
||||
// return c;
|
||||
// }
|
||||
// });
|
||||
Arrays.sort(metas, new Comparator<BaseMeta>() {
|
||||
@Override
|
||||
public int compare(BaseMeta o1, BaseMeta o2) {
|
||||
return EasyMeta.getLabel(o1).compareToIgnoreCase(EasyMeta.getLabel(o2));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,12 +69,12 @@ public class AdvFilterParser {
|
|||
|
||||
public String toSqlWhere() {
|
||||
JSONArray items = filterExp.getJSONArray("items");
|
||||
JSONObject qvalues = filterExp.getJSONObject("values");
|
||||
JSONObject values = filterExp.getJSONObject("values");
|
||||
String equation = StringUtils.defaultIfBlank(filterExp.getString("equation"), "OR");
|
||||
|
||||
List<String> itemsSql = new ArrayList<>();
|
||||
for (Object item : items) {
|
||||
String itemSql = parseItem((JSONObject) item, qvalues);
|
||||
String itemSql = parseItem((JSONObject) item, values);
|
||||
if (itemSql != null) {
|
||||
itemsSql.add(itemSql);
|
||||
}
|
||||
|
@ -89,17 +89,18 @@ public class AdvFilterParser {
|
|||
return "( " + StringUtils.join(itemsSql, " and ") + " )";
|
||||
}
|
||||
|
||||
// TODO 高级表达式
|
||||
// TODO 高级表达式 eg. (1 AND 2) or (3 AND 4)
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param item
|
||||
* @param qvalues
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
protected String parseItem(JSONObject item, JSONObject qvalues) {
|
||||
protected String parseItem(JSONObject item, JSONObject values) {
|
||||
String field = item.getString("field");
|
||||
if (!rootEntity.containsField(field)) {
|
||||
return null;
|
||||
|
@ -113,17 +114,22 @@ public class AdvFilterParser {
|
|||
String op = convOp(item.getString("op"));
|
||||
|
||||
String value = item.getString("value");
|
||||
// 占位
|
||||
if (value.matches("\\{\\d+\\}")) {
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String valIndex = value.replaceAll("[\\{\\}]", "");
|
||||
Object valHold = qvalues.get(valIndex);
|
||||
if (valHold == null) {
|
||||
Object valReady = values.get(valIndex);
|
||||
if (valReady == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// in
|
||||
if (valHold instanceof JSONArray) {
|
||||
if (valReady instanceof JSONArray) {
|
||||
Set<String> valArray = new HashSet<>();
|
||||
for (Object o : (JSONArray) valHold) {
|
||||
for (Object o : (JSONArray) valReady) {
|
||||
valArray.add(quote(o.toString()));
|
||||
}
|
||||
|
||||
|
@ -134,7 +140,7 @@ public class AdvFilterParser {
|
|||
}
|
||||
|
||||
} else {
|
||||
value = valHold.toString();
|
||||
value = valReady.toString();
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -169,17 +175,22 @@ public class AdvFilterParser {
|
|||
* @return
|
||||
*/
|
||||
protected String convOp(String op) {
|
||||
if ("eq".equals(op)) return "=";
|
||||
if ("neq".equals(op)) return "<>";
|
||||
if ("gt".equals(op)) return ">";
|
||||
if ("lt".equals(op)) return "<";
|
||||
if ("ge".equals(op)) return ">=";
|
||||
if ("le".equals(op)) return "<=";
|
||||
if ("nl".equals(op)) return "is null";
|
||||
if ("nt".equals(op)) return "is not null";
|
||||
if ("lk".equals(op)) return "like";
|
||||
if ("nlk".equals(op)) return "not like";
|
||||
if ("in".equals(op)) return "in";
|
||||
if ("EQ".equalsIgnoreCase(op)) return "=";
|
||||
else if ("NEQ".equalsIgnoreCase(op)) return "<>";
|
||||
else if ("GT".equalsIgnoreCase(op)) return ">";
|
||||
else if ("LT".equalsIgnoreCase(op)) return "<";
|
||||
else if ("GE".equalsIgnoreCase(op)) return ">=";
|
||||
else if ("LE".equalsIgnoreCase(op)) return "<=";
|
||||
else if ("NL".equalsIgnoreCase(op)) return "is null";
|
||||
else if ("NT".equalsIgnoreCase(op)) return "is not null";
|
||||
else if ("LK".equalsIgnoreCase(op)) return "like";
|
||||
else if ("NLK".equalsIgnoreCase(op)) return "not like";
|
||||
else if ("IN".equalsIgnoreCase(op)) return "in";
|
||||
else if ("BW".equalsIgnoreCase(op)) return "between";
|
||||
else if ("BFD".equalsIgnoreCase(op)) return "$before_day(%d)";
|
||||
else if ("BFM".equalsIgnoreCase(op)) return "$before_month(%d)";
|
||||
else if ("AFD".equalsIgnoreCase(op)) return "$after_day(%d)";
|
||||
else if ("AFM".equalsIgnoreCase(op)) return "$after_month(%d)";
|
||||
throw new UnsupportedOperationException("Unsupported token [" + op + "]");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.rebuild.server.entityhub.EasyMeta;
|
||||
import com.rebuild.server.helper.manager.PickListManager;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
import com.rebuild.server.metadata.PortalMetaSorter;
|
||||
import com.rebuild.web.BaseControll;
|
||||
|
@ -80,8 +82,9 @@ public class MetadataGet extends BaseControll {
|
|||
writeSuccess(response, list);
|
||||
}
|
||||
|
||||
// 指定实体所引用的字段实体
|
||||
@RequestMapping("references")
|
||||
public void ref(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
public void references(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String entity = getParameterNotNull(request, "entity");
|
||||
Entity entityMeta = MetadataHelper.getEntity(entity);
|
||||
|
||||
|
@ -100,4 +103,13 @@ public class MetadataGet extends BaseControll {
|
|||
}
|
||||
writeSuccess(response, list);
|
||||
}
|
||||
|
||||
// PickList 值列表
|
||||
@RequestMapping("picklist")
|
||||
public void ref(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String entity = getParameterNotNull(request, "entity");
|
||||
String field = getParameterNotNull(request, "field");
|
||||
JSON list = PickListManager.getPickList(entity, field, false);
|
||||
writeSuccess(response, list);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23614,7 +23614,9 @@ div.dataTables_wrapper div.dataTables_filter label select {
|
|||
|
||||
.datetimepicker table tbody tr td {
|
||||
line-height: 31px;
|
||||
padding: 0 8px
|
||||
padding: 0 8px;
|
||||
line-height: 28px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.datetimepicker table tbody tr td.day {
|
||||
|
|
|
@ -978,8 +978,10 @@ i.split.ui-draggable-dragging {
|
|||
margin-left: -25px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
padding-top: 10px;
|
||||
color: #777;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.adv-filter .item .field i.zmdi {
|
||||
position: absolute;
|
||||
|
@ -989,6 +991,7 @@ i.split.ui-draggable-dragging {
|
|||
color: #999;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
}
|
||||
.adv-filter .item .field i.zmdi:hover{
|
||||
color: #0d5bdd;
|
||||
|
@ -996,6 +999,9 @@ i.split.ui-draggable-dragging {
|
|||
.adv-filter .item:hover .field i.zmdi {
|
||||
display: block;
|
||||
}
|
||||
.adv-filter .item:hover .field em {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.adv-filter .item .op {
|
||||
padding-left: 0;
|
||||
|
@ -1005,25 +1011,54 @@ i.split.ui-draggable-dragging {
|
|||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.adv-filter .select2-container--default .select2-selection--single {
|
||||
.adv-filter .item .val .val-range {
|
||||
position: relative;
|
||||
}
|
||||
.adv-filter .item .val .val-range > span {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
background-color: #eee;
|
||||
color: #999;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.adv-filter .item .val .val-range > span.end {
|
||||
top: 46px;
|
||||
}
|
||||
|
||||
.adv-filter .select2-container--default .select2-selection--single, .adv-filter .select2-container--default .select2-selection--multiple {
|
||||
height: 34px;
|
||||
}
|
||||
.adv-filter .select2-container--default .select2-selection--multiple {
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.adv-filter .select2-container--default .select2-selection--single .select2-selection__rendered,
|
||||
.adv-filter .select2-container--default .select2-selection--multiple .select2-selection__rendered,
|
||||
.adv-filter .form-control-sm {
|
||||
height: 34px !important;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.adv-filter .form-control-sm {
|
||||
height: 34px !important;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.adv-filter .select2-container--default .select2-selection--single .select2-selection__arrow b:after
|
||||
{
|
||||
.adv-filter .select2-container .select2-search--inline .select2-search__field,
|
||||
.adv-filter .select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.adv-filter .select2-container--default .select2-selection--single .select2-selection__arrow b:after {
|
||||
line-height: 34px;
|
||||
}
|
||||
.adv-filter+.adv-filter {
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
class AdvFilter extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { ...props }
|
||||
|
||||
// TODO parse exists items
|
||||
let items = []
|
||||
this.filterItems = {}
|
||||
this.state = { ...props, items: items }
|
||||
|
||||
this.childrenRef = []
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
|
@ -10,11 +16,12 @@ class AdvFilter extends React.Component {
|
|||
<div className="adv-filter">
|
||||
<div className="filter-option">
|
||||
</div>
|
||||
<div className="filter-items">
|
||||
{(this.state.items || []).map((item)=>{
|
||||
<div className="filter-items" ref="items">
|
||||
{this.state.items.map((item)=>{
|
||||
return item
|
||||
//return React.cloneElement(item, { ref: item.id })
|
||||
})}
|
||||
<div className="item plus"><a href="javascript:;" onClick={()=>this.addItem()}><i className="zmdi zmdi-plus-circle icon"></i> 新增条件</a></div>
|
||||
<div className="item plus"><a href="javascript:;" onClick={()=>this.addItem()}><i className="zmdi zmdi-plus-circle icon"></i> 添加条件</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="adv-filter">
|
||||
|
@ -26,11 +33,11 @@ class AdvFilter extends React.Component {
|
|||
</div>
|
||||
{this.state.enableAdvexp !== true ? null :
|
||||
<div className="mb-3">
|
||||
<input className="form-control form-control-sm form-control-success" ref="adv-exp" value={this.state.advexp} />
|
||||
<input className="form-control form-control-sm form-control-success" ref="adv-exp" value={this.state.advexp} onChange={()=>this.handleChange()} />
|
||||
</div>
|
||||
}
|
||||
<div className="item">
|
||||
<button className="btn btn-primary" type="button">应用</button>
|
||||
<button className="btn btn-primary" type="button" onClick={()=>this.toFilterJson()}>应用</button>
|
||||
|
||||
<button className="btn btn-secondary" type="button">取消</button>
|
||||
</div>
|
||||
|
@ -41,48 +48,93 @@ class AdvFilter extends React.Component {
|
|||
componentDidMount() {
|
||||
let that = this
|
||||
$.get(rb.baseUrl + '/commons/metadata/fields?entity=' + this.state.entity, function(res){
|
||||
that.fields = res.data
|
||||
that.fields = res.data.map((item) => {
|
||||
if (item.type == 'DATETIME') item.type = 'DATE'
|
||||
return item
|
||||
})
|
||||
})
|
||||
}
|
||||
onRef = (child) => {
|
||||
console.log('onRef ... ' + child)
|
||||
this.childrenRef.push(child)
|
||||
}
|
||||
handleChange(event) {
|
||||
let v = event.target.value
|
||||
console.log(v)
|
||||
}
|
||||
|
||||
addItem(){
|
||||
if (!this.fields) return
|
||||
let _items = this.state.items || []
|
||||
if (_items.length >= 10){ rb.notice('最多可设置10个条件'); return}
|
||||
if (_items.length >= 10){ rb.notice('最多可添加10个条件'); return }
|
||||
|
||||
let id = 'item-' + $random()
|
||||
_items.push(<FilterItem index={_items.length + 1} fields={this.fields} $$$parent={this} key={id} id={id} onRef={this.onRef} />)
|
||||
|
||||
_items.push(<FilterItem index={_items.length + 1} fields={this.fields} $$$parent={this} key={'item-' + $random()} />)
|
||||
let advexp = []
|
||||
for (let i = 1; i <= _items.length; i++) advexp.push(i)
|
||||
this.setState({ items: _items, advexp: advexp.join(' OR ') })
|
||||
}
|
||||
delItem(del){
|
||||
removeItem(id){
|
||||
let _items = []
|
||||
for (let i = 0; i < this.state.items.length; i++){
|
||||
let item = this.state.items[i]
|
||||
if (item.props.index != del.props.index) _items.push(item)
|
||||
}
|
||||
this.state.items.forEach((item)=>{
|
||||
if (item.props.id != id) _items.push(item)
|
||||
})
|
||||
let _children = []
|
||||
this.childrenRef.forEach((item)=>{
|
||||
if (item.props.id != id) _children.push(item)
|
||||
})
|
||||
this.childrenRef = _children
|
||||
|
||||
let that = this
|
||||
let advexp = []
|
||||
for (let i = 1; i <= _items.length; i++) advexp.push(i)
|
||||
this.setState({ items: _items, advexp: advexp.join(' OR ') })
|
||||
this.setState({ items: _items, advexp: advexp.join(' OR ') }, ()=>{
|
||||
that.childrenRef.forEach((child, idx)=>{
|
||||
child.setIndex(idx + 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
toggleAdvexp() {
|
||||
this.setState({ enableAdvexp: this.state.enableAdvexp !== true })
|
||||
}
|
||||
|
||||
toFilterJson() {
|
||||
let filters = []
|
||||
let hasError = false
|
||||
for (let i = 0; i < this.childrenRef.length; i++){
|
||||
let fj = this.childrenRef[i].getFilterJson()
|
||||
if (!!!fj) hasError = true
|
||||
else filters.push(fj)
|
||||
}
|
||||
if (hasError){ rb.notice('部分条件设置有误,请检查'); return }
|
||||
|
||||
let adv = { items: filters }
|
||||
if (this.state.enableAdvexp == true) adv.equation = this.state.advexp
|
||||
console.log(JSON.stringify(adv))
|
||||
}
|
||||
}
|
||||
|
||||
const OP_TYPE = { LK:'包含', NLK:'不包含', EQ:'等于', NEQ:'不等于', GT:'大于', LT:'小于', BW:'区间', NL:'为空', NT:'不为空', BFD:'...天前', BFM:'...月前', AFD:'...天后', AFM:'...月后' }
|
||||
const OP_DATE_NOPICKER = ['BFD','BFM','AFD','AFM']
|
||||
const PICKLIST_CACHE = {}
|
||||
|
||||
class FilterItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { ...props }
|
||||
console.log(props)
|
||||
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="row item" key={'item-' + this.state.index}>
|
||||
<div className="row item">
|
||||
<div className="col-sm-5 field">
|
||||
<em>{this.state.index}</em>
|
||||
<i className="zmdi zmdi-minus-circle" title="移除条件" onClick={()=>this.props.$$$parent.delItem(this)}></i>
|
||||
<select className="form-control form-control-sm" ref="filter-field">
|
||||
<em className={this.state.hasError ? 'text-danger' : ''}>{this.state.index}</em>
|
||||
<i className="zmdi zmdi-minus-circle" title="移除条件" onClick={()=>this.props.$$$parent.removeItem(this.props.id)}></i>
|
||||
<select className="form-control form-control-sm" ref="filter-field" value={this.state.field}>
|
||||
{this.state.fields.map((item)=>{
|
||||
return <option value={item.name + '----' + item.type} key={'field-' + item.name}>{item.label}</option>
|
||||
})}
|
||||
|
@ -91,39 +143,58 @@ class FilterItem extends React.Component {
|
|||
<div className="col-sm-2 op">
|
||||
{this.renderOp()}
|
||||
</div>
|
||||
<div className="col-sm-5 val">
|
||||
<div className={'col-sm-5 val' + (this.state.op == 'NL' || this.state.op == 'NT' ? ' hide' : '')}>
|
||||
{this.renderVal()}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
renderOp(){
|
||||
let op = [ ['lk','包含'], ['nlk','不包含'], ['eq','等于'], ['neq','不等于'], ['nl','为空'], ['nt','不为空'] ]
|
||||
let op = [ 'LK', 'NLK', 'EQ', 'NEQ' ]
|
||||
if (this.state.type == 'NUMBER' || this.state.type == 'DECIMAL'){
|
||||
op = [ ['gt','大于'], ['lt','小于'], ['bw','区间'], ['eq','等于'] ]
|
||||
op = [ 'GT', 'LT', 'BW', 'EQ' ]
|
||||
} else if (this.state.type == 'DATE' || this.state.type == 'DATETIME'){
|
||||
op = [ ['gt','大于'], ['lt','小于'], ['bw','区间'], ['bfd','...天前'], ['bfm','...月前'], ['afd','...天后'], ['afm','...月后'] ]
|
||||
op = [ 'GT', 'LT', 'BW', 'BFD', 'BFM', 'AFD', 'AFM' ]
|
||||
} else if (this.state.type == 'FILE' || this.state.type == 'IMAGE'){
|
||||
op = [ ['nl','为空'], ['nt','不为空'] ]
|
||||
op = []
|
||||
} else if (this.state.type == 'PICKLIST'){
|
||||
op = [ 'LK', 'NLK' ]
|
||||
}
|
||||
op.push('NL', 'NT')
|
||||
this.__op = op
|
||||
|
||||
return (
|
||||
<select className="form-control form-control-sm" ref="filter-op">
|
||||
<select className="form-control form-control-sm" ref="filter-op" value={this.state.op}>
|
||||
{op.map((item)=>{
|
||||
return <option value={item[0]} key={'op-' + item.join('-')}>{item[1]}</option>
|
||||
return <option value={item} key={'op-' + item}>{OP_TYPE[item]}</option>
|
||||
})}
|
||||
</select>
|
||||
)
|
||||
}
|
||||
renderVal(){
|
||||
return this.state.op != 'bw' ? (this.state.op == 'nl' || this.state.op == 'nt' ? null : <input className="form-control form-control-sm" ref="filter-val" />) : (<div>
|
||||
<input className="form-control form-control-sm" ref="filter-val" />
|
||||
<input className="form-control form-control-sm" ref="filter-val-2" />
|
||||
let val = <input className="form-control form-control-sm" ref="filter-val" onChange={this.handleChange} value={this.state.value || ''} />
|
||||
if (this.state.op == 'BW'){
|
||||
val = (
|
||||
<div className="val-range">
|
||||
<input className="form-control form-control-sm" ref="filter-val" onChange={this.handleChange} value={this.state.value || ''} />
|
||||
<input className="form-control form-control-sm" ref="filter-val2" onChange={this.handleChange} data-at="2" value={this.state.value2 || ''} />
|
||||
<span>起</span>
|
||||
<span className="end">止</span>
|
||||
</div>)
|
||||
} else if (this.state.type == 'PICKLIST'){
|
||||
val = (
|
||||
<select className="form-control form-control-sm" multiple="true" ref="filter-val">
|
||||
{(this.state.picklist || []).map((item) => {
|
||||
return <option value={item.id} key={'val-' + item.id}>{item.text}</option>
|
||||
})}
|
||||
</select>)
|
||||
}
|
||||
return (val)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.onRef(this)
|
||||
|
||||
let that = this
|
||||
let s2field = $(this.refs['filter-field']).select2({
|
||||
language: 'zh-CN',
|
||||
|
@ -132,7 +203,7 @@ class FilterItem extends React.Component {
|
|||
}).on('change.select2', function(e){
|
||||
let ft = e.target.value.split('----')
|
||||
that.setState({ field: ft[0], type: ft[1] }, function(){
|
||||
s2op.val(that.__op[0][0]).trigger('change')
|
||||
s2op.val(that.__op[0]).trigger('change')
|
||||
})
|
||||
})
|
||||
let s2op = $(this.refs['filter-op']).select2({
|
||||
|
@ -141,9 +212,165 @@ class FilterItem extends React.Component {
|
|||
width: '100%',
|
||||
}).on('change.select2', function(e){
|
||||
that.setState({ op: e.target.value }, function(){
|
||||
$(that.refs['filter-val']).focus()
|
||||
$setTimeout(function(){
|
||||
//ReactDOM.findDOMNode(that.refs['filter-val']).focus()
|
||||
}, 200, 'filter-val-focus')
|
||||
})
|
||||
})
|
||||
this.__select2 = [s2field, s2op]
|
||||
s2field.trigger('change')
|
||||
}
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
let thisEnter = this.state.field + '----' + this.state.type + '----' + (this.state.op == 'BW')/*区间*/ + '----' + (OP_DATE_NOPICKER.contains(this.state.op))
|
||||
if (this.__lastEnter == thisEnter) return
|
||||
console.log(thisEnter)
|
||||
let lastType = this.__lastEnter ? this.__lastEnter.split('----')[1] : null
|
||||
this.__lastEnter = thisEnter
|
||||
|
||||
if (this.state.type == 'PICKLIST') {
|
||||
this.renderPickList(this.state.field)
|
||||
} else if (lastType == 'PICKLIST') {
|
||||
this.removePickList()
|
||||
}
|
||||
|
||||
if (this.state.type == 'DATE') {
|
||||
this.removeDatepicker()
|
||||
if (OP_DATE_NOPICKER.contains(this.state.op)){
|
||||
// 无需日期组件
|
||||
} else {
|
||||
this.renderDatepicker()
|
||||
}
|
||||
} else if (lastType == 'DATE'){
|
||||
this.removeDatepicker()
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.__select2.forEach((item, index) => {
|
||||
item.select2('destroy')
|
||||
})
|
||||
this.__select2 = null
|
||||
this.removePickList()
|
||||
this.removeDatepicker()
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
let that = this
|
||||
let val = event.target.value
|
||||
if (event.target.dataset.at == 2) {
|
||||
this.setState({ value2: val }, function(){
|
||||
})
|
||||
} else {
|
||||
this.setState({ value: val }, function(){
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
renderPickList(field) {
|
||||
let that = this
|
||||
if (PICKLIST_CACHE[field]) {
|
||||
this.setState({ picklist: PICKLIST_CACHE[field] }, function(){
|
||||
that.renderPickListAfter()
|
||||
})
|
||||
} else {
|
||||
$.get(rb.baseUrl + '/commons/metadata/picklist?entity=' + this.props.$$$parent.props.entity + '&field=' + field, function(res){
|
||||
if (res.error_code == 0){
|
||||
PICKLIST_CACHE[field] = res.data
|
||||
that.setState({ picklist: PICKLIST_CACHE[field] }, function(){
|
||||
that.renderPickListAfter()
|
||||
})
|
||||
} else{
|
||||
rb.notice(res.error_msg, 'danger')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
renderPickListAfter(){
|
||||
console.log('render PickList ...')
|
||||
let that = this
|
||||
let s2val = $(this.refs['filter-val']).select2({
|
||||
language: 'zh-CN',
|
||||
placeholder: '选择值',
|
||||
width: '100%',
|
||||
}).on('change.select2', function(e){
|
||||
let val = s2val.val()
|
||||
that.setState({ value: val.join(',') }, function(){
|
||||
})
|
||||
})
|
||||
this.__select2_PickList = s2val
|
||||
}
|
||||
removePickList(){
|
||||
if (this.__select2_PickList) {
|
||||
console.log('remove PickList ...')
|
||||
this.__select2_PickList.select2('destroy')
|
||||
this.__select2_PickList = null
|
||||
}
|
||||
}
|
||||
|
||||
renderDatepicker(){
|
||||
console.log('render Datepicker ...')
|
||||
let cfg = {
|
||||
componentIcon:'zmdi zmdi-calendar',
|
||||
navIcons: { rightIcon:'zmdi zmdi-chevron-right', leftIcon:'zmdi zmdi-chevron-left'},
|
||||
format: 'yyyy-mm-dd',
|
||||
minView: 2,
|
||||
startView: 'month',
|
||||
weekStart: 1,
|
||||
autoclose: true,
|
||||
language: 'zh',
|
||||
todayHighlight: true,
|
||||
showMeridian: false,
|
||||
keyboardNavigation: false,
|
||||
}
|
||||
|
||||
let that = this
|
||||
let dp1 = $(this.refs['filter-val']).datetimepicker(cfg)
|
||||
dp1.on('change.select2', function(e){
|
||||
that.setState({ value: e.target.value }, function(){
|
||||
})
|
||||
})
|
||||
this.__datepicker = [dp1]
|
||||
|
||||
if (this.refs['filter-val2']) {
|
||||
let dp2 = $(this.refs['filter-val2']).datetimepicker(cfg)
|
||||
dp2.on('change.select2', function(e){
|
||||
that.setState({ value2: e.target.value }, function(){
|
||||
})
|
||||
})
|
||||
this.__datepicker.push(dp2)
|
||||
}
|
||||
}
|
||||
removeDatepicker(){
|
||||
if (this.__datepicker) {
|
||||
console.log('remove Datepicker ...')
|
||||
this.__datepicker.forEach((item) => {
|
||||
item.datetimepicker('remove')
|
||||
})
|
||||
this.__datepicker = null
|
||||
}
|
||||
}
|
||||
|
||||
setIndex(idx) {
|
||||
this.setState({ index: idx })
|
||||
}
|
||||
getFilterJson(){
|
||||
let s = this.state
|
||||
if (!!!s.value) {
|
||||
if (s.op == 'NL' || s.op == 'NT'){
|
||||
// 允许无值
|
||||
} else {
|
||||
this.setState({ hasError: true })
|
||||
return
|
||||
}
|
||||
}
|
||||
if (s.op == 'BW' && !!!s.value2){
|
||||
this.setState({ hasError: true })
|
||||
return
|
||||
}
|
||||
|
||||
let item = { index: s.index, field: s.field, op: s.op, value: s.value }
|
||||
if (s.value2) item.value2 = s.value2
|
||||
this.setState({ hasError: false })
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -403,6 +403,7 @@ class RbFormDateTime extends RbFormElement {
|
|||
todayHighlight: true,
|
||||
showMeridian: false,
|
||||
keyboardNavigation: false,
|
||||
minuteStep: 5,
|
||||
}).on('changeDate', function(){
|
||||
let val = $(this).val()
|
||||
that.handleChange({ target: { value: val } }, true)
|
||||
|
|
|
@ -80,7 +80,7 @@ const __initNavs = function(){
|
|||
})
|
||||
$(document.body).click(function(){
|
||||
// MinNav && SubnavOpen
|
||||
if ($('.rb-collapsible-sidebar').hasClass('rb-collapsible-sidebar-collapsed') && currsntSubnav.hasClass('open')) {
|
||||
if ($('.rb-collapsible-sidebar').hasClass('rb-collapsible-sidebar-collapsed') && currsntSubnav && currsntSubnav.hasClass('open')) {
|
||||
currsntSubnav.removeClass('open')
|
||||
currsntSubnav.find('.sub-menu').removeClass('visible')
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ const __checkMessage = function(){
|
|||
$('.rb-notifications span.badge').text('0')
|
||||
__checkMessage_status = 0
|
||||
}
|
||||
setTimeout(__checkMessage, 3000);
|
||||
// setTimeout(__checkMessage, 3000);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue