Commit a8c35e7a by guojx

流失数据概览

parent d3a07f39
package com.gic.haoban.manage.web.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.Page;
import com.gic.commons.util.DataApiUtils;
import com.gic.commons.util.DateUtil;
import com.gic.commons.webapi.reponse.RestResponse;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.dto.StoreSearchDTO;
import com.gic.enterprise.api.service.StoreGroupService;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.base.api.common.pojo.dto.WebLoginDTO;
import com.gic.haoban.common.utils.AuthWebRequestUtil;
import com.gic.haoban.manage.api.service.StaffApiService;
import com.gic.haoban.manage.web.qo.wechatwork.StoreCommonQO;
import com.gic.haoban.manage.web.qo.wechatwork.WechatWorkLostOverviewQO;
import com.gic.haoban.manage.web.utils.data.ConcurrencyUtils;
import com.gic.haoban.manage.web.utils.data.MapThreadHandlerRequest;
import com.gic.haoban.manage.web.vo.wechatwork.WechatWorkLostVO;
import com.gic.web.common.controller.NewBaseController;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 企微流失接口
* @Author guojx
* @Date 2024/5/21 13:45
*/
@RestController("wechat-work")
@Slf4j
public class WechatWorkController extends NewBaseController {
@Autowired
private StoreGroupService storeGroupService;
@Autowired
private StaffApiService staffApiService;
@Autowired
private StoreService storeService;
/**
* 流失数据概览
* @param qo
* @return
*/
@RequestMapping(value = "lost-overview")
public RestResponse<WechatWorkLostVO> lostOverview(@RequestBody WechatWorkLostOverviewQO qo) {
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(qo);
setCommonParam(jsonObject, qo);
Map<String, Object> res = DataApiUtils.http(jsonObject.toJSONString(), "data_mbr_scale_haoban_background_loss");
List<JSONObject> list = DataApiUtils.getDataList(res);
List<WechatWorkLostVO> voList = JSONArray.parseArray(JSON.toJSONString(list), WechatWorkLostVO.class);
return RestResponse.successResult(CollectionUtils.isEmpty(voList) ? null : voList.get(0));
}
/**
* 流失数据概览趋势图
* @param qo
* @return
* @throws ParseException
*/
@RequestMapping(value = "lost-overview-trend")
public RestResponse<List<WechatWorkLostVO>> lostOverviewTrend(@RequestBody WechatWorkLostOverviewQO qo) throws ParseException {
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(qo);
setCommonParam(jsonObject, qo);
List<MapThreadHandlerRequest> list = new ArrayList<>();
jsonObject.put("groupType", 1);
list.add(new MapThreadHandlerRequest(jsonObject, "data_mbr_scale_haoban_background_loss_date", "1_onewayFriendNum"));
jsonObject.put("groupType", 2);
list.add(new MapThreadHandlerRequest(jsonObject, "data_mbr_scale_haoban_background_loss_date", "2_totalLostNum"));
jsonObject.put("groupType", 3);
list.add(new MapThreadHandlerRequest(jsonObject, "data_mbr_scale_haoban_background_loss_date", "3_deleteSalesNum"));
jsonObject.put("groupType", 4);
list.add(new MapThreadHandlerRequest(jsonObject, "data_mbr_scale_haoban_background_loss_date", "4_salesDeleteNum"));
Map<String, List<JSONObject>> map = ConcurrencyUtils.concurrencyDataForMap(list);
List<JSONObject> resultList = new ArrayList<>();
if (map != null) {
map.forEach((k, v) -> {
if (CollectionUtils.isNotEmpty(v)) {
for (JSONObject tempJson : v) {
tempJson.put(k.substring(0, 1), tempJson.get(k.substring(2)));
}
resultList.addAll(v);
}
});
}
Map<String, List<JSONObject>> voMap = resultList.stream().collect(Collectors.groupingBy(e -> e.getString("bizDate")));
List<String> dateList = DateUtil.getBetweenDates(qo.getStartDate(), qo.getEndDate());
List<WechatWorkLostVO> voList = new ArrayList<>();
for (String date : dateList) {
WechatWorkLostVO vo = new WechatWorkLostVO();
vo.setBizDate(date);
List<JSONObject> mapValue = voMap.get(date);
if (CollectionUtils.isNotEmpty(mapValue)) {
for (JSONObject tempJson : mapValue) {
vo.setOnewayFriendNum(tempJson.getInteger("1"));
vo.setTotalLostNum(tempJson.getInteger("2"));
vo.setDeleteSalesNum(tempJson.getInteger("3"));
vo.setSalesDeleteNum(tempJson.getInteger("4"));
}
}
voList.add(vo);
}
return RestResponse.successResult(voList);
}
private void setCommonParam(JSONObject jsonObject, StoreCommonQO storeCommonQO) {
List<String> storeIds = getAuthStoreId(storeCommonQO);
if (CollectionUtils.isNotEmpty(storeIds)) {
jsonObject.put("storeId", storeIds);
}
WebLoginDTO login = AuthWebRequestUtil.getLoginUser();
jsonObject.put("enterpriseId", login.getEnterpriseId());
}
private List<String> getAuthStoreId(StoreCommonQO storeCommonQO) {
String storeGroupId = storeCommonQO.getStoreGroupId();
String storeSearchParam = storeCommonQO.getStoreSearchParam();
String storeId = storeCommonQO.getStoreId();
WebLoginDTO login = AuthWebRequestUtil.getLoginUser();
List<String> roleStoreIds = staffApiService.getHaoBanStoreIdsRolesByClerkId(login.getClerkId(), login.getWxEnterpriseId());
if (CollectionUtils.isEmpty(roleStoreIds)) {
log.info("登录人无门店权限");
return getNoExistStore();
}
if(StringUtils.isNotBlank(storeGroupId) || StringUtils.isNotBlank(storeSearchParam)) {
StoreSearchDTO storeSearch = new StoreSearchDTO();
storeSearch.setEnterpriseId(login.getEnterpriseId());
if (StringUtils.isNotBlank(storeGroupId)) {
List<String> storeGroupIds = Arrays.stream(storeGroupId.split(",")).collect(Collectors.toList());
List<String> groupIds = storeGroupService.getStoreGroupIdsByParentGroupId(login.getEnterpriseId(), storeGroupIds);
storeSearch.setStoreGroupIdList(groupIds);
}
if (StringUtils.isNotBlank(storeSearchParam)) {
storeSearch.setSearchName(storeSearchParam);
}
Page pageStore = new Page<>();
//-1代表不分页
pageStore.setCurrentPage(-1);
Page resultPage = storeService.storeListPage(pageStore, storeSearch);
List<StoreDTO> storeDTOList = resultPage.getResult();
if (CollectionUtils.isEmpty(storeDTOList)) {
return getNoExistStore();
}
List<String> searchStoreIdList = storeDTOList.stream().map(e -> e.getStoreId()).collect(Collectors.toList());
if (isAllAuth(roleStoreIds)) {
return searchStoreIdList;
}
//交集
roleStoreIds.retainAll(searchStoreIdList);
if (CollectionUtils.isEmpty(roleStoreIds)) {
return getNoExistStore();
}
}
if (StringUtils.isNotBlank(storeId)) {
List<String> ids = Arrays.stream(storeId.split(",")).collect(Collectors.toList());
roleStoreIds.retainAll(ids);
if (CollectionUtils.isEmpty(roleStoreIds)) {
return getNoExistStore();
}
}
return roleStoreIds;
}
private static boolean isAllAuth(List<String> roleStoreIds) {
return roleStoreIds.size() == 1 && "-1".equals(roleStoreIds.get(0));
}
private static List<String> getNoExistStore() {
List<String> list = new ArrayList<>(1);
list.add("no_exist_store_id");
return list;
}
}
......@@ -169,4 +169,11 @@ public class GlobalExceptionHandler extends WebBaseController {
return RestResponse.failure(ex.getCode(), ex.getMessage());
}
@ResponseBody
@ExceptionHandler(com.gic.commons.exception.DataApiException.class)
public RestResponse dataApiExceptionCommon(HttpServletResponse response, com.gic.commons.exception.DataApiException ex) {
logger.info("DataApiException common异常信息:{}", ex);
return RestResponse.failure(ex.getCode(), ex.getMessage());
}
}
package com.gic.haoban.manage.web.qo.wechatwork;
import lombok.Data;
import java.io.Serializable;
/**
* @Author guojx
* @Date 2024/5/21 15:43
*/
@Data
public class StoreCommonQO implements Serializable {
/**
* 分组ID,支持多选,英文逗号隔开
*/
private String storeGroupId;
/**
* 门店code/名称
*/
private String storeSearchParam;
/**
* 门店ID
*/
private String storeId;
}
package com.gic.haoban.manage.web.qo.wechatwork;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serializable;
/**
* @Author guojx
* @Date 2024/5/21 14:12
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class WechatWorkLostOverviewQO extends StoreCommonQO implements Serializable {
/**
* yyyy-MM-dd
*/
private String startDate;
/**
* yyyy-MM-dd
*/
private String endDate;
}
package com.gic.haoban.manage.web.utils.data;
import com.alibaba.fastjson.JSONObject;
import com.gic.dubbo.entity.ProviderLocalTag;
import com.gic.web.common.utils.ExecutorPoolSingleton;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
/**
* @Author guojx
* @Date 2024/1/12 13:41
*/
@Slf4j
public class ConcurrencyUtils {
public static Map<String, List<JSONObject>> concurrencyDataForMap(List<MapThreadHandlerRequest> list) {
Map<String, List<JSONObject>> resultMap = new HashMap<>();
if (CollectionUtils.isEmpty(list)) {
return resultMap;
}
ProviderLocalTag providerLocalTag = ProviderLocalTag.tag.get();
String traceId = providerLocalTag.traceId;
for (MapThreadHandlerRequest temp : list) {
temp.setTraceId(traceId);
}
long startTime = System.currentTimeMillis();
try {
List<Future<Map<String, List<JSONObject>>>> futures2 = ExecutorPoolSingleton.getInstance().getExecutorService().invokeAll(list);
log.info("调用API耗时 : " + (System.currentTimeMillis() - startTime));
for (Future<Map<String, List<JSONObject>>> future : futures2) {
try {
Map<String, List<JSONObject>> map = future.get();
if (map != null) {
map.forEach((k, v) -> {
resultMap.put(k, v);
});
}
} catch (Exception e) {
log.warn("remote Api failed : {}", e.getCause().getMessage());
}
}
long endTime = System.currentTimeMillis();
log.info("耗时 : " + (endTime - startTime));
} catch (Exception e) {
log.warn("并发调用错误:{}", e.getMessage(), e);
}
return resultMap;
}
public static List<JSONObject> concurrencyData(List<ThreadHandlerRequest> list) {
List<JSONObject> resultList = new ArrayList<>();
if (CollectionUtils.isEmpty(list)) {
return resultList;
}
List<MapThreadHandlerRequest> mapParam = new ArrayList<>();
for (int i = 0, len = list.size(); i < len; i++) {
MapThreadHandlerRequest res = new MapThreadHandlerRequest(list.get(i).getJsonObject(),
list.get(i).getApolloKey(), "data" + i);
mapParam.add(res);
}
Map<String, List<JSONObject>> map = concurrencyDataForMap(mapParam);
if (map != null) {
map.forEach((k, v) -> {
if (CollectionUtils.isNotEmpty(v)) {
resultList.addAll(v);
}
});
}
return resultList;
}
}
package com.gic.haoban.manage.web.utils.data;
import com.alibaba.fastjson.JSONObject;
import com.gic.commons.exception.DataApiException;
import com.gic.commons.util.DataApiUtils;
import com.gic.dubbo.entity.ProviderLocalTag;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* @Author guojx
* @Date 2024/1/11 15:33
*/
@Slf4j
public class MapThreadHandlerRequest implements Callable<Map<String, List<JSONObject>>> {
private JSONObject jsonObject;
private String apolloKey;
private String webObjName;
private String traceId;
public MapThreadHandlerRequest(JSONObject jsonObject, String apolloKey, String webObjName) {
this.jsonObject = JSONObject.parseObject(jsonObject.toJSONString());
this.apolloKey = apolloKey;
this.webObjName = webObjName;
}
@Override
public Map<String, List<JSONObject>> call() throws Exception {
try {
//log.info("并发调用入口:{}-{}", apolloKey, webObjName);
ProviderLocalTag providerLocalTag = ProviderLocalTag.tag.get();
providerLocalTag.traceId = traceId;
Map<String, Object> res = DataApiUtils.http(jsonObject.toJSONString(), apolloKey);
List<JSONObject> list = DataApiUtils.getDataList(res);
Map<String, List<JSONObject>> map = new HashMap<>(2);
map.put(webObjName, list);
return map;
} catch (DataApiException e) {
// if (DataApiException.OVER_HANDLE_ERROR.equals(e.getCode())) {
// throw new DataApiException(e.getCode(), e.getMessage());
// }
log.info("{}调用错误:{}", apolloKey, e.getMessage(), e);
} catch (Exception e) {
log.info("{}调用错误:{}", apolloKey, e.getMessage(), e);
}
return null;
}
public String getTraceId() {
return traceId;
}
public MapThreadHandlerRequest setTraceId(String traceId) {
this.traceId = traceId;
return this;
}
}
package com.gic.haoban.manage.web.utils.data;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
/**
* @Author guojx
* @Date 2024/1/11 15:33
*/
@Slf4j
public class ThreadHandlerRequest {
private JSONObject jsonObject;
private String apolloKey;
public ThreadHandlerRequest(JSONObject jsonObject, String apolloKey) {
this.jsonObject = JSONObject.parseObject(jsonObject.toJSONString());
this.apolloKey = apolloKey;
}
public JSONObject getJsonObject() {
return jsonObject;
}
public ThreadHandlerRequest setJsonObject(JSONObject jsonObject) {
this.jsonObject = jsonObject;
return this;
}
public String getApolloKey() {
return apolloKey;
}
public ThreadHandlerRequest setApolloKey(String apolloKey) {
this.apolloKey = apolloKey;
return this;
}
}
package com.gic.haoban.manage.web.vo.wechatwork;
import lombok.Data;
import java.io.Serializable;
/**
* @Author guojx
* @Date 2024/5/21 15:56
*/
@Data
public class WechatWorkLostVO implements Serializable {
/**
* 单向好友数
*/
private Integer onewayFriendNum = 0;
/**
* 总流失人数
*/
private Integer totalLostNum = 0;
/**
* 删除导购人数
*/
private Integer deleteSalesNum = 0;
/**
* 导购删除好友人数
*/
private Integer salesDeleteNum = 0;
/**
*
*/
private String bizDate;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment