mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-11-10 17:04:33 +08:00
feat: search ref in dialog
This commit is contained in:
parent
b83ba5fb35
commit
24dc951cff
18 changed files with 429 additions and 142 deletions
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and 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.
|
||||
*/
|
||||
|
||||
package com.rebuild.server.helper.datalist;
|
||||
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.server.configuration.ConfigEntry;
|
||||
import com.rebuild.server.configuration.portals.ChartManager;
|
||||
import com.rebuild.server.metadata.EntityHelper;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
import com.rebuild.server.metadata.entity.EasyMeta;
|
||||
import com.rebuild.server.service.query.AdvFilterParser;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
|
||||
/**
|
||||
* 解析已知的个性化过滤条件
|
||||
*
|
||||
* @author devezhao
|
||||
* @since 2020/6/13
|
||||
*/
|
||||
public class ProtocolFilter {
|
||||
|
||||
final private String protocol;
|
||||
|
||||
/**
|
||||
* @param protocol via:xxx ref:xxx
|
||||
*/
|
||||
public ProtocolFilter(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String toSqlWhere() {
|
||||
String[] ps = protocol.split(":");
|
||||
switch (ps[0]) {
|
||||
case "via" : {
|
||||
return parseVia(ps[1]);
|
||||
}
|
||||
case "ref" : {
|
||||
return parseRef(ps[1]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public String parseVia(String content) {
|
||||
final ID anyId = ID.isId(content) ? ID.valueOf(content) : null;
|
||||
if (anyId == null) return null;
|
||||
|
||||
// via Charts
|
||||
if (anyId.getEntityCode() == EntityHelper.ChartConfig) {
|
||||
ConfigEntry chart = ChartManager.instance.getChart(anyId);
|
||||
JSONObject filterExp = ((JSONObject) chart.getJSON("config")).getJSONObject("filter");
|
||||
return new AdvFilterParser(filterExp).toSqlWhere();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public String parseRef(String content) {
|
||||
String[] fieldAndEntity = content.split("\\.");
|
||||
if (fieldAndEntity.length != 2 || !MetadataHelper.checkAndWarnField(fieldAndEntity[1], fieldAndEntity[0])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Field field = MetadataHelper.getField(fieldAndEntity[1], fieldAndEntity[0]);
|
||||
String referenceDataFilter = EasyMeta.valueOf(field).getExtraAttr("referenceDataFilter");
|
||||
|
||||
if (JSONUtils.wellFormat(referenceDataFilter)) {
|
||||
JSONObject advFilter = JSON.parseObject(referenceDataFilter);
|
||||
if (advFilter.get("items") != null && !advFilter.getJSONArray("items").isEmpty()) {
|
||||
return new AdvFilterParser(advFilter).toSqlWhere();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.server.configuration.ConfigEntry;
|
||||
import com.rebuild.server.configuration.portals.AdvFilterManager;
|
||||
import com.rebuild.server.configuration.portals.ChartManager;
|
||||
import com.rebuild.server.metadata.EntityHelper;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
import com.rebuild.server.service.query.AdvFilterParser;
|
||||
|
@ -172,33 +171,38 @@ public class QueryParser {
|
|||
|
||||
// 过滤器
|
||||
|
||||
final StringBuilder sqlWhere = new StringBuilder("(1=1)");
|
||||
List<String> wheres = new ArrayList<>();
|
||||
|
||||
// Default
|
||||
String defaultFilter = dataListControl == null ? null : dataListControl.getDefaultFilter();
|
||||
if (StringUtils.isNotBlank(defaultFilter)) {
|
||||
sqlWhere.append(" and (").append(defaultFilter).append(')');
|
||||
wheres.add(defaultFilter);
|
||||
}
|
||||
|
||||
// appends ProtocolFilter
|
||||
String protocolFilter = queryExpr.getString("protocolFilter");
|
||||
if (StringUtils.isNotBlank(protocolFilter)) {
|
||||
String where = new ProtocolFilter(protocolFilter).toSqlWhere();
|
||||
if (StringUtils.isNotBlank(where)) wheres.add(where);
|
||||
}
|
||||
|
||||
// appends AdvFilter
|
||||
String advFilter = queryExpr.getString("advFilter");
|
||||
if (ID.isId(advFilter)) {
|
||||
String where = parseAdvFilter(ID.valueOf(advFilter));
|
||||
if (StringUtils.isNotBlank(where)) {
|
||||
sqlWhere.append(" and ").append(where);
|
||||
}
|
||||
if (StringUtils.isNotBlank(where)) wheres.add(where);
|
||||
}
|
||||
|
||||
// appends Quick
|
||||
JSONObject quickFilter = queryExpr.getJSONObject("filter");
|
||||
if (quickFilter != null) {
|
||||
String where = new AdvFilterParser(entity, quickFilter).toSqlWhere();
|
||||
if (StringUtils.isNotBlank(where)) {
|
||||
sqlWhere.append(" and ").append(where);
|
||||
}
|
||||
if (StringUtils.isNotBlank(where)) wheres.add(where);
|
||||
}
|
||||
|
||||
final String sqlWhere = wheres.isEmpty() ? "1=1" : StringUtils.join(wheres.iterator(), " and ");
|
||||
fullSql.append(" where ").append(sqlWhere);
|
||||
|
||||
|
||||
// 排序
|
||||
|
||||
StringBuilder sqlSort = new StringBuilder(" order by ");
|
||||
|
@ -246,20 +250,11 @@ public class QueryParser {
|
|||
* @return
|
||||
*/
|
||||
private String parseAdvFilter(ID filterId) {
|
||||
// via Charts
|
||||
if (filterId.getEntityCode() == EntityHelper.ChartConfig) {
|
||||
ConfigEntry chart = ChartManager.instance.getChart(filterId);
|
||||
JSONObject filterExp = ((JSONObject) chart.getJSON("config")).getJSONObject("filter");
|
||||
return new AdvFilterParser(entity, filterExp).toSqlWhere();
|
||||
}
|
||||
|
||||
// AdvFilter
|
||||
ConfigEntry advFilter = AdvFilterManager.instance.getAdvFilter(filterId);
|
||||
if (advFilter != null) {
|
||||
JSONObject filterExp = (JSONObject) advFilter.getJSON("filter");
|
||||
return new AdvFilterParser(entity, filterExp).toSqlWhere();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ViewAddonsControll extends BaseControll implements PortalsConfigura
|
|||
JSON config = ServletUtils.getRequestJson(request);
|
||||
|
||||
ID configId = ViewAddonsManager.instance.detectUseConfig(user, entity, applyType);
|
||||
Record record = null;
|
||||
Record record;
|
||||
if (configId == null) {
|
||||
record = EntityHelper.forNew(EntityHelper.LayoutConfig, user);
|
||||
record.setString("belongEntity", entity);
|
||||
|
|
|
@ -12,9 +12,10 @@ import cn.devezhao.persist4j.Field;
|
|||
import cn.devezhao.persist4j.dialect.FieldType;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.server.Application;
|
||||
import com.rebuild.server.configuration.portals.ClassificationManager;
|
||||
import com.rebuild.server.configuration.portals.DataListManager;
|
||||
import com.rebuild.server.helper.datalist.ProtocolFilter;
|
||||
import com.rebuild.server.helper.fieldvalue.FieldValueWrapper;
|
||||
import com.rebuild.server.metadata.EntityHelper;
|
||||
import com.rebuild.server.metadata.MetadataHelper;
|
||||
|
@ -23,17 +24,18 @@ import com.rebuild.server.metadata.entity.DisplayType;
|
|||
import com.rebuild.server.metadata.entity.EasyMeta;
|
||||
import com.rebuild.server.service.bizz.UserHelper;
|
||||
import com.rebuild.server.service.bizz.UserService;
|
||||
import com.rebuild.server.service.query.AdvFilterParser;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import com.rebuild.web.BaseControll;
|
||||
import com.rebuild.web.BaseEntityControll;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -51,7 +53,7 @@ import java.util.Set;
|
|||
*/
|
||||
@Controller
|
||||
@RequestMapping("/commons/search/")
|
||||
public class ReferenceSearch extends BaseControll {
|
||||
public class ReferenceSearch extends BaseEntityControll {
|
||||
|
||||
// 快速搜索引用字段
|
||||
@RequestMapping({ "reference", "quick" })
|
||||
|
@ -77,20 +79,13 @@ public class ReferenceSearch extends BaseControll {
|
|||
|
||||
// 引用字段数据过滤仅在搜索时有效
|
||||
// 启用数据过滤后最近搜索将不可用
|
||||
JSONObject advFilter = null;
|
||||
String referenceDataFilter = EasyMeta.valueOf(referenceField).getExtraAttr("referenceDataFilter");
|
||||
if (JSONUtils.wellFormat(referenceDataFilter)) {
|
||||
advFilter = JSON.parseObject(referenceDataFilter);
|
||||
if (advFilter.get("items") == null || advFilter.getJSONArray("items").isEmpty()) {
|
||||
advFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
final String protocolFilter = new ProtocolFilter(null).parseRef(field + "." + entity);
|
||||
|
||||
String q = getParameter(request, "q");
|
||||
// 为空则加载最近使用的
|
||||
if (StringUtils.isBlank(q)) {
|
||||
ID[] recently = null;
|
||||
if (advFilter == null) {
|
||||
if (protocolFilter == null) {
|
||||
String type = getParameter(request, "type");
|
||||
recently = Application.getRecentlyUsedCache().gets(user, referenceEntity.getName(), type);
|
||||
}
|
||||
|
@ -127,11 +122,8 @@ public class ReferenceSearch extends BaseControll {
|
|||
|
||||
String like = " like '%" + q + "%'";
|
||||
String searchWhere = StringUtils.join(searchFields.iterator(), like + " or ") + like;
|
||||
if (advFilter != null) {
|
||||
String advFilterSql = new AdvFilterParser(advFilter).toSqlWhere();
|
||||
if (advFilterSql != null) {
|
||||
searchWhere = "(" + searchWhere + ") and " + advFilterSql;
|
||||
}
|
||||
if (protocolFilter != null) {
|
||||
searchWhere = "(" + searchWhere + ") and (" + protocolFilter + ')';
|
||||
}
|
||||
|
||||
String sql = MessageFormat.format("select {0},{1} from {2} where ( {3} )",
|
||||
|
@ -299,4 +291,35 @@ public class ReferenceSearch extends BaseControll {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.rebuild.web.base.general.GeneralDataListControll#pageList(String, HttpServletRequest, HttpServletResponse)
|
||||
*/
|
||||
@RequestMapping("reference-search-list")
|
||||
public ModelAndView pageListSearch(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String[] fieldAndEntity = getParameterNotNull(request,"field").split("\\.");
|
||||
if (!MetadataHelper.checkAndWarnField(fieldAndEntity[1], fieldAndEntity[0])) {
|
||||
response.sendError(404);
|
||||
return null;
|
||||
}
|
||||
|
||||
Entity entity = MetadataHelper.getEntity(fieldAndEntity[1]);
|
||||
Field field = entity.getField(fieldAndEntity[0]);
|
||||
Entity searchEntity = field.getReferenceEntity();
|
||||
|
||||
ModelAndView mv = createModelAndView("/general-entity/reference-search.jsp");
|
||||
putEntityMeta(mv, searchEntity);
|
||||
|
||||
JSON config = DataListManager.instance.getFieldsLayout(searchEntity.getName(), getRequestUser(request));
|
||||
mv.getModel().put("DataListConfig", JSON.toJSONString(config));
|
||||
|
||||
// 是否启用了字段过滤
|
||||
String referenceDataFilter = EasyMeta.valueOf(field).getExtraAttr("referenceDataFilter");
|
||||
if (referenceDataFilter != null && referenceDataFilter.length() > 10) {
|
||||
mv.getModel().put("referenceFilter", "ref:" + getParameter(request, "field"));
|
||||
} else {
|
||||
mv.getModel().put("referenceFilter", StringUtils.EMPTY);
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class GeneralDataListControll extends BaseEntityControll {
|
|||
response.sendError(404);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
final Entity thatEntity = MetadataHelper.getEntity(entity);
|
||||
|
||||
if (!thatEntity.isQueryable()) {
|
||||
|
@ -62,7 +62,7 @@ public class GeneralDataListControll extends BaseEntityControll {
|
|||
response.sendError(403, "你没有访问此实体的权限");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
ModelAndView mv;
|
||||
if (thatEntity.getMasterEntity() != null) {
|
||||
mv = createModelAndView("/general-entity/slave-list.jsp", entity, user);
|
||||
|
@ -70,7 +70,7 @@ public class GeneralDataListControll extends BaseEntityControll {
|
|||
mv = createModelAndView("/general-entity/record-list.jsp", entity, user);
|
||||
}
|
||||
|
||||
JSON config = DataListManager.instance.getFieldsLayout(entity, getRequestUser(request));
|
||||
JSON config = DataListManager.instance.getFieldsLayout(entity, user);
|
||||
mv.getModel().put("DataListConfig", JSON.toJSONString(config));
|
||||
|
||||
// 列表相关权限
|
||||
|
|
|
@ -71,7 +71,7 @@ public class ChartDataControll extends BaseControll {
|
|||
JSONObject config = (JSONObject) configEntry.getJSON("config");
|
||||
String sourceEntity = config.getString("entity");
|
||||
|
||||
String url = MessageFormat.format("../app/{0}/list?via={1}", sourceEntity, id);
|
||||
String url = MessageFormat.format("../app/{0}/list#via={1}", sourceEntity, id);
|
||||
response.sendRedirect(url);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22010,7 +22010,7 @@ fieldset[disabled] .full-calendar .fc-button:hover {
|
|||
.select2-container--default .select2-selection--multiple .select2-selection__rendered .select2-selection__clear {
|
||||
right: 20px;
|
||||
font-size: 1.35rem;
|
||||
top: -2px;
|
||||
top: -1px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
|
|
@ -587,6 +587,8 @@ div.dataTables_wrapper div.dataTables_filter {
|
|||
padding: 0 !important;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.modal-body.iframe iframe {
|
||||
|
@ -755,7 +757,7 @@ a {
|
|||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.rbform .select2-container--default .select2-selection--multiple::after,
|
||||
/* .rbform .select2-container--default .select2-selection--multiple::after,
|
||||
.type-REFERENCE .select2-container--default .select2-selection--single .select2-selection__arrow b:after {
|
||||
content: '\f1c3';
|
||||
font: normal normal normal 14px/1 'Material-Design-Iconic-Font';
|
||||
|
@ -765,7 +767,7 @@ a {
|
|||
position: absolute;
|
||||
right: 8px;
|
||||
top: 9px;
|
||||
}
|
||||
} */
|
||||
|
||||
.type-REFERENCE .select2-container--default .select2-selection--single .select2-selection__arrow b:after {
|
||||
right: 7px;
|
||||
|
@ -978,7 +980,7 @@ a {
|
|||
.datetime-field .clean {
|
||||
position: absolute;
|
||||
right: 45px;
|
||||
top: 1px;
|
||||
top: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #404040;
|
||||
|
@ -3495,6 +3497,36 @@ a.icon-link>.zmdi {
|
|||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.badge-border {
|
||||
display: inline-block;
|
||||
border-color: #fbbc05;
|
||||
color: #fbbc05;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
padding: 3px 6px;
|
||||
position: relative;
|
||||
padding-right: 30px;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.badge-border .close {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 24px;
|
||||
border-left: 1px solid #fbbc05;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding-top: 3px;
|
||||
opacity: 1;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.badge-border:hover .close {
|
||||
background-color: #fbbc05;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* text overflow */
|
||||
|
||||
.aside-header .title,
|
||||
|
|
|
@ -419,9 +419,9 @@ function __renderRichContent(e) {
|
|||
}
|
||||
{e.type === 3 && <div>
|
||||
{contentMore.showWhere > 0 &&
|
||||
<div><span>展示位置 : </span> {__findMaskTexts(contentMore.showWhere, ANN_OPTIONS).join('、')}</div>}
|
||||
<div><span>公示位置 : </span> {__findMaskTexts(contentMore.showWhere, ANN_OPTIONS).join('、')}</div>}
|
||||
{(contentMore.timeStart || contentMore.timeEnd) &&
|
||||
<div><span>展示时间 : </span> {contentMore.timeStart || ''} 至 {contentMore.timeEnd}</div>}
|
||||
<div><span>公示时间 : </span> {contentMore.timeStart || ''} 至 {contentMore.timeEnd}</div>}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -448,7 +448,7 @@ class AnnouncementOptions extends React.Component {
|
|||
render() {
|
||||
return <div className="feed-options announcement">
|
||||
<dl className="row mb-1">
|
||||
<dt className="col-12 col-lg-3">同时展示在</dt>
|
||||
<dt className="col-12 col-lg-3">同时公示在</dt>
|
||||
<dd className="col-12 col-lg-9 mb-0" ref={(c) => this._showWhere = c}>
|
||||
<label className="custom-control custom-checkbox custom-control-inline">
|
||||
<input className="custom-control-input" name="showOn" type="checkbox" value={1} disabled={this.props.readonly} />
|
||||
|
@ -460,12 +460,12 @@ class AnnouncementOptions extends React.Component {
|
|||
</label>
|
||||
<label className="custom-control custom-checkbox custom-control-inline">
|
||||
<input className="custom-control-input" name="showOn" type="checkbox" value={4} disabled={this.props.readonly} />
|
||||
<span className="custom-control-label">登录页 <i className="zmdi zmdi-help zicon down-3" data-toggle="tooltip" title="选择登录页展示请注意不要发布敏感信息" /></span>
|
||||
<span className="custom-control-label">登录页 <i className="zmdi zmdi-help zicon down-3" data-toggle="tooltip" title="选择登录页公示请注意不要发布敏感信息" /></span>
|
||||
</label>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl className="row">
|
||||
<dt className="col-12 col-lg-3 pt-2">展示时间</dt>
|
||||
<dt className="col-12 col-lg-3 pt-2">公示时间</dt>
|
||||
<dd className="col-12 col-lg-9" ref={(c) => this._showTime = c}>
|
||||
<div className="input-group">
|
||||
<input type="text" className="form-control form-control-sm" placeholder="现在" />
|
||||
|
|
|
@ -96,7 +96,7 @@ class MessageList extends React.Component {
|
|||
}, () => {
|
||||
$.get(`/notification/messages?type=${this.state.type}&pageNo=${this.state.page}`, (res) => {
|
||||
this.setState({ list: res.data || [] }, () => {
|
||||
if (focusItem) setTimeout(() => $gotoSection($('.notification.focus').offset().top - 66), 200)
|
||||
if (focusItem && $('.notification.focus').length > 0) setTimeout(() => $gotoSection($('.notification.focus').offset().top - 66), 200)
|
||||
focusItem = null
|
||||
})
|
||||
})
|
||||
|
|
|
@ -33,12 +33,12 @@ class RbModal extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const root = $(this._rbmodal).modal({ show: true, backdrop: this.props.backdrop === false ? false : 'static', keyboard: false })
|
||||
const $root = $(this._rbmodal).modal({ show: true, backdrop: this.props.backdrop === false ? false : 'static', keyboard: false })
|
||||
.on('hidden.bs.modal', () => {
|
||||
$keepModalOpen()
|
||||
if (this.props.disposeOnHide === true) {
|
||||
root.modal('dispose')
|
||||
$unmount(root.parent())
|
||||
$root.modal('dispose')
|
||||
$unmount($root.parent())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -56,13 +56,13 @@ class RbModal extends React.Component {
|
|||
resize() {
|
||||
if (this.props.children) return
|
||||
|
||||
const root = $(this._rbmodal)
|
||||
const $root = $(this._rbmodal)
|
||||
$setTimeout(() => {
|
||||
let iframe = root.find('iframe')
|
||||
let height = iframe.contents().find('.main-content').outerHeight()
|
||||
if (height === 0) height = iframe.contents().find('body').height()
|
||||
const $iframe = $root.find('iframe')
|
||||
let height = $iframe.contents().find('.main-content').outerHeight()
|
||||
if (height === 0) height = $iframe.contents().find('body').height()
|
||||
// else height += 45 // .main-content's padding
|
||||
root.find('.modal-body').height(height)
|
||||
$root.find('.modal-body').height(height)
|
||||
this.setState({ frameLoad: false })
|
||||
}, 20, 'RbModal-resize')
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ class RbFormHandler extends RbModalHandler {
|
|||
const id = target.dataset.id || target.name
|
||||
if (!id) return
|
||||
const val = target.type === 'checkbox' ? target.checked : target.value
|
||||
let s = {}
|
||||
const s = {}
|
||||
s[id] = val
|
||||
this.setState(s, call)
|
||||
this.handleChangeAfter(id, val)
|
||||
|
@ -157,10 +157,9 @@ class RbFormHandler extends RbModalHandler {
|
|||
|
||||
componentWillUnmount() {
|
||||
// destroy select2
|
||||
const ss = this.__select2
|
||||
if (ss) {
|
||||
if ($.type(ss) === 'array') $(ss).each(function () { this.select2('destroy') })
|
||||
else ss.select2('destroy')
|
||||
if (this.__select2) {
|
||||
if ($.type(this.__select2) === 'array') $(this.__select2).each(function () { this.select2('destroy') })
|
||||
else this.__select2.select2('destroy')
|
||||
this.__select2 = null
|
||||
}
|
||||
}
|
||||
|
@ -181,21 +180,22 @@ class RbAlert extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
let style = {}
|
||||
if (this.props.width) style.maxWidth = ~~this.props.width
|
||||
|
||||
return <div className="modal rbalert" ref={(c) => this._dlg = c} tabIndex={this.state.tabIndex || -1}>
|
||||
<div className="modal-dialog modal-dialog-centered" style={style}>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header pb-0">
|
||||
<button className="close" type="button" onClick={() => this.hide()}><span className="zmdi zmdi-close" /></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{this.renderContent()}
|
||||
const styles = {}
|
||||
if (this.props.width) styles.maxWidth = ~~this.props.width
|
||||
return (
|
||||
<div className="modal rbalert" ref={(c) => this._dlg = c} tabIndex={this.state.tabIndex || -1}>
|
||||
<div className="modal-dialog modal-dialog-centered" style={styles}>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header pb-0">
|
||||
<button className="close" type="button" onClick={() => this.hide()}><span className="zmdi zmdi-close" /></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{this.renderContent()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
|
@ -210,21 +210,23 @@ class RbAlert extends React.Component {
|
|||
const cancel = (this.props.cancel || this.hide).bind(this)
|
||||
const confirm = (this.props.confirm || this.hide).bind(this)
|
||||
|
||||
return <div className="text-center ml-6 mr-6">
|
||||
<div className={`text-${type}`}><i className={`modal-main-icon zmdi zmdi-${icon}`} /></div>
|
||||
{this.props.title && <h4 className="mb-2 mt-3">{this.props.title}</h4>}
|
||||
<div className={this.props.title ? '' : 'mt-3'}>{content}</div>
|
||||
<div className="mt-4 mb-3">
|
||||
<button disabled={this.state.disable} className="btn btn-space btn-secondary" type="button" onClick={cancel}>{this.props.cancelText || '取消'}</button>
|
||||
<button disabled={this.state.disable} className={`btn btn-space btn-${type}`} type="button" onClick={confirm}>{this.props.confirmText || '确定'}</button>
|
||||
return (
|
||||
<div className="text-center ml-6 mr-6">
|
||||
<div className={`text-${type}`}><i className={`modal-main-icon zmdi zmdi-${icon}`} /></div>
|
||||
{this.props.title && <h4 className="mb-2 mt-3">{this.props.title}</h4>}
|
||||
<div className={this.props.title ? '' : 'mt-3'}>{content}</div>
|
||||
<div className="mt-4 mb-3">
|
||||
<button disabled={this.state.disable} className="btn btn-space btn-secondary" type="button" onClick={cancel}>{this.props.cancelText || '取消'}</button>
|
||||
<button disabled={this.state.disable} className={`btn btn-space btn-${type}`} type="button" onClick={confirm}>{this.props.confirmText || '确定'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const root = $(this._dlg).modal({ show: true, keyboard: true }).on('hidden.bs.modal', () => {
|
||||
root.modal('dispose')
|
||||
$unmount(root.parent())
|
||||
const $root = $(this._dlg).modal({ show: true, keyboard: true }).on('hidden.bs.modal', () => {
|
||||
$root.modal('dispose')
|
||||
$unmount($root.parent())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -253,7 +255,7 @@ class RbAlert extends React.Component {
|
|||
}
|
||||
|
||||
ext = ext || {}
|
||||
let props = { ...ext, title: titleOrExt }
|
||||
const props = { ...ext, title: titleOrExt }
|
||||
if (ext.html === true) props.htmlMessage = message
|
||||
else props.message = message
|
||||
renderRbcomp(<RbAlert {...props} />, null, ext.call)
|
||||
|
@ -275,13 +277,15 @@ class RbHighbar extends React.Component {
|
|||
? <div className="message pl-0" dangerouslySetInnerHTML={{ __html: this.props.htmlMessage }} />
|
||||
: <div className="message pl-0">{this.props.message}</div>
|
||||
|
||||
return <div ref={(c) => this._rbhighbar = c} className={`rbhighbar animated faster ${this.state.animatedClass}`}>
|
||||
<div className={`alert alert-dismissible alert-${(this.props.type || 'warning')} mb-0`}>
|
||||
<button className="close" type="button" onClick={this.close}><i className="zmdi zmdi-close" /></button>
|
||||
<div className="icon"><i className={`zmdi zmdi-${icon}`} /></div>
|
||||
{content}
|
||||
return (
|
||||
<div ref={(c) => this._rbhighbar = c} className={`rbhighbar animated faster ${this.state.animatedClass}`}>
|
||||
<div className={`alert alert-dismissible alert-${(this.props.type || 'warning')} mb-0`}>
|
||||
<button className="close" type="button" onClick={this.close}><i className="zmdi zmdi-close" /></button>
|
||||
<div className="icon"><i className={`zmdi zmdi-${icon}`} /></div>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -328,25 +332,29 @@ function RbAlertBox(props) {
|
|||
const type = (props || {}).type || 'warning'
|
||||
const icon = type === 'success' ? 'check' : (type === 'danger' ? 'close-circle-o' : 'info-outline')
|
||||
|
||||
return <div className={`alert alert-icon alert-icon-border alert-dismissible alert-sm alert-${type}`}>
|
||||
<div className="icon"><i className={`zmdi zmdi-${icon}`} /></div>
|
||||
<div className="message">
|
||||
<a className="close" data-dismiss="alert"><i className="zmdi zmdi-close" /></a>
|
||||
<p>{props.message || 'INMESSAGE'}</p>
|
||||
return (
|
||||
<div className={`alert alert-icon alert-icon-border alert-dismissible alert-sm alert-${type}`}>
|
||||
<div className="icon"><i className={`zmdi zmdi-${icon}`} /></div>
|
||||
<div className="message">
|
||||
<a className="close" data-dismiss="alert"><i className="zmdi zmdi-close" /></a>
|
||||
<p>{props.message || 'INMESSAGE'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ~~ 加载动画
|
||||
function RbSpinner(props) {
|
||||
const spinner = <div className="rb-spinner">
|
||||
{$.browser.msie
|
||||
? <span className="spinner-border spinner-border-xl text-primary"></span>
|
||||
: <svg width="40px" height="40px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle fill="none" strokeWidth="4" strokeLinecap="round" cx="33" cy="33" r="30" className="circle" />
|
||||
</svg>
|
||||
}
|
||||
</div>
|
||||
const spinner = (
|
||||
<div className="rb-spinner">
|
||||
{$.browser.msie
|
||||
? <span className="spinner-border spinner-border-xl text-primary"></span>
|
||||
: <svg width="40px" height="40px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle fill="none" strokeWidth="4" strokeLinecap="round" cx="33" cy="33" r="30" className="circle" />
|
||||
</svg>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
if (props && props.fully === true) return <div className="rb-loading rb-loading-active">{spinner}</div>
|
||||
return spinner
|
||||
}
|
||||
|
@ -507,19 +515,26 @@ class UserSelector extends React.Component {
|
|||
const UserShow = function (props) {
|
||||
const viewUrl = props.id ? `#!/View/User/${props.id}` : null
|
||||
const avatarUrl = `${rb.baseUrl}/account/user-avatar/${props.id}`
|
||||
return <a href={viewUrl} className="user-show" title={props.name} onClick={props.onClick}>
|
||||
<div className={`avatar ${props.showName === true ? ' float-left' : ''}`}>{props.icon ? <i className={props.icon} /> : <img src={avatarUrl} alt="Avatar" />}</div>
|
||||
{props.showName && (<div className={`text-truncate name ${props.deptName ? 'vm' : ''}`}>{props.name}{props.deptName && <em>{props.deptName}</em>}</div>)}
|
||||
</a>
|
||||
return (
|
||||
<a href={viewUrl} className="user-show" title={props.name} onClick={props.onClick}>
|
||||
<div className={`avatar ${props.showName === true ? ' float-left' : ''}`}>{props.icon ? <i className={props.icon} /> : <img src={avatarUrl} alt="Avatar" />}</div>
|
||||
{props.showName && (<div className={`text-truncate name ${props.deptName ? 'vm' : ''}`}>{props.name}{props.deptName && <em>{props.deptName}</em>}</div>)}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* JSX 组件渲染
|
||||
* @param {*} jsx
|
||||
* @param {*} target id or object of element
|
||||
* @param {*} target id or object of element (or function of callback)
|
||||
* @param {*} call callback
|
||||
*/
|
||||
const renderRbcomp = function (jsx, target, call) {
|
||||
if (typeof target === 'function') {
|
||||
call = target
|
||||
target = null
|
||||
}
|
||||
|
||||
target = target || $random('react-comps-')
|
||||
if ($.type(target) === 'string') { // element id
|
||||
const container = document.getElementById(target)
|
||||
|
|
|
@ -191,6 +191,7 @@ class RbList extends React.Component {
|
|||
pageSize: this.pageSize,
|
||||
filter: this.lastFilter,
|
||||
advFilter: this.advFilterId,
|
||||
protocolFilter: wpc.protocolFilter,
|
||||
sort: fieldSort,
|
||||
reload: this.pageNo === 1
|
||||
}
|
||||
|
@ -751,12 +752,10 @@ const AdvFilters = {
|
|||
/**
|
||||
* @param {Element} el 控件
|
||||
* @param {String} entity 实体
|
||||
* @param {ID} viaFilter 默认高级过滤 ID
|
||||
*/
|
||||
init(el, entity, viaFilter) {
|
||||
init(el, entity) {
|
||||
this.__el = $(el)
|
||||
this.__entity = entity
|
||||
this.__viaFilter = viaFilter
|
||||
|
||||
this.__el.find('.J_advfilter').click(() => {
|
||||
this.showAdvFilter(null, this.current)
|
||||
|
@ -833,16 +832,8 @@ const AdvFilters = {
|
|||
$ghost.appendTo($('#asideFilters').empty())
|
||||
}
|
||||
|
||||
// 首次使用
|
||||
if (that.__viaFilter) {
|
||||
RbListPage._RbList.setAdvFilter(that.__viaFilter)
|
||||
that.__viaFilter = null
|
||||
}
|
||||
else {
|
||||
if (!$defaultFilter) $defaultFilter = $('.adv-search .dropdown-item:eq(0)')
|
||||
$defaultFilter.trigger('click')
|
||||
}
|
||||
|
||||
if (!$defaultFilter) $defaultFilter = $('.adv-search .dropdown-item:eq(0)')
|
||||
$defaultFilter.trigger('click')
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -910,13 +901,22 @@ const AdvFilters = {
|
|||
|
||||
// init: DataList
|
||||
$(document).ready(() => {
|
||||
const gs = $urlp('gs', location.hash)
|
||||
const viaFilter = $urlp('via')
|
||||
const via = $urlp('via', location.hash)
|
||||
if (via) {
|
||||
wpc.protocolFilter = `via:${via}`
|
||||
const $cleanVia = $('<div class="badge badge-border float-left ml-2 mt-1">当前数据已过滤<a class="close" title="查看全部数据">×</a></div>').appendTo('.dataTables_filter')
|
||||
$cleanVia.find('a').click(() => {
|
||||
wpc.protocolFilter = null
|
||||
RbListPage.reload()
|
||||
$cleanVia.remove()
|
||||
})
|
||||
}
|
||||
|
||||
const gs = $urlp('gs', location.hash)
|
||||
if (gs) $('.search-input-gs, .input-search>input').val($decode(gs))
|
||||
if (wpc.entity) {
|
||||
RbListPage.init(wpc.listConfig, wpc.entity, wpc.privileges)
|
||||
if (!(wpc.advFilter === false)) AdvFilters.init('.adv-search', wpc.entity[0], viaFilter)
|
||||
if (wpc.advFilter !== false) AdvFilters.init('.adv-search', wpc.entity[0])
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -20,13 +20,15 @@ class RbFormModal extends React.Component {
|
|||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header modal-header-colored">
|
||||
{this.state.icon && (<span className={'icon zmdi zmdi-' + this.state.icon} />)}
|
||||
{this.state.icon
|
||||
&& <span className={'icon zmdi zmdi-' + this.state.icon} />}
|
||||
<h3 className="modal-title">{this.state.title || '新建'}</h3>
|
||||
{rb.isAdminUser ? <a className="close s" href={rb.baseUrl + '/admin/entity/' + this.state.entity + '/form-design'} title="配置布局" target="_blank"><span className="zmdi zmdi-settings"></span></a> : null}
|
||||
{rb.isAdminUser
|
||||
&& <a className="close s" href={rb.baseUrl + '/admin/entity/' + this.state.entity + '/form-design'} title="配置布局" target="_blank"><span className="zmdi zmdi-settings"></span></a>}
|
||||
<button className="close md-close" type="button" onClick={() => this.hide()}><span className="zmdi zmdi-close"></span></button>
|
||||
</div>
|
||||
<div className={'modal-body rb-loading' + (this.state.inLoad ? ' rb-loading-active' : '')}>
|
||||
{this.state.alertMessage && (<div className="alert alert-warning rbform-alert">{this.state.alertMessage}</div>)}
|
||||
{this.state.alertMessage && <div className="alert alert-warning rbform-alert">{this.state.alertMessage}</div>}
|
||||
{this.state.formComponent}
|
||||
{this.state.inLoad && <RbSpinner />}
|
||||
</div>
|
||||
|
@ -67,10 +69,12 @@ class RbFormModal extends React.Component {
|
|||
}
|
||||
|
||||
renderFromError(message) {
|
||||
const error = <div className="alert alert-danger alert-icon mt-5 w-75 mlr-auto">
|
||||
<div className="icon"><i className="zmdi zmdi-alert-triangle"></i></div>
|
||||
<div className="message" dangerouslySetInnerHTML={{ __html: '<strong>抱歉!</strong> ' + message }}></div>
|
||||
</div>
|
||||
const error = (
|
||||
<div className="alert alert-danger alert-icon mt-5 w-75 mlr-auto">
|
||||
<div className="icon"><i className="zmdi zmdi-alert-triangle"></i></div>
|
||||
<div className="message" dangerouslySetInnerHTML={{ __html: '<strong>抱歉!</strong> ' + message }}></div>
|
||||
</div>
|
||||
)
|
||||
this.setState({ formComponent: error }, () => this.setState({ inLoad: false }))
|
||||
}
|
||||
|
||||
|
@ -832,7 +836,15 @@ class RbFormReference extends RbFormElement {
|
|||
|
||||
renderElement() {
|
||||
if (this.props.readonly) return super.renderElement(this.props.value ? this.props.value.text : null)
|
||||
return <select ref={(c) => this._fieldValue = c} className="form-control form-control-sm" />
|
||||
// return <select ref={(c) => this._fieldValue = c} className="form-control form-control-sm" />
|
||||
return (
|
||||
<div className="input-group datetime-field">
|
||||
<select ref={(c) => this._fieldValue = c} className="form-control form-control-sm" />
|
||||
<div className="input-group-append">
|
||||
<button className="btn btn-secondary" type="button" onClick={this.showSearch}><i className="icon zmdi zmdi-search" /></button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderViewElement() {
|
||||
|
@ -911,6 +923,24 @@ class RbFormReference extends RbFormElement {
|
|||
this.handleChange({ target: { value: val.id } }, true)
|
||||
} else this.__select2.val(null).trigger('change')
|
||||
}
|
||||
|
||||
showSearch = () => {
|
||||
const that = this
|
||||
referenceSearch__call = function (selected) {
|
||||
selected = selected[0]
|
||||
$.get(`/commons/search/read-labels?ids=${selected}`, (res) => {
|
||||
const o = new Option(res.data[selected], selected, true, true)
|
||||
that.__select2.append(o).trigger('change')
|
||||
})
|
||||
that.__searcher.hide()
|
||||
}
|
||||
|
||||
if (this.__searcher) this.__searcher.show()
|
||||
else {
|
||||
const searchUrl = `${rb.baseUrl}/commons/search/reference-search-list?field=${this.props.field}.${this.props.$$$parent.props.entity}`
|
||||
renderRbcomp(<ReferenceSearcher url={searchUrl} title={`查询${this.props.label}`} />, function () { that.__searcher = this })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RbFormClassification extends RbFormElement {
|
||||
|
@ -1317,6 +1347,34 @@ class ClassificationSelector extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
// see `reference-search.jsp`
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
var referenceSearch__call = function (selected) {/* NOOP */ }
|
||||
class ReferenceSearcher extends RbModal {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="modal rbmodal colored-header colored-header-primary" ref={(c) => this._rbmodal = c}>
|
||||
<div className="modal-dialog" style={{ maxWidth: 1220 }}>
|
||||
<div className="modal-content" style={{ maxWidth: 1220 }}>
|
||||
<div className="modal-header modal-header-colored">
|
||||
<h3 className="modal-title">{this.props.title || '查询'}</h3>
|
||||
<button className="close" type="button" onClick={() => this.hide()}><span className="zmdi zmdi-close" /></button>
|
||||
</div>
|
||||
<div className="modal-body iframe">
|
||||
<iframe src={this.props.url} frameBorder="0" style={{ height: 600, maxHeight: '100%' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除确认
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
class DeleteConfirm extends RbAlert {
|
||||
|
|
|
@ -484,7 +484,8 @@ var $initReferenceSelect2 = function (el, field) {
|
|||
noResults: function () { return (search_input || '').length > 0 ? '未找到结果' : '输入关键词搜索' },
|
||||
inputTooShort: function () { return '输入关键词搜索' },
|
||||
searching: function () { return '搜索中...' },
|
||||
maximumSelected: function () { return '只能选择 1 项' }
|
||||
maximumSelected: function () { return '只能选择 1 项' },
|
||||
removeAllItems: function () { return '清除' }
|
||||
},
|
||||
theme: `default ${field.appendClass || ''}`
|
||||
})
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
<div class="input-group-append"><button title="高级查询" class="btn btn-secondary J_advfilter" type="button"><i class="icon zmdi zmdi-filter-list"></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group input-search">
|
||||
<div class="input-group input-search float-left">
|
||||
<input class="form-control" type="text" placeholder="查询${entityLabel}" maxlength="40">
|
||||
<span class="input-group-btn"><button class="btn btn-secondary" type="button"><i class="icon zmdi zmdi-search"></i></button></span>
|
||||
</div>
|
||||
|
|
69
src/main/webapp/general-entity/reference-search.jsp
Normal file
69
src/main/webapp/general-entity/reference-search.jsp
Normal file
|
@ -0,0 +1,69 @@
|
|||
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>查询${entityLabel}</title>
|
||||
<style type="text/css">
|
||||
.rb-datatable-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #f7f7f7;
|
||||
z-index: 10;
|
||||
}
|
||||
#react-list {
|
||||
margin-top: 68px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="dialog">
|
||||
<div class="main-content container-fluid p-0">
|
||||
<div class="card card-table">
|
||||
<div class="card-body">
|
||||
<div class="dataTables_wrapper container-fluid">
|
||||
<div class="row rb-datatable-header">
|
||||
<div class="col-6">
|
||||
<div class="dataTables_filter">
|
||||
<div class="input-group input-search">
|
||||
<input class="form-control" type="text" placeholder="查询${entityLabel}" maxlength="40">
|
||||
<span class="input-group-btn"><button class="btn btn-secondary" type="button"><i class="icon zmdi zmdi-search"></i></button></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="dataTables_oper">
|
||||
<button class="btn btn-space btn-primary J_select"><i class="icon zmdi zmdi-check"></i> 确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="react-list" class="rb-loading rb-loading-active data-list">
|
||||
<%@ include file="/_include/Spinner.jsp"%>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%@ include file="/_include/Foot.jsp"%>
|
||||
<script>
|
||||
window.__PageConfig = {
|
||||
type: 'RecordList',
|
||||
entity: ['${entityName}','${entityLabel}','${entityIcon}'],
|
||||
listConfig: ${DataListConfig},
|
||||
advFilter: false,
|
||||
protocolFilter: '${referenceFilter}'
|
||||
}
|
||||
</script>
|
||||
<script src="${baseUrl}/assets/js/rb-datalist.jsx" type="text/babel"></script>
|
||||
<script type="text/babel">
|
||||
$(document).ready(function () {
|
||||
$('.J_select').click(function () {
|
||||
const ss = RbListPage._RbList.getSelectedIds()
|
||||
if (ss.length > 0 && parent && parent.referenceSearch__call) parent.referenceSearch__call(ss)
|
||||
else console.log(ss)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -59,7 +59,7 @@
|
|||
<div class="input-group-append"><button title="高级查询" class="btn btn-secondary J_advfilter" type="button"><i class="icon zmdi zmdi-filter-list"></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group input-search">
|
||||
<div class="input-group input-search float-left">
|
||||
<input class="form-control" type="text" placeholder="查询${entityLabel}" maxlength="40">
|
||||
<span class="input-group-btn"><button class="btn btn-secondary" type="button"><i class="icon zmdi zmdi-search"></i></button></span>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue