开发日志——标签搜索开发
最近这个月都在做带标签的搜索,主要使用的技术为elasticsearch+springmvc+spring 前端使用的是vue.js+bootstrap
1.业务分析
平台面向用户为成都局各个市辖区的环保部门,以前的关键字搜索是采用数据库的模糊查询,多字段的like,效率低,不够智能,用户的数量增长起来,且日常的收发文增多,搜索反馈就很不好。
现在使用elasticsearch进行搜索业务的重构,增加高亮显示,分词搜索,自定义分词规则,提高了用户的搜索体验和搜索反馈速度
2.elasticsearch的搭建
选用版本 6.3.1,pom如下,其中elasticsearch的搭建非常简单,只需要配置名称与端口号即可
POM:
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.3.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.3.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.3.1</version>
</dependency>
3.spring的配置
#es配置
#申明es服务地址
elasticsearch.host=
elasticsearch.port=8080
elasticsearch.schema=http
elasticsearch.connectTimeOut=1000
elasticsearch.socketTimeOut=30000
elasticsearch.connectionRequestTimeOut=500
elasticsearch.maxConnectNum=100
elasticsearch.maxConnectPerRoute=100
elasticsearch.indexName=
elasticsearch.esType=
# 默认查询条数
elasticsearch.size=2
配置类:
package ths.project.common.config;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @Title: ElasticsearchConfig
* @Description: Elasticsearch 配置类*/
@Configuration
public class ElasticsearchConfig {
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
@Value("${elasticsearch.schema}")
private String schema;
@Value("${elasticsearch.connectTimeOut}")
private int connectTimeOut;
@Value("${elasticsearch.socketTimeOut}")
private int socketTimeOut;
@Value("${elasticsearch.connectionRequestTimeOut}")
private int connectionRequestTimeOut;
@Value("${elasticsearch.maxConnectNum}")
private int maxConnectNum;
@Value("${elasticsearch.maxConnectPerRoute}")
private int maxConnectPerRoute;
private HttpHost httpHost;
private boolean uniqueConnectTimeConfig = true;
private boolean uniqueConnectNumConfig = true;
private RestClientBuilder builder;
private RestHighLevelClient client;
@Bean(autowire = Autowire.BY_NAME, name = "restHighLevelClient")
public RestHighLevelClient client() {
httpHost= new HttpHost(host, port, schema);
builder = RestClient.builder(httpHost);
if (uniqueConnectTimeConfig) {
setConnectTimeOutConfig();
}
if (uniqueConnectNumConfig) {
setMutiConnectConfig();
}
client = new RestHighLevelClient(builder);
return client;
}
/**
* 异步httpclient的连接延时配置
*/
public void setConnectTimeOutConfig() {
builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
requestConfigBuilder.setConnectTimeout(connectTimeOut);
requestConfigBuilder.setSocketTimeout(socketTimeOut);
requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);
return requestConfigBuilder;
}
});
}
/**
* 异步httpclient的连接数配置
*/
public void setMutiConnectConfig() {
builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
httpClientBuilder.setMaxConnTotal(maxConnectNum);
httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
return httpClientBuilder;
}
});
}
/**
* 关闭连接
*/
public void close() {
if (client != null) {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.搜索模型的创建+自定义分词器
搜索模型其实就是我们SQL整合的结果,在es中存放的mapping,其中主要关键的是字段的类型选择,是否分词与分词规则,具体需要结合业务来考虑,不过在标签的搜索,由于我们是可以选择同类是多个标签,所以我们需要将标签用特殊符号连接在一起,然后在es查询中按照规则进行拆分。即标签使用自定义分词器,关键词搜索使用ik分词器
PUT /workmanager
{
"settings":{
"number_of_shards":1,
"number_of_replicas":1,
"analysis": {
"analyzer": {
"comma": {
"type": "pattern",
"pattern":","
}
}
}
},
"mappings":{
"work":{
"properties":{
"id":{"type":"keyword"},
"BUSINESS_TYPE_NAME":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"SOURCE_DEPT_NAME":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"HINT_NAME":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"WORK_TYPE_NAME":{"type":"keyword"},
"WORK_TYPE_CODE":{"type":"keyword"},
"LEADER_DEPT":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"TASK_NAME":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_smart"},
"MACTCH_DEPT":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"RECEIVE_DATE":{"type":"date"},
"HANDLE_DATE":{"type":"date"},
"DEPT_NAME":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_max_word"},
"TASK_STATE_NAME":{"type":"text","analyzer":"comma","search_analyzer":"comma"},
"FILE_NAME":{"type":"text","analyzer":"ik_max_word","search_analyzer":"ik_max_word"},
"SOURCE_NUM":{"type":"keyword"},
"DISTANCE_DAY":{"type":"integer"},
"TASK_STATE_CODE":{"type":"text","analyzer":"comma","search_analyzer":"comma"}
}
}
}
}
5.java操作elasticsearch
我并没有使用拼接elasticsearch的查询语句来查询,而是用的SearchSourceBuilder来进行条件的查询,其中可以添加不同的builder(相当于es中的查询条件)进行条件查询
1.条件查询+高亮+分页
/**
* @Author xp
* @Description 条件查询
* @Param [queryList, from] 查询内容集合 开始
* @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
**/
@SearchAnnotation(operation = OperationTypeEnums.WORKTYPE_MATCH_QUERY)
public List<Map<String,Object>> queryByMatch(List<Map<String,Object>> queryList,Integer from,String orderFiled){
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
List<Map<String,Object>> queryResultList=new ArrayList<>();
//分页构建
if (from == null) {
sourceBuilder.from(0);
} else {
sourceBuilder.from(from);
}
sourceBuilder.size(size);
List<String> listFileds=new ArrayList<>();
BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
//构建sourceBuilder
queryList.forEach(e->{
//需要指定字段返回
//根据不同条件添加查询builder
if((SearchEnums.FILED_TEXT.getCode().equals(MapUtils.getString(e,SearchEnums.FILED_TYPE.getCode())))){
QueryBuilder queryBuilder = QueryBuilders.matchQuery( MapUtils.getString(e, SearchEnums.SEARCH_FIELD.getCode()), MapUtils.getString(e, SearchEnums.NAME.getCode()))
;
boolBuilder.should(queryBuilder);
}else{
QueryBuilder queryBuilder = QueryBuilders.matchQuery( MapUtils.getString(e, SearchEnums.SEARCH_FIELD.getCode()), MapUtils.getString(e, SearchEnums.NAME.getCode()))
.operator(Operator.AND);
boolBuilder.must(queryBuilder);
}
});
//高亮响应字段
this.getHighlightBuilder(queryList,sourceBuilder);
//搜索的字段 第一个为查询的字段 后面是过滤的字段
sourceBuilder.fetchSource( listFileds.toArray(new String[]{}), new String[]{});
sourceBuilder.query(boolBuilder);
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.types(esType);
searchRequest.source(sourceBuilder);
//排序
if(StringUtils.isNotEmpty(orderFiled)){
sourceBuilder.sort(new FieldSortBuilder(orderFiled).order(SortOrder.ASC));
}
try {
SearchResponse response = restHighLevelClient.search(searchRequest);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit searchHit : searchHits) {
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
if (MapUtils.isNotEmpty(highlightFields)) {
highlightFields.forEach((k, v) -> {
HighlightField titleField = highlightFields.get(k);
Text[] fragments = titleField.fragments();
StringBuilder name = new StringBuilder();
for (Text text : fragments) {
name.append(text);
}
sourceAsMap.put(k, name.toString());
});
}
queryResultList.add(sourceAsMap);
}
} catch (IOException e) {
e.printStackTrace();
}
return queryResultList;
}
/**
* @Author xp
* @Description 需要高亮的字段
* @Param [queryMap] key--->高亮的字段 value---->高亮的颜色(没有 默认为unified)
* @return org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder
**/
private void getHighlightBuilder(List<Map<String,Object>> queryList,SearchSourceBuilder sourceBuilder){
HighlightBuilder highlightBuilder = new HighlightBuilder(); //创建一个新的HighlightBuilder。
//高亮字段
queryList.forEach(e->{
HighlightBuilder.Field highlightTitle= new HighlightBuilder.Field(MapUtils.getString(e,SearchEnums.SEARCH_FIELD.getCode())); //为title字段创建字段高光色。
//高亮颜色
highlightBuilder.requireFieldMatch(false);
highlightTitle.preTags("<span style=\"color:red\">");
highlightTitle.postTags("</span>");
highlightBuilder.field(highlightTitle); //将字段高光色添加到高亮构建器。
});
sourceBuilder.highlighter(highlightBuilder);
}
2.聚合查询
/**
* @Author xp
* @Description 聚合和搜索
* @Param [queryList, from, orderFiled] 查询字段集合 开始 排序字段
* @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
**/
@SearchAnnotation(operation = OperationTypeEnums.WORKTYPE_AGGS_QUERY)
public List<Map<String,Object>> queryByAggs(List<Map<String,Object>> queryList,Integer from,Integer size,String orderFiled,String aggField){
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
List<Map<String,Object>> queryResultList=new ArrayList<>();
BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
//构建sourceBuilder
queryList.forEach(e->{
//需要指定字段返回
//根据不同条件添加查询builder
QueryBuilder queryBuilder =queryBuilder = QueryBuilders.matchQuery( MapUtils.getString(e, SearchEnums.SEARCH_FIELD.getCode()), MapUtils.getString(e, SearchEnums.NAME.getCode()))
.operator(Operator.AND);
boolBuilder.must(queryBuilder);
});
//聚合查询
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(aggField).field(aggField).subAggregation(AggregationBuilders.topHits(SearchEnums.TOP.getCode()).from(from).size(size).sort(orderFiled,SortOrder.ASC));
sourceBuilder.aggregation(termsAggregationBuilder);
//条件查询
sourceBuilder.query(boolBuilder);
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.types(esType);
searchRequest.source(sourceBuilder);
try {
SearchResponse response = restHighLevelClient.search(searchRequest);
Aggregations aggregations = response.getAggregations();
//聚合数据查询
Terms terms = aggregations.get(aggField);
if(terms==null){
return queryList;
}
SearchHits hits = null;
long docCount = 0;
for(Terms.Bucket buck : terms.getBuckets()) {
docCount= Math.max(docCount, buck.getDocCount());
ParsedTopHits top = (ParsedTopHits) buck.getAggregations().getAsMap().get(SearchEnums.TOP.getCode());
hits = top.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit searchHit : searchHits) {
Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
queryResultList.add(sourceAsMap);
}
}
Map<String,Object> maxCountMap = new HashMap<>();
maxCountMap.put(SearchEnums.MAX_COUNT.getCode(),docCount);
queryResultList.add(maxCountMap);
} catch (IOException e) {
e.printStackTrace();
}
return queryResultList;
}
6.前端模型的创建与搜索组件的构建
前端使用的是vue.js 将搜索组件抽成了一个组件的方式,方便不同页面调用,其中各个页面只需要传入自己的code码就可以查询自己标签,进行自己的内容搜索,其中一些特殊的标签如时间框之类是根据数据库他带的类型来进行区别
页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="search" class="small-content content" v-cloak>
<div class="main">
<!-- 顶部筛选块 -->
<div class="main-header">
<div class="main-header-hd">
<%--搜索框--%>
<div class="serach-input">
<div class="input-group mb-3">
<input type="text" id="main-search" class="form-control" placeholder="请输入关键字查询" aria-label="请输入关键字查询" v-model="searchObj.keywordSearch" aria-describedby="button-addon2" @keyup.enter="submitSearch()">
<div class="input-group-append">
<button class="btn btn-primary" type="button" id="button-addon2" @click="submitSearch()">
<svg class="bi bi-search g-icon" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M10.442 10.442a1 1 0 0 1 1.415 0l3.85 3.85a1 1 0 0 1-1.414 1.415l-3.85-3.85a1 1 0 0 1 0-1.415z" clip-rule="evenodd"/>
<path fill-rule="evenodd" d="M6.5 12a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM13 6.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z" clip-rule="evenodd"/>
</svg>
</button>
</div>
</div>
</div>
<%--标签内容--%>
<div class="main-header-hd-filterView g-flex-center-row">
<div class="main-header-hd-left">
<div class="tag-view g-flex-center-row">
<div class="tag-view-label">
<svg class="bi bi-tag-fill g-text-blue" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M2 1a1 1 0 0 0-1 1v4.586a1 1 0 0 0 .293.707l7 7a1 1 0 0 0 1.414 0l4.586-4.586a1 1 0 0 0 0-1.414l-7-7A1 1 0 0 0 6.586 1H2zm4 3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" clip-rule="evenodd"/>
</svg>
<span class="g-text-gray">已选标签:</span>
</div>
<%--已选 子标签--%>
<div class="tag-view-content" >
<div style="display: inline-block;text-align: left;">
<button class="btn g-btn-white g-btn" @click="unCheckedTag(checkedTag)" v-for="(checkedTag,index) in searchObj.FILTER_CHECKED_TAG_LIST" >
{{checkedTag.FATHER_NAME}}:
<span class="g-text-light-blue" v-if="checkedTag.FULL_NAME!=''&&checkedTag.FULL_NAME!=null" > {{checkedTag.FULL_NAME|fmt(checkedTag)}}</span>
<span class="g-text-light-blue" v-else >
{{checkedTag.NAME|fmt(checkedTag)}}
<svg class="bi bi-x g-text-font-20" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M11.854 4.146a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708-.708l7-7a.5.5 0 0 1 .708 0z" clip-rule="evenodd"></path>
<path fill-rule="evenodd" d="M4.146 4.146a.5.5 0 0 0 0 .708l7 7a.5.5 0 0 0 .708-.708l-7-7a.5.5 0 0 0-.708 0z" clip-rule="evenodd"></path>
</svg>
</span>
</button>
</div>
</div>
</div>
<div class="tag-view g-flex-center-row">
<div class="tag-view-label">
<svg class="bi bi-lightning-fill g-text-blue" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M11.251.068a.5.5 0 0 1 .227.58L9.677 6.5H13a.5.5 0 0 1 .364.843l-8 8.5a.5.5 0 0 1-.842-.49L6.323 9.5H3a.5.5 0 0 1-.364-.843l8-8.5a.5.5 0 0 1 .615-.09z" clip-rule="evenodd"/>
</svg>
<span class="g-text-gray">快捷标签:</span>
</div>
<%--快捷标签 子标签--%>
<div class="tag-view-content" v-for="(quickTag,index) in searchObj.QUICK_TAG_LIST">
<button class="btn g-btn-white g-btn" @click="confirmQuickTag(quickTag)">
{{quickTag.NAME}}
</button>
</div>
</div>
</div>
<div class="main-header-hd-right">
<button class="btn g-btn btn-no-border" @click="clearCheckedTag()">清空</button>
<button class="btn g-btn btn-no-border" @click="showTagList($event)">展开筛选
<i class="fa fa-angle-down" style="font-size:21px;color:#575b63" aria-hidden="true" ></i>
</button>
</div>
</div>
</div>
<div class="main-header-bd g-flex-center">
<div id="tag" class="main-header-bd g-flex-center" v-show="searchObj.isShow" >
<div class="main-header-bd-item g-flex-center-row" v-for="(tag,indexInTag) in searchObj.TAG_LIST" v-show="!tag.isLongListShow&&indexInTag<searchObj.tagListFactSize" >
<span class="item-label g-text-gray" v-if="tag.COLUMN_TYPE==='1'">
</span>
<span class="item-label g-text-gray" v-else>
{{tag.NAME}}
</span>
<%--部门标签开始--%>
<div class="item-content g-flex-center-row" v-if="tag.TYPE==='DEPT1'" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
<%--部门标签结束--%>
<%--部门标签开始--%>
<div class="item-content g-flex-center-row" v-if="tag.TYPE==='DEPT2'" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
<%--部门标签结束--%>
<%--时间标签开始--%>
<div class="item-content g-flex-center-row" v-else-if="tag.TYPE==='TIME1'">
<div class="item-content g-flex-center-row" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
</div>
<%--时间标签开始--%>
<%--时间标签开始--%>
<div class="item-content g-flex-center-row" v-else-if="tag.TYPE==='TIME2'">
<div class="item-content g-flex-center-row" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
</div>
<%--时间标签开始--%>
<%--一般标签开始--%>
<div class="item-content g-flex-center-row" v-else>
<div class="item-content-left g-flex-center-row" >
<span class="item-content-span g-flex-center-row custom-control custom-checkbox" v-for="(tagNode,index) in tag.childrenCategoryList" v-if="tagNode.childrenCategoryList.length==0" >
<input type="checkbox" class="custom-control-input" :checked="tagNode.isChecked">
<label class="custom-control-label" @click="delegateCheckedTag($event,tagNode,indexInTag)">{{tagNode.NAME}}</label>
</span>
<%--存在二级子标签--%>
<span class="item-content-span g-flex-center-row custom-control custom-checkbox" v-for="(tagNode,index) in tag.childrenCategoryList" v-if="tagNode.childrenCategoryList.length>0">
<input type="checkbox" class="custom-control-input" :checked="tagNode.isChecked" >
<label class="custom-control-label" @click="confirmAllTwoTag($event,tagNode,indexInTag,index)" >{{tagNode.NAME}}</label>
<i class="fa fa-angle-down" style="font-size:21px;color:#575b63" aria-hidden="true" @click="confirmTwoTag($event,tagNode,indexInTag)"></i>
</span>
</div>
<button class="btn btn-white g-btn item-content-btn"v-if="tag.COLUMN_TYPE==='0'" @click="showLongTaglist($event,tag,indexInTag)" style="display: block;">{{searchObj.LONG_TIPS}}
<i class="fa fa-angle-down" style="font-size:15px;color:#575b63" aria-hidden="true" ></i>
</button>
</div>
<%--一般标签结束--%>
</div>
<div class="main-header-bd-item g-flex-center-row" v-for="(tag,indexInTag) in searchObj.TAG_LIST" v-show="indexInTag>=searchObj.tagListFactSize&&searchObj.isShowMore">
<span class="item-label g-text-gray">
{{tag.NAME}}
</span>
<%--部门标签开始--%>
<div class="item-content g-flex-center-row" v-if="tag.TYPE==='DEPT1'" >
<div class="item-content g-flex-center-row" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
</div>
<%--部门标签结束--%>
<%--部门标签开始--%>
<div class="item-content g-flex-center-row" v-if="tag.TYPE==='DEPT2'" >
<div class="item-content g-flex-center-row" >
<div class="layui-input-block" style="margin-left:0px" @click="deptSelect('LEADINGUNIT',indexInTag)">
<input type="text" name="title" required lay-verify="required" placeholder="请选择" autocomplete="off" class="layui-input" >
<div class="divbutton">选择</div>
</div>
</div>
</div>
<%--部门标签结束--%>
<%--时间标签开始--%>
<div class="item-content g-flex-center-row" v-else-if="tag.TYPE==='TIME1'">
<div class="layui-input-block" style="margin-left:0px">
<input type="text" class="layui-input " id="receivedate" readonly="readonly" placeholder="请选择收文日期666" >
<i class="layui-icon layui-icon-date receivedate"></i>
</div>
</div>
<%--时间标签开始--%>
<%--时间标签开始--%>
<div class="item-content g-flex-center-row" v-else-if="tag.TYPE==='TIME2'">
<div class="layui-input-block" style="margin-left:0px">
<input type="text" class="layui-input" readonly="readonly" placeholder="请选择收文日期" >
<i class="layui-icon layui-icon-date receivedate"></i>
</div>
</div>
<%--时间标签开始--%>
<%--一般标签开始--%>
<div class="item-content g-flex-center-row" v-else>
<div class="item-content-left g-flex-center-row" >
<span class="item-content-span g-flex-center-row custom-control custom-checkbox" v-for="(tagNode,index) in tag.childrenCategoryList" v-if="tagNode.childrenCategoryList.length==0" >
<input type="checkbox" class="custom-control-input" :checked="tagNode.isChecked">
<label class="custom-control-label" @click="delegateCheckedTag($event,tagNode,indexInTag)">{{tagNode.NAME}}</label>
</span>
<%--存在二级子标签--%>
<span class="item-content-span g-flex-center-row custom-control custom-checkbox" v-for="(tagNode,index) in tag.childrenCategoryList" v-if="tagNode.childrenCategoryList.length>0">
<input type="checkbox" class="custom-control-input" :checked="tagNode.isChecked" >
<label class="custom-control-label" @click="confirmAllTwoTag($event,tagNode,indexInTag,index)" >{{tagNode.NAME}}</label>
<i class="fa fa-angle-down" style="font-size:21px;color:#575b63" aria-hidden="true" @click="confirmTwoTag($event,tagNode,indexInTag)"></i>
</span>
</div>
<button class="btn btn-white g-btn item-content-btn"v-if="tag.COLUMN_TYPE==='0'" @click="showLongTaglist($event,tag,indexInTag)" style="display: block;">{{searchObj.LONG_TIPS}}
<i class="fa fa-angle-down" style="font-size:15px;color:#575b63" aria-hidden="true" ></i>
</button>
</div>
<%--一般标签结束--%>
</div>
<div class="main-header-more g-flex-center-row" v-if="searchObj.isShowMore">
<button class="btn g-btn btn-no-border" @click="showMoreTagList()">
更多标签
<svg id="headerDownArrow-more" class="bi bi-chevron-down" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg" style="transform: rotate(-180deg);">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" clip-rule="evenodd"></path>
</svg>
</button>
</div>
<div class="main-header-more g-flex-center-row" v-else>
<button class="btn g-btn btn-no-border" @click="showMoreTagList()">
更多标签
<svg id="headerDownArrow-more" class="bi bi-chevron-down" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" clip-rule="evenodd"></path>
</svg>
</button>
</div>
<div class="main-header-more g-flex-center-row" >
<div style="height: 1000px"></div>
</div>
</div>
</div>
<%--展开筛选内容--%>
<div class="main-header-ft g-flex-center">
<div class="search-list" v-show="searchObj.isShowSearchContent" style=" width:100%;height:140px;overflow:auto;overflow-x:hidden;" @scroll.passive="getScroll($event)">
<div v-for="(result,index) in searchObj.resultSearchList">
<div class="search-item g-flex-center">
<div class="search-item-hd g-margin-bottom-10 g-text-bold g-text-blue" v-html="result.TASK_NAME">
</div>
<div class="search-item-bd g-margin-bottom-5 g-text-bold" v-html="result.TASK_NAME">
</div>
<div class="search-item-ft g-flex-center-row">
<div class="search-item-ft-label">
<span class="g-text-label-gray">交办时间:</span>
<span class="g-text-black" v-html="result.REPLY_DATE"></span>
</div>
<div class="search-item-ft-label">
<span class="g-text-label-gray">办理状态:</span>
<span class="g-text-black" v-html="result.TASK_STATE_NAME"></span>
</div>
<div class="search-item-ft-label">
<span class="g-text-label-gray">责任领导:</span>
<span class="g-text-black" v-html="result.HINT_NAME"></span>
</div>
<div class="search-item-ft-label">
<span class="g-text-label-gray">责任单位:</span>
<span class="g-text-black" v-html="result.WORK_TYPE_NAME"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="main-mask" v-show="searchObj.isMask" >
</div>
</div>
</div>
</div>
js
const SEARCH_CONST={
/*快捷标签ID*/
QUICK_TAG_ID:"4",
/**标签类别ID*/
TAG_TYPE:"1",
/**二级标签ID*/
TWO_TAG_TYPE:"3",
/**二级标签样式名*/
TWO_TAG_CLASS:"fa fa-angle-up",
/**二级标签父标签状态*/
TWO_TAG_PARENT_STATUS:{
//全选中
ALL:2,
//没有完全选中
NOT_ALL:1,
//没有选中
NOT:0
},
/**全部*/
FULL_NAME:"全部",
FULL_TYPE:"-1",
/**搜索模型*/
QUERY_MODEL:{
/**
* 索引名称
*/
"SEARCH_FIELD":"",
/**
* 查询的值
*/
"NAME":"",
/**
* 高亮颜色
*/
"HIGHLIGHT_COLOR":""
},
/**选中模型*/
CHECKED_MODEL:{
},
/**关键字类型*/
KEYWORD_TYPE:"1",
SHOW_MODEL:{
FATHER_ID: "",
FATHER_NAME:"" ,
HIGHLIGHT_COLOR:"" ,
ID: "" ,
NAME: "" ,
ORDER_ID: "" ,
PREVIOUS_NAME: "" ,
QUICK_ID:"" ,
SEARCH_FIELD:"" ,
STATUS: "" ,
TASK_ID:"" ,
TITLE:"" ,
TYPE:"" ,
childrenCategoryList:[]
},
/**超长列*/
/**超长列的子列ID*/
LONG_COLUMN_TYPE_SON:"1",
/**超长列的第一列ID*/
LONG_COLUMN_TYPE_PARENT:"0",
/**超长列的总共多少个子列*/
LONG_COLUMN_TYPE_COUNT:0,
LONG_TIPS:{
MORE:"更多",
LESS:"收起"
}
}
Vue.filter('fmt', function (value,tag) {
var checkedLength=tag.CHECKED_ID.split(',').length;
console.log(checkedLength);
if (checkedLength===tag.OWEN_LENGTH){
return SEARCH_CONST.FULL_NAME;
}
if (value.substr(0, 1)==="、" ){
value=value.substr(1);
}
return value;
})
Vue.component('my-search',{
template:'#vue-template-search',
props: {
searchObj:{
type:Object,
defalut:{
//已选择标签
CHECKED_TAG_LIST:[],
//中转已选择标签
TEMP_CHECKED_TAG_LIST:[],
//处理过后的已选择标签
FILTER_CHECKED_TAG_LIST:[],
//快捷标签
QUICK_TAG_LIST:[],
//标签——操作数组
TAG_LIST:[],
//标签——源数组
TAG_FINAL_LIST:[],
//二级标签
TWO_TAG_LIST:[],
//是否显示标签
isShow:false,
//是否显示更多标签
isShowMore:false,
//二级标签ID
TWO_TAG_TYPE:"3",
//显示搜索内容
isShowSearchContent:false,
//关键字查询
keywordSearch:'',
//结果值
resultSearchList:[],
//查询条件
queryList:[],
//关键词查询条件
keywordList:[],
//当前条数
from:0,
//每次条数
size:2,
//业务ID
TASK_ID:"",
// 关键字搜索的字段名称 ,"REPLY_DATE"
KEYWORD_FIELDS:[],
//排序字段
ORDER_NAME:"",
//遮挡层
isMask:false,
//是否展示超长列
isNotShowMoreTag:true,
//显示的列数---需要根据超长列计算
tagListShowSize:4,
//实际的列数
tagListFactSize:4,
/**超长列的长度*/
LONG_COLUMN_TYPE_SIZE:5,
LONG_TIPS:"更多",
/**部门选择*/
DEPTLIST:{},
//牵头单位列表
LEADINGUNIT:[],
}
}
},
watch: {
'searchObj.CHECKED_TAG_LIST':function (newVal,oldVal) {
var temp = []; //一个新的临时数组
//去重处理
for(var i = 0; i < newVal.length; i++){
if(temp.indexOf(newVal[i]) == -1){
//优化显示
newVal[i].isShow=true;
temp.push(newVal[i]);
}
}
this.searchObj.FILTER_CHECKED_TAG_LIST=temp;
},
"searchObj.TEMP_CHECKED_TAG_LIST":function (newVal,oldVal) {
//父组件联动
this.handleTagChange();
}
},
mounted: function () {
//获取标签数据
this.getListSearchCategory();
},
methods: {
//搜索目录json
getListSearchCategory:function () {
var _this=this;
http.request("/search/listSearchCategory.vm?taskID="+_this.searchObj.TASK_ID,"",http.requestMethod.GET,function (categoryList) {
if (categoryList){
for (let i = 0; i <categoryList.length ; i++) {
if (categoryList[i].QUICK_ID){
for (let j = 0; j <categoryList[i].childrenCategoryList.length; j++) {
_this.searchObj.QUICK_TAG_LIST.push(categoryList[i].childrenCategoryList[j]);
}
}else{
for (let j = 0; j <categoryList[i].childrenCategoryList.length; j++) {
if (categoryList[i].childrenCategoryList[j].childrenCategoryList.length>_this.searchObj.LONG_COLUMN_TYPE_SIZE){
//如果元素超长 截取处理
var count=Math.ceil(categoryList[i].childrenCategoryList[j].childrenCategoryList.length/_this.searchObj.LONG_COLUMN_TYPE_SIZE);
_this.loadTagList(categoryList[i].childrenCategoryList[j],count);
}else{
_this.searchObj.TAG_LIST.push(categoryList[i].childrenCategoryList[j]);
_this.searchObj.TAG_FINAL_LIST.push(categoryList[i].childrenCategoryList[j]);
}
//组装二级菜单数组
_this.getTwoTagList(categoryList[i].childrenCategoryList[j]);
}
}
}
console.log(_this.searchObj.TAG_LIST)
}
});
},
loadTagList:function(tag,count){
SEARCH_CONST.LONG_COLUMN_TYPE_COUNT=count;
this.searchObj.tagListFactSize=this.searchObj.tagListShowSize+count;
for (let i = 0; i <count ; i++) {
var temp_tag= {
FATHER_ID: tag.FATHER_ID,
FATHER_NAME:tag.FATHER_NAME ,
HIGHLIGHT_COLOR:tag.HIGHLIGHT_COLOR,
ID: tag.ID ,
NAME: tag.NAME ,
ORDER_ID: tag.ORDER_ID ,
PREVIOUS_NAME: tag.PREVIOUS_NAME ,
QUICK_ID:tag.QUICK_ID ,
SEARCH_FIELD:tag.SEARCH_FIELD ,
STATUS: tag.STATUS ,
TASK_ID:tag.TASK_ID ,
TITLE:tag.TITLE ,
TYPE:tag.TYPE ,
childrenCategoryList:[]
};
if (i===0){
temp_tag.COLUMN_TYPE=SEARCH_CONST.LONG_COLUMN_TYPE_PARENT;
}else{
temp_tag.COLUMN_TYPE=SEARCH_CONST.LONG_COLUMN_TYPE_SON;
temp_tag.isLongListShow=this.searchObj.isNotShowMoreTag;
}
var tempFrom=i*this.searchObj.LONG_COLUMN_TYPE_SIZE===0?0:i*this.searchObj.LONG_COLUMN_TYPE_SIZE;
var tempSize=(i+1)*this.searchObj.LONG_COLUMN_TYPE_SIZE>tag.childrenCategoryList.length?tag.childrenCategoryList.length:(i+1)*this.searchObj.LONG_COLUMN_TYPE_SIZE;
for (let j =tempFrom ;
j <tempSize;
j++) {
temp_tag.childrenCategoryList.push(tag.childrenCategoryList[j])
}
this.searchObj.TAG_LIST.push(temp_tag);
this.searchObj.TAG_FINAL_LIST.push(temp_tag);
}
},
//寻找自己统计长度
findOwnerListLength:function(tag,FATERID){
if (tag.TYPE===SEARCH_CONST.TWO_TAG_TYPE){
for (let i = 0; i < this.searchObj.TAG_LIST.length; i++) {
for (let j = 0; j < this.searchObj.TAG_LIST[i].childrenCategoryList.length; j++) {
if (this.searchObj.TAG_LIST[i].childrenCategoryList[j].ID===FATERID){
return this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList.length;
}
}
}
}else {
console.log( this.searchObj.TAG_LIST);
for (let i = 0; i < this.searchObj.TAG_LIST.length; i++) {
if (this.searchObj.TAG_LIST[i].ID===FATERID){
return this.searchObj.TAG_LIST[i].childrenCategoryList.length;
}
}
}
},
//清空已选择标签
clearCheckedTag:function(tag,list){
if (!tag){
//全部清空
window.location.reload();
}else{
//删除指定标签
for (let i = 0; i <list.length ; i++) {
if (list[i]===tag){
list.splice(i,1);
}
}
}
},
//显示/隐藏标签
showTagList:function (event) {
var element=$(event.target);
if($(event.target).prop("tagName")==='BUTTON'){
//寻找他的子元素
element=element.find("I")
}
this.searchObj.isMask=false;
this.searchObj.isShow=!this.searchObj.isShow;
if (this.searchObj.isShow){
this.searchObj.isShowSearchContent=false;
}
this.changeFaFaStatus(this.searchObj.isShow,element);
},
changeFaFaStatus:function(flag,element){
if(flag){
element.attr("class","fa fa-angle-up");
}else{
element.attr("class","fa fa-angle-down");
}
},
//显示/隐藏标签
showMoreTagList:function () {
this.searchObj.isMask=false;
this.searchObj.isShowMore=!this.searchObj.isShowMore;
},
//选中标签
delegateCheckedTag:function (event,tag,index) {
if (tag.isChecked){
//消除标签
this.doDeleteTag(tag);
//判断是否为二级标签
if (tag.TYPE===SEARCH_CONST.TWO_TAG_TYPE){
var count=0;
for (let i = 0; i < this.searchObj.TAG_LIST[index].childrenCategoryList.length; i++) {
if(!this.searchObj.TAG_LIST[index].childrenCategoryList[i].isChecked){
count++;
}
}
//如果都取消---父标签状态改变NOT
//部分取消--父标签状态改变
var status;
if (count===this.searchObj.TAG_LIST[index].childrenCategoryList.length){
status=SEARCH_CONST.TWO_TAG_PARENT_STATUS.NOT;
}else{
status=SEARCH_CONST.TWO_TAG_PARENT_STATUS.NOT_ALL;
}
for (let i = 0; i < this.searchObj.TAG_LIST[index-1].childrenCategoryList.length; i++) {
if (tag.FATHER_ID===this.searchObj.TAG_LIST[index-1].childrenCategoryList[i].ID){
this.changeTwoTagParentStatus($(event.target),this.searchObj.TAG_LIST[index-1].childrenCategoryList[i],status)
}
}
}
}else{
this.doAddTag(tag);
if (tag.TYPE===SEARCH_CONST.TWO_TAG_TYPE){
var count=0;
for (let i = 0; i < this.searchObj.TAG_LIST[index].childrenCategoryList.length; i++) {
if(this.searchObj.TAG_LIST[index].childrenCategoryList[i].isChecked){
count++;
}
}
//如果都取消---父标签状态改变NOT
//部分取消--父标签状态改变
var status;
if (count===this.searchObj.TAG_LIST[index].childrenCategoryList.length){
status=SEARCH_CONST.TWO_TAG_PARENT_STATUS.ALL;
}else{
status=SEARCH_CONST.TWO_TAG_PARENT_STATUS.NOT;
}
for (let i = 0; i < this.searchObj.TAG_LIST[index-1].childrenCategoryList.length; i++) {
if (tag.FATHER_ID===this.searchObj.TAG_LIST[index-1].childrenCategoryList[i].ID){
this.changeTwoTagParentStatus($(event.target),this.searchObj.TAG_LIST[index-1].childrenCategoryList[i],status)
}
}
}
}
},
//获取二级菜单
getTwoTagList(tag){
if(tag.TYPE==this.searchObj.TWO_TAG_TYPE){
var temp={}
// temp.array=tag;
temp.FATHER_ID=tag.FATHER_ID;
this.searchObj.TWO_TAG_LIST.push(temp);
}
if (tag.childrenCategoryList){
for (let i = 0; i < tag.childrenCategoryList.length; i++) {
this.getTwoTagList(tag.childrenCategoryList[i]);
}
}
},
//判断二级菜单是否全部
getTimes(id,arr){
var times=0;
for(var i=0;i<arr.length;i++){
if(arr[i].FATHER_ID==id){
times++;//数组中有相同值就加容1
}
}
return times;
},
//选中二级标签
confirmTwoTag:function(event,tag,index){
this.searchObj.TAG_LIST=this.searchObj.TAG_FINAL_LIST;
var element=$(event.target);
var flag=false;
if (element.attr("class")!==SEARCH_CONST.TWO_TAG_CLASS){
//关闭二级标签
//标签样式修改
// element.attr("class","fa fa-angle-down");
for (let i = 0; i <element.parent().parent().find("i").length ; i++) {
this.changeFaFaStatus(flag,$(element.parent().parent().find("i")[i]));
// $(element.parent().parent().find("i")[i]).attr("class","fa fa-angle-down");
}
//开启二级标签
//标签样式修改
// element.attr("class","fa fa-angle-up");
flag=true;
//将二级菜单加入原标签数组
this.addTwoTagList( tag.childrenCategoryList,index);
}
this.changeFaFaStatus(flag,element);
},
//新增二级菜单
addTwoTagList:function (twoTagList,index) {
var newTag=[];
for (let i = 0; i < this.searchObj.TAG_LIST.length; i++) {
newTag.push(this.searchObj.TAG_LIST[i]);
//二级菜单所在位置
if (i ===index){
//新增一行
for (let j = 0; j < twoTagList.length; j++) {
twoTagList[j].isTwoTag=true;
}
var tag={
"childrenCategoryList":twoTagList
};
newTag.push(tag);
}
}
this.searchObj.TAG_LIST=newTag;
},
//选中该标签下面所有子标签
confirmAllTwoTag:function (event,tag,index,indexInTag) {
this.doConfirmTwoTagList($(event.target).next(),tag,index,indexInTag,this.unCheckedAllTwoTag,this.checkedAllTwoTag);
},
//取消所有二级标签
unCheckedAllTwoTag:function(tag,index,indexInTag){
// this.doDeleteTag(this.searchObj.TAG_LIST[index].childrenCategoryList[indexInTag]);
this.searchObj.TAG_LIST[index].childrenCategoryList[indexInTag].isChecked=false;
//还原状态
for (let i = 0; i < tag.childrenCategoryList.length; i++) {
this.doDeleteTag( tag.childrenCategoryList[i]);
}
},
//选中所有二级标签
checkedAllTwoTag:function(tag,index,indexInTag){
//父级选中
this.searchObj.TAG_LIST[index].childrenCategoryList[indexInTag].isChecked=true;
// this.doAddTag(this.searchObj.TAG_LIST[index].childrenCategoryList[indexInTag])
//二级选中
for (let i = 0; i <this.searchObj.TAG_LIST[index+1].childrenCategoryList.length ; i++) {
this.searchObj.TAG_LIST[index+1].childrenCategoryList[i].PREVIOUS_NAME=this.searchObj.TAG_LIST[index].childrenCategoryList[indexInTag].NAME;
this.doAddTag(this.searchObj.TAG_LIST[index+1].childrenCategoryList[i]);
}
},
//确认二级标签
doConfirmTwoTagList(element,tag,index,indexInTag,closeFunction,openFunction){
this.searchObj.TAG_LIST=this.searchObj.TAG_FINAL_LIST;
var flag=false;
if (element.attr("class")===SEARCH_CONST.TWO_TAG_CLASS||tag.isChecked){
//关闭二级标签
if (closeFunction)closeFunction(tag,index,indexInTag);
//标签样式修改
// element.attr("class","fa fa-angle-down");
}else{
for (let i = 0; i <element.parent().parent().find("i").length ; i++) {
$(element.parent().parent().find("i")[i]).attr("class","fa fa-angle-down");
}
//开启二级标签
//标签样式修改
// element.attr("class","fa fa-angle-up");
flag=true;
//将二级菜单加入原标签数组
this.addTwoTagList( tag.childrenCategoryList,index);
if (openFunction) openFunction(tag,index,indexInTag);
}
this.changeFaFaStatus(flag,element);
},
//二级标签父标签状态
changeTwoTagParentStatus(element,tag,status){
if (status===SEARCH_CONST.TWO_TAG_PARENT_STATUS.ALL){
tag.isChecked=true;
}else if (status===SEARCH_CONST.TWO_TAG_PARENT_STATUS.NOT){
tag.isChecked=false;
}else{
//未选择的中间状态
}
},
//添加标签
doAddTag(tag){
//选中标签
tag.isChecked=true;
//选中显示
//构建标签的选择模型
this.buildCheckModel(tag);
//构建标签的搜索模型
this.bulidQueryModel(tag);
this.searchObj.TEMP_CHECKED_TAG_LIST.push(tag);
},
bulidQueryModel:function(tag){
//如果含有二级标签那么将他所有子标签内容添加进去
var queryModel=SEARCH_CONST.QUERY_MODEL;
queryModel.SEARCH_FIELD=tag.SEARCH_FIELD;
queryModel.NAME=tag.NAME;
queryModel.HIGHLIGHT_COLOR=tag.HIGHLIGHT_COLOR;
queryModel.FATHER_ID = tag.FATHER_ID;
queryModel.CHECKED_ID=tag.ID;
for (let i = 0; i <this.searchObj.queryList.length ; i++) {
//如果查询字段相同进行拼接
if (this.searchObj.queryList[i].SEARCH_FIELD===tag.SEARCH_FIELD){
this.searchObj.queryList[i].NAME=this.searchObj.queryList[i].NAME+','+tag.NAME;
this.searchObj.queryList[i].CHECKED_ID=this.searchObj.queryList[i].CHECKED_ID+','+queryModel.CHECKED_ID;
return
}
}
//添加
this.searchObj.queryList.push(queryModel);
SEARCH_CONST.QUERY_MODEL={};
},
buildCheckModel:function(tag){
var checkedModel=SEARCH_CONST.CHECKED_MODEL;
checkedModel.SEARCH_FIELD=tag.SEARCH_FIELD;
checkedModel.NAME=tag.NAME;
checkedModel.ID = tag.ID;
checkedModel.FATHER_ID = tag.FATHER_ID;
if (tag.TYPE ===SEARCH_CONST.TWO_TAG_TYPE){
checkedModel.FATHER_NAME=tag.FATHER_NAME+"-"+tag.PREVIOUS_NAME;
}else {
checkedModel.FATHER_NAME=tag.FATHER_NAME;
}
checkedModel.TYPE=tag.TYPE;
checkedModel.CHECKED_ID=tag.ID;
checkedModel.CHECKED_NAME=tag.NAME;
checkedModel.PREVIOUS_NAME=tag.PREVIOUS_NAME;
for (let i = 0; i <this.searchObj.CHECKED_TAG_LIST.length ; i++) {
//如果查询字段相同进行拼接
if (this.searchObj.CHECKED_TAG_LIST[i].FATHER_ID===tag.FATHER_ID){
this.searchObj.CHECKED_TAG_LIST[i].NAME=this.searchObj.CHECKED_TAG_LIST[i].NAME+'、'+checkedModel.NAME;
this.searchObj.CHECKED_TAG_LIST[i].CHECKED_ID=this.searchObj.CHECKED_TAG_LIST[i].CHECKED_ID+','+checkedModel.CHECKED_ID;
this.searchObj.CHECKED_TAG_LIST[i].CHECKED_NAME=this.searchObj.CHECKED_TAG_LIST[i].CHECKED_NAME+','+checkedModel.NAME;
this.searchObj.CHECKED_TAG_LIST[i].OWEN_LENGTH=this.findOwnerListLength(tag,tag.FATHER_ID);
return
}
}
this.searchObj.CHECKED_TAG_LIST.push(checkedModel);
//添加
SEARCH_CONST.CHECKED_MODEL={};
},
//删除标签
doDeleteTag(tag){
this.clearCheckedTag(tag, this.searchObj.TEMP_CHECKED_TAG_LIST);
//取消标签
tag.isChecked=false;
//从已选标签中删除
// this.clearCheckedTag(tag, this.searchObj.CHECKED_TAG_LIST);
for (let i = 0; i <this.searchObj.CHECKED_TAG_LIST.length ; i++) {
//如果查询字段相同进行去除
if (this.searchObj.CHECKED_TAG_LIST[i].FATHER_ID===tag.FATHER_ID){
this.searchObj.CHECKED_TAG_LIST[i].NAME=this.searchObj.CHECKED_TAG_LIST[i].NAME.replace("、"+tag.NAME,"");
this.searchObj.CHECKED_TAG_LIST[i].NAME=this.searchObj.CHECKED_TAG_LIST[i].NAME.replace(tag.NAME,"");
}
if (!this.searchObj.CHECKED_TAG_LIST[i].NAME){
this.searchObj.CHECKED_TAG_LIST.splice(i, 1);
}
}
for (let i = 0; i <this.searchObj.queryList.length ; i++) {
//如果查询字段相同进行去除
if (this.searchObj.queryList[i].SEARCH_FIELD===tag.SEARCH_FIELD){
this.searchObj.queryList[i].NAME=this.searchObj.queryList[i].NAME.replace(","+tag.NAME,"");
this.searchObj.queryList[i].NAME=this.searchObj.queryList[i].NAME.replace(tag.NAME,"");
}
if (!this.searchObj.queryList[i].NAME){
this.searchObj.queryList.splice(i, 1);
return;
}
}
},
//快捷标签选择
confirmQuickTag:function (tag) {
console.log(tag);
for (let i = 0; i <this.searchObj.TAG_LIST.length ; i++) {
for (let j = 0; j < this.searchObj.TAG_LIST[i].childrenCategoryList.length; j++) {
if (this.searchObj.TAG_LIST[i].childrenCategoryList[j].ID===tag.ID){
//标签属于二级标签父标签
this.recursiveTag(this.searchObj.TAG_LIST[i].childrenCategoryList[j]);
return
}
if (this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList){
//二级菜单选择
for (let k = 0; k < this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList.length; k++) {
if (this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList[k].ID===tag.ID){
this.recursiveTag(this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList[k]);
return
}
}
}
}
}
},
//设置每层的属性
recursiveTag:function (tag) {
if (!tag.isChecked){
this.doAddTag(tag);
}else{
this.doDeleteTag(tag);
}
if (tag.childrenCategoryList){
for (let i = 0; i <tag.childrenCategoryList.length ; i++) {
this.recursiveTag(tag.childrenCategoryList[i]);
}
}
},
unCheckedTag:function (tag) {
//展示内容修改
for (let i = 0; i <this.searchObj.CHECKED_TAG_LIST.length ; i++) {
//如果查询字段相同进行去除
if (this.searchObj.CHECKED_TAG_LIST[i].FATHER_ID===tag.FATHER_ID){
this.searchObj.CHECKED_TAG_LIST.splice(i, 1);
}
}
//选中状态修改
if (tag.TYPE===SEARCH_CONST.TWO_TAG_TYPE){
for (let i = 0; i < this.searchObj.TAG_LIST.length; i++) {
for (let j = 0; j <this.searchObj.TAG_LIST[i].childrenCategoryList.length ; j++) {
if (tag.FATHER_ID===this.searchObj.TAG_LIST[i].childrenCategoryList[j].ID){
this.searchObj.TAG_LIST[i].childrenCategoryList[j].isChecked=false;
for (let k = 0; k < this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList.length; k++) {
this.searchObj.TAG_LIST[i].childrenCategoryList[j].childrenCategoryList[k].isChecked=false;
}
}
if (tag.FATHER_ID===this.searchObj.TAG_LIST[i].childrenCategoryList[j].FATHER_ID){
this.searchObj.TAG_LIST[i].childrenCategoryList[j].isChecked=false;
}
}
}
}else{
var checkedList=tag.CHECKED_ID.split(',');
for (let i = 0; i <checkedList.length ; i++) {
//遍历整个数组将ID为
for (let j = 0; j <this.searchObj.TAG_LIST.length ; j++) {
this.unCheckedTagForID(this.searchObj.TAG_LIST[j],checkedList[i]);
}
}
}
var checkedList=tag.CHECKED_ID.split(',');
for (let i = 0; i <checkedList.length ; i++) {
for (let j = 0; j < this.searchObj.TEMP_CHECKED_TAG_LIST.length; j++) {
if (this.searchObj.TEMP_CHECKED_TAG_LIST[j].ID===checkedList[i]){
this.doDeleteTag(this.searchObj.TEMP_CHECKED_TAG_LIST[j]);
}
}
}
},
unCheckedTagForID:function(tag,ID){
if (tag.ID===ID){
tag.isChecked=false;
}
if (tag.childrenCategoryList.length>0){
for (let i = 0; i <tag.childrenCategoryList.length ; i++) {
this.unCheckedTagForID(tag.childrenCategoryList[i],ID);
}
}
},
//数组去重
disctinctArrayObject:function (obj) {
var uniques = [];
var stringify = {};
for (var i = 0; i < obj.length; i++) {
var keys = Object.keys(obj[i]);
keys.sort(function(a, b) {
return (Number(a) - Number(b));
});
var str = '';
for (var j = 0; j < keys.length; j++) {
str += JSON.stringify(keys[j]);
str += JSON.stringify(obj[i][keys[j]]);
}
if (!stringify.hasOwnProperty(str)) {
uniques.push(obj[i]);
stringify[str] = true;
}
}
uniques = uniques;
return uniques;
},
//提交搜索内容
submitSearch(){
this.searchObj.isMask=true;
//关闭搜索条件详情
this.searchObj.isShow=false;
//置空上一次的起始页
this.searchObj.from=0;
//显示搜索内容
this.searchObj.isShowSearchContent=true;
//判断是否已选择标签
this.searchObj.keywordList=[];
console.log(this.searchObj.queryList);
//组装搜索条件
this.assemblyQuery(this.searchObj.keywordList);
var _this=this;
for (let i = 0; i < this.searchObj.queryList.length; i++) {
this.searchObj.keywordList.push(this.searchObj.queryList[i]);
}
http.request("/search/queryByMatch.vm?from=0&orderFiled="+this.searchObj.ORDER_NAME,JSON.stringify(this.searchObj.keywordList),http.requestMethod.POST,function (resultList) {
_this.searchObj.resultSearchList=resultList;
})
},
//组装关键词的搜索条件
assemblyQuery:function (keywordList) {
if (this.searchObj.keywordSearch!==""&&this.searchObj.keywordSearch!=null){
for (let i = 0; i <this.searchObj.KEYWORD_FIELDS.length ; i++) {
var queryModel={};
queryModel.SEARCH_FIELD=this.searchObj.KEYWORD_FIELDS[i];
queryModel.NAME=this.searchObj.keywordSearch;
queryModel.FILED_TYPE=SEARCH_CONST.KEYWORD_TYPE;
keywordList.push(queryModel);
}
}
},
getScroll(event) {
var _this=this;
// 滚动条距离底部的距离scrollBottom
let scrollBottom =
event.target.scrollHeight -
event.target.scrollTop -
event.target.clientHeight;
if (scrollBottom < 1) {
this.searchObj.from=this.searchObj.from+this.searchObj.size;
http.request("/search/queryByMatch.vm?from="+this.searchObj.from+"&orderFiled="+this.searchObj.ORDER_NAME,JSON.stringify(this.searchObj.keywordList),http.requestMethod.POST,function (resultList) {
for (let i = 0; i < resultList.length; i++) {
_this.searchObj.resultSearchList.push(resultList[i])
}
})
}
},
//选择标签与父页面联动
handleTagChange:function () {
this.$emit('handletagchange',this.searchObj.queryList)
},
//显示超长列
showLongTaglist:function (event,tag,index) {
var element=$(event.target);
if($(event.target).prop("tagName")==='BUTTON'){
//寻找他的子元素
element=element.find("I")
}
this.changeFaFaStatus(this.searchObj.isNotShowMoreTag,element);
this.searchObj.isNotShowMoreTag=!this.searchObj.isNotShowMoreTag;
if (this.searchObj.isNotShowMoreTag){
this.searchObj.LONG_TIPS=SEARCH_CONST.LONG_TIPS.MORE;
}else{
this.searchObj.LONG_TIPS=SEARCH_CONST.LONG_TIPS.LESS;
}
console.log(SEARCH_CONST.LONG_COLUMN_TYPE_COUNT);
for (let i = 1; i <SEARCH_CONST.LONG_COLUMN_TYPE_COUNT; i++) {
this.searchObj.TAG_LIST[index+i].isLongListShow=this.searchObj.isNotShowMoreTag;
}
},
deptSelect:function(dataname){
var _this = this;
layui.use('layer', function () {
var layer = layui.layer;
layer.open({
type: 2,
title: '部门选择',
shadeClose: true,
shade: 0.8,
area: ['800px','500px'],
offset: ['150px'],
content:ctx+'/select/deptInfo.vm?DEPTCODE=8'
,success: function(layero, index){
_this.searchObj.DEPTLIST=_this.searchObj[dataname][0];
}
,end: function(){
//_this.LEADINGUNIT[i]=_this.DEPTLIST;
// _this.searchObj[dataname][0].DEPT_CODE=_this.searchObj.DEPTLIST.DEPT_CODE;
// _this.searchObj[dataname][0].DEPT_NAME=_this.searchObj.DEPTLIST.DEPT_NAME;
// _this.searchObj[dataname][0].LEADER_NAME=_this.searchObj.DEPTLIST.LEADER_NAME;
// _this.searchObj[dataname][0].CHIEF_NAME=_this.searchObj.DEPTLIST.CHIEF_NAME;
}
});
});
},
}
})