advfilter

This commit is contained in:
FangfangZhao 2018-11-08 17:54:06 +08:00
parent 2ee947d9fc
commit 8598ed0175
6 changed files with 160 additions and 77 deletions

View file

@ -186,6 +186,7 @@ public class AdvFilterParser {
else if ("LK".equalsIgnoreCase(op)) return "like";
else if ("NLK".equalsIgnoreCase(op)) return "not like";
else if ("IN".equalsIgnoreCase(op)) return "in";
else if ("NIN".equalsIgnoreCase(op)) return "not 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)";

View file

@ -33,6 +33,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.alibaba.fastjson.JSON;
import com.rebuild.server.entityhub.DisplayType;
import com.rebuild.server.entityhub.EasyMeta;
import com.rebuild.server.helper.manager.PickListManager;
import com.rebuild.server.metadata.MetadataHelper;
@ -70,13 +71,18 @@ public class MetadataGet extends BaseControll {
String entity = getParameterNotNull(request, "entity");
Entity entityBase = MetadataHelper.getEntity(entity);
List<Map<String, String>> list = new ArrayList<>();
for (Field e : PortalMetaSorter.sortFields(entityBase)) {
Map<String, String> map = new HashMap<>();
map.put("name", e.getName());
EasyMeta easyMeta = new EasyMeta(e);
List<Map<String, Object>> list = new ArrayList<>();
for (Field field : PortalMetaSorter.sortFields(entityBase)) {
Map<String, Object> map = new HashMap<>();
map.put("name", field.getName());
EasyMeta easyMeta = new EasyMeta(field);
map.put("label", easyMeta.getLabel());
map.put("type", easyMeta.getDisplayType(false));
DisplayType dt = easyMeta.getDisplayType();
map.put("type", dt.name());
if (dt == DisplayType.REFERENCE) {
Entity ref = field.getReferenceEntities()[0];
map.put("ref", new String[] { ref.getName(), EasyMeta.getDisplayType(ref.getNameField()).name() });
}
list.add(map);
}
writeSuccess(response, list);

View file

@ -18128,10 +18128,11 @@ form.dropzone .dz-preview .dz-error-message {
}
.select2-container--default .select2-selection--single, .select2-container--default .select2-selection--multiple {
height: 37px
min-height: 37px;
font-size: 0;
}
.select2-container--default .select2-selection--single .select2-selection__rendered, .select2-container--default .select2-selection--multiple .select2-selection__rendered {
padding: 0 10px;
height: 37px;
line-height: 37px;
font-size: 1rem;
color: #404040

View file

@ -156,6 +156,13 @@ body.view-body {
.select2.select2-container {
width: 100%;
}
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
line-height: 30px;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
margin-top: 4px;
margin-right: 4px;
}
textarea.row2x {
height: 52px !important;
resize: none;
@ -836,31 +843,31 @@ i.split.ui-draggable-dragging {
.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;
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 .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 {
border-top: 1px solid #eee;
padding-top: 8px;
margin-top: 8px;
}
}
.adv-filter .form-control-sm,.adv-filter .select2-container--default .select2-selection--single .select2-selection__rendered, .adv-filter .select2-container--default .select2-selection--multiple .select2-selection__rendered {
padding-left: 8px;
padding-right: 8px;
}
/* height = 34px
.adv-filter .select2-container--default .select2-selection--single, .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 {
line-height: 34px;
padding: 0 8px;
}
.adv-filter .select2-container--default .select2-selection--single .select2-selection__arrow {
height: 34px;
top: -1px;
}
.adv-filter .form-control-sm {
height: 34px !important;
padding: 3px 8px;
}
*/

View file

@ -5,9 +5,7 @@ class AdvFilter extends React.Component {
// TODO parse exists items
let items = []
this.filterItems = {}
this.state = { ...props, items: items }
this.childrenRef = []
}
render() {
@ -19,7 +17,6 @@ class AdvFilter extends React.Component {
<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>
@ -47,15 +44,18 @@ class AdvFilter extends React.Component {
}
componentDidMount() {
let that = this
$.get(rb.baseUrl + '/commons/metadata/fields?entity=' + this.state.entity, function(res){
$.get(rb.baseUrl + '/commons/metadata/fields?entity=' + this.props.entity, function(res){
that.fields = res.data.map((item) => {
if (item.type == 'DATETIME') item.type = 'DATE'
if (item.type == 'DATETIME') {
item.type = 'DATE'
} else if (item.type == 'REFERENCE') {
REFFIELD_CACHE[that.props.entity + '.' + item.name] = item.ref
}
return item
})
})
}
onRef = (child) => {
console.log('onRef ... ' + child)
this.childrenRef.push(child)
}
handleChange(event) {
@ -110,29 +110,32 @@ class AdvFilter extends React.Component {
}
if (hasError){ rb.notice('部分条件设置有误,请检查'); return }
let adv = { items: filters }
let adv = { entity: this.props.entity, 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_TYPE = { LK:'包含', NLK:'不包含', IN:'包含', NIN:'不包含', EQ:'等于', NEQ:'不等于', GT:'大于', LT:'小于', BW:'区间', NL:'为空', NT:'不为空', BFD:'...天前', BFM:'...月前', AFD:'...天后', AFM:'...月后' }
const OP_DATE_NOPICKER = ['BFD','BFM','AFD','AFM']
const PICKLIST_CACHE = {}
const REFFIELD_CACHE = {}
class FilterItem extends React.Component {
constructor(props) {
super(props)
this.state = { ...props }
console.log(props)
this.__entity = this.props.$$$parent.props.entity
this.handleChange = this.handleChange.bind(this)
this.valueHandle = this.valueHandle.bind(this)
this.valueCheck = this.valueCheck.bind(this)
}
render() {
return (
<div className="row item">
<div className="col-sm-5 field">
<em className={this.state.hasError ? 'text-danger' : ''}>{this.state.index}</em>
<em>{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)=>{
@ -157,9 +160,11 @@ class FilterItem extends React.Component {
op = [ 'GT', 'LT', 'BW', 'BFD', 'BFM', 'AFD', 'AFM' ]
} else if (this.state.type == 'FILE' || this.state.type == 'IMAGE'){
op = []
} else if (this.state.type == 'PICKLIST'){
op = [ 'LK', 'NLK' ]
} else if (this.state.type == 'PICKLIST' || this.isBizzField()){
op = [ 'IN', 'NIN' ]
}
// TODO
op.push('NL', 'NT')
this.__op = op
@ -172,12 +177,12 @@ class FilterItem extends React.Component {
)
}
renderVal(){
let val = <input className="form-control form-control-sm" ref="filter-val" onChange={this.handleChange} value={this.state.value || ''} />
let val = <input className="form-control form-control-sm" ref="filter-val" onChange={this.valueHandle} onBlur={this.valueCheck} 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 || ''} />
<input className="form-control form-control-sm" ref="filter-val" onChange={this.valueHandle} onBlur={this.valueCheck} value={this.state.value || ''} />
<input className="form-control form-control-sm" ref="filter-val2" onChange={this.valueHandle} onBlur={this.valueCheck} data-at="2" value={this.state.value2 || ''} />
<span></span>
<span className="end"></span>
</div>)
@ -188,17 +193,36 @@ class FilterItem extends React.Component {
return <option value={item.id} key={'val-' + item.id}>{item.text}</option>
})}
</select>)
} else if (this.isBizzField()){
val = <select className="form-control form-control-sm" multiple="true" ref="filter-val" />
}
return (val)
}
// User/Department
isBizzField() {
if (this.state.type == 'REFERENCE'){
const fRef = REFFIELD_CACHE[this.__entity + '.' + this.state.field]
return fRef && (fRef[0] == 'User' || fRef[0] == 'Department')
}
return false
}
//
isNumberValue(){
if (this.state.type == 'NUMBER' || this.state.type == 'DECIMAL'){
return true
} else if (this.state.type == 'DATE' && OP_DATE_NOPICKER.contains(this.state.op)){
return true
}
return false
}
componentDidMount() {
this.props.onRef(this)
let that = this
let s2field = $(this.refs['filter-field']).select2({
language: 'zh-CN',
placeholder: '选择字段',
width: '100%',
}).on('change.select2', function(e){
let ft = e.target.value.split('----')
@ -208,7 +232,6 @@ class FilterItem extends React.Component {
})
let s2op = $(this.refs['filter-op']).select2({
language: 'zh-CN',
placeholder: '选择操作',
width: '100%',
}).on('change.select2', function(e){
that.setState({ op: e.target.value }, function(){
@ -243,39 +266,54 @@ class FilterItem extends React.Component {
} else if (lastType == 'DATE'){
this.removeDatepicker()
}
if (this.isBizzField()){
const fRef = REFFIELD_CACHE[this.__entity + '.' + this.state.field]
this.renderBizzSearch(fRef[0])
} else if (lastType == 'REFERENCE') {
this.removeBizzSearch()
}
}
componentWillUnmount() {
this.__select2.forEach((item, index) => {
item.select2('destroy')
})
this.__select2.forEach((item, index) => { item.select2('destroy') })
this.__select2 = null
this.removePickList()
this.removeDatepicker()
this.removeBizzSearch()
}
handleChange(event) {
valueHandle(event) {
let that = this
let val = event.target.value
if (event.target.dataset.at == 2) {
this.setState({ value2: val }, function(){
})
if (event.target.dataset.at == 2) this.setState({ value2: val })
else this.setState({ value: val })
}
valueCheck(event){
let el = $(event.target)
let val = event.target.value
if (!!!val){
el.addClass('is-invalid')
} else {
this.setState({ value: val }, function(){
})
if (this.isNumberValue() && $regex.isDecimal(val) == false){
el.addClass('is-invalid')
} else {
el.removeClass('is-invalid')
}
}
}
renderPickList(field) {
let that = this
if (PICKLIST_CACHE[field]) {
this.setState({ picklist: PICKLIST_CACHE[field] }, function(){
const plKey = this.props.$$$parent.props.entity + '.' + field
if (PICKLIST_CACHE[plKey]) {
this.setState({ picklist: PICKLIST_CACHE[plKey] }, 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(){
PICKLIST_CACHE[plKey] = res.data
that.setState({ picklist: PICKLIST_CACHE[plKey] }, function(){
that.renderPickListAfter()
})
} else{
@ -289,7 +327,6 @@ class FilterItem extends React.Component {
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()
@ -349,6 +386,43 @@ class FilterItem extends React.Component {
}
}
renderBizzSearch(entity){
console.log('render BizzSearch ...')
let that = this
let s2val = $(this.refs['filter-val']).select2({
language: 'zh-CN',
width: '100%',
minimumInputLength: 1,
ajax: {
url: rb.baseUrl + '/commons/search',
delay: 300,
data: function(params) {
let query = {
entity: entity,
fields: entity == 'User' ? 'loginName,fullName,email' : 'name',
q: params.term,
}
return query
},
processResults: function(data){
let rs = data.data.map((item) => { return item })
return { results: rs }
}
}
}).on('change.select2', function(e){
let val = s2val.val()
that.setState({ value: val.join(',') })
})
this.__select2_BizzSearch = s2val
}
removeBizzSearch(){
if (this.__select2_BizzSearch){
console.log('remove BizzSearch ...')
this.__select2_BizzSearch.select2('destroy')
this.__select2_BizzSearch = null
}
}
setIndex(idx) {
this.setState({ index: idx })
}
@ -358,16 +432,22 @@ class FilterItem extends React.Component {
if (s.op == 'NL' || s.op == 'NT'){
//
} else {
this.setState({ hasError: true })
return
}
} else if (s.op == 'NL' || s.op == 'NT'){
s.value = null
}
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.value && ($(this.refs['filter-val']).hasClass('is-invalid') || $(this.refs['filter-val2']).hasClass('is-invalid'))) {
return
}
let item = { index: s.index, field: s.field, op: s.op }
if (s.value) item.value = s.value
if (s.value2) item.value2 = s.value2
this.setState({ hasError: false })
return item

View file

@ -1,12 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>