From 9621b2366364bed8d52625b82fdd5258428f5668 Mon Sep 17 00:00:00 2001 From: wangxianzhang Date: Tue, 2 Nov 2021 10:27:52 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=EF=BC=9A=20=E5=AF=BC?= =?UTF-8?q?=E5=85=A5excel=E5=B1=85=E6=B0=91=E4=BF=A1=E6=81=AF=EF=BC=88?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../epmet/dto/form/CustomerFormQueryDTO.java | 5 +- .../java/com/epmet/dto/result/FormItem.java | 10 + .../feign/OperCustomizeOpenFeignClient.java | 16 +- .../OperCustomizeOpenFeignClientFallback.java | 10 +- .../epmet/controller/IcFormController.java | 21 +- .../main/java/com/epmet/dao/IcFormDao.java | 10 + .../java/com/epmet/service/IcFormService.java | 12 + .../epmet/service/impl/IcFormServiceImpl.java | 15 + .../src/main/resources/mapper/IcFormDao.xml | 29 ++ epmet-user/epmet-user-server/pom.xml | 5 + .../controller/IcResiUserController.java | 6 + .../handler/DynamicEasyExcelListener.java | 73 ++++ .../handler/IcResiExcelImportHandler.java | 12 + .../com/epmet/service/IcResiUserService.java | 1 + .../service/impl/IcResiUserServiceImpl.java | 311 +++++++++++++++++- 15 files changed, 518 insertions(+), 18 deletions(-) create mode 100644 epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/DynamicEasyExcelListener.java create mode 100644 epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcResiExcelImportHandler.java diff --git a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/form/CustomerFormQueryDTO.java b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/form/CustomerFormQueryDTO.java index 55e1160110..8759909f38 100644 --- a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/form/CustomerFormQueryDTO.java +++ b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/form/CustomerFormQueryDTO.java @@ -13,7 +13,10 @@ import java.io.Serializable; @Data public class CustomerFormQueryDTO implements Serializable { public interface AddUserInternalGroup {} - @NotBlank(message = "formCode不能为空,居民信息默认传:resi_base_info",groups =AddUserInternalGroup.class ) + // 获取表单相关信息 + public interface GetFormInfoGroup {} + + @NotBlank(message = "formCode不能为空,居民信息默认传:resi_base_info",groups = { AddUserInternalGroup.class, GetFormInfoGroup.class} ) private String formCode; diff --git a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/result/FormItem.java b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/result/FormItem.java index 552ddbe880..7e3abbaa0e 100644 --- a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/result/FormItem.java +++ b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/dto/result/FormItem.java @@ -120,5 +120,15 @@ public class FormItem implements Serializable { * 1可以多选,0单选,默认0 */ private Boolean multiSelect; + + /** + * @description 分组label + * + * @param null + * @return + * @author wxz + * @date 2021.10.28 22:57:15 + */ + private String groupLabel; } diff --git a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/OperCustomizeOpenFeignClient.java b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/OperCustomizeOpenFeignClient.java index 5a02a97f13..58def540a4 100644 --- a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/OperCustomizeOpenFeignClient.java +++ b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/OperCustomizeOpenFeignClient.java @@ -7,10 +7,7 @@ import com.epmet.dto.form.CheckFloatFootBarFormDTO; import com.epmet.dto.form.CustomerFootBarFormDTO; import com.epmet.dto.form.CustomerFormQueryDTO; import com.epmet.dto.form.CustomerFunctionListFormDTO; -import com.epmet.dto.result.CheckFloatFootBarResultDTO; -import com.epmet.dto.result.CustomerFormResultDTO; -import com.epmet.dto.result.DefaultFunctionListResultDTO; -import com.epmet.dto.result.IcFormResColumnDTO; +import com.epmet.dto.result.*; import com.epmet.feign.fallback.OperCustomizeOpenFeignClientFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; @@ -80,4 +77,15 @@ public interface OperCustomizeOpenFeignClient { @PostMapping(value = "/oper/customize/icform/queryIcResiSubTables", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) Result> queryIcResiSubTables(@RequestBody CustomerFormQueryDTO queryDTO); + + /** + * @description item列表 + * + * @param formDto + * @return + * @author wxz + * @date 2021.10.28 15:19:59 + */ + @PostMapping("/oper/customize/icform/items") + Result> listItems(@RequestBody CustomerFormQueryDTO formDto); } diff --git a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/fallback/OperCustomizeOpenFeignClientFallback.java b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/fallback/OperCustomizeOpenFeignClientFallback.java index 8a300aeb19..2420adb817 100644 --- a/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/fallback/OperCustomizeOpenFeignClientFallback.java +++ b/epmet-module/oper-customize/oper-customize-client/src/main/java/com/epmet/feign/fallback/OperCustomizeOpenFeignClientFallback.java @@ -8,10 +8,7 @@ import com.epmet.dto.form.CheckFloatFootBarFormDTO; import com.epmet.dto.form.CustomerFootBarFormDTO; import com.epmet.dto.form.CustomerFormQueryDTO; import com.epmet.dto.form.CustomerFunctionListFormDTO; -import com.epmet.dto.result.CheckFloatFootBarResultDTO; -import com.epmet.dto.result.CustomerFormResultDTO; -import com.epmet.dto.result.DefaultFunctionListResultDTO; -import com.epmet.dto.result.IcFormResColumnDTO; +import com.epmet.dto.result.*; import com.epmet.feign.OperCustomizeOpenFeignClient; import java.util.List; @@ -72,4 +69,9 @@ public class OperCustomizeOpenFeignClientFallback implements OperCustomizeOpenFe public Result> queryIcResiSubTables(CustomerFormQueryDTO queryDTO) { return ModuleUtils.feignConError(ServiceConstant.OPER_CUSTOMIZE_SERVER, "queryIcResiSubTables", queryDTO); } + + @Override + public Result> listItems(CustomerFormQueryDTO formDto) { + return ModuleUtils.feignConError(ServiceConstant.OPER_CUSTOMIZE_SERVER, "listItems", formDto); + } } diff --git a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/controller/IcFormController.java b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/controller/IcFormController.java index 5443b382a8..8c506cfe74 100644 --- a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/controller/IcFormController.java +++ b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/controller/IcFormController.java @@ -29,10 +29,7 @@ import com.epmet.commons.tools.validator.group.DefaultGroup; import com.epmet.commons.tools.validator.group.UpdateGroup; import com.epmet.dto.IcFormDTO; import com.epmet.dto.form.CustomerFormQueryDTO; -import com.epmet.dto.result.ConditionResultDTO; -import com.epmet.dto.result.CustomerFormResultDTO; -import com.epmet.dto.result.IcFormResColumnDTO; -import com.epmet.dto.result.TableHeaderResultDTO; +import com.epmet.dto.result.*; import com.epmet.excel.IcFormExcel; import com.epmet.service.IcFormItemService; import com.epmet.service.IcFormService; @@ -179,4 +176,20 @@ public class IcFormController { ValidatorUtils.validateEntity(queryDTO,CustomerFormQueryDTO.AddUserInternalGroup.class); return new Result>().ok(icFormItemService.queryIcResiSubTables(queryDTO.getCustomerId(),queryDTO.getFormCode())); } + + /** + * @description item列表 + * + * @param tokenDto + * @param formDto + * @return + * @author wxz + * @date 2021.10.28 15:19:59 + */ + @PostMapping("items") + public Result> listItems(@LoginUser TokenDto tokenDto, @RequestBody CustomerFormQueryDTO formDto) { + ValidatorUtils.validateEntity(formDto, CustomerFormQueryDTO.GetFormInfoGroup.class); + List rst = icFormService.listItems(tokenDto.getCustomerId(), formDto.getFormCode()); + return new Result>().ok(rst); + } } diff --git a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/dao/IcFormDao.java b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/dao/IcFormDao.java index 846e59ad72..6cd4fa7188 100644 --- a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/dao/IcFormDao.java +++ b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/dao/IcFormDao.java @@ -55,4 +55,14 @@ public interface IcFormDao extends BaseDao { List selectListGroup(String formId); FormGroupDTO selectChildGroup(String itemId); + + /** + * @description 通用查询item列表,无固定条件 + * + * @param formId + * @return + * @author wxz + * @date 2021.10.28 16:43:00 + */ + List listItems(@Param("formId") String formId); } diff --git a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/IcFormService.java b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/IcFormService.java index 08ae71841b..b1d0dddaf1 100644 --- a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/IcFormService.java +++ b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/IcFormService.java @@ -22,6 +22,7 @@ import com.epmet.commons.tools.page.PageData; import com.epmet.dto.IcFormDTO; import com.epmet.dto.form.CustomerFormQueryDTO; import com.epmet.dto.result.CustomerFormResultDTO; +import com.epmet.dto.result.FormItem; import com.epmet.entity.IcFormEntity; import java.util.List; @@ -104,4 +105,15 @@ public interface IcFormService extends BaseService { * @date 2021/10/26 2:41 下午 */ CustomerFormResultDTO getCustomerForm(CustomerFormQueryDTO formDto); + + /** + * @description 查询item列表 + * + * @param customerId + * @param formCode + * @return + * @author wxz + * @date 2021.10.27 17:41:59 + */ + List listItems(String customerId, String formCode); } \ No newline at end of file diff --git a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/impl/IcFormServiceImpl.java b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/impl/IcFormServiceImpl.java index f7cf1fe235..23088c3024 100644 --- a/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/impl/IcFormServiceImpl.java +++ b/epmet-module/oper-customize/oper-customize-server/src/main/java/com/epmet/service/impl/IcFormServiceImpl.java @@ -131,4 +131,19 @@ public class IcFormServiceImpl extends BaseServiceImpl customerFootBarRedis.setCustomerFormResultDTO(formDto.getFormCode(),formDto.getCustomerId(),resultDTO); return resultDTO; } + + @Override + public List listItems(String customerId, String formCode) { + CustomerFormResultDTO formResultDto=baseDao.selectByCode(customerId, formCode); + if (null == formResultDto) { + throw new RenException(EpmetErrorCode.CUSTOMER_FORM_NOT_EXITS.getCode(),EpmetErrorCode.CUSTOMER_FORM_NOT_EXITS.getMsg()); + } + + List formItems = baseDao.listItems(formResultDto.getFormId()); + formItems.forEach(i -> { + i.setOptions(baseDao.selectListOption(i.getItemId())); + }); + + return formItems; + } } diff --git a/epmet-module/oper-customize/oper-customize-server/src/main/resources/mapper/IcFormDao.xml b/epmet-module/oper-customize/oper-customize-server/src/main/resources/mapper/IcFormDao.xml index 6310a06195..44d23cda3f 100644 --- a/epmet-module/oper-customize/oper-customize-server/src/main/resources/mapper/IcFormDao.xml +++ b/epmet-module/oper-customize/oper-customize-server/src/main/resources/mapper/IcFormDao.xml @@ -210,4 +210,33 @@ g.SORT ASC + diff --git a/epmet-user/epmet-user-server/pom.xml b/epmet-user/epmet-user-server/pom.xml index c6417f095f..0d8854d5ff 100644 --- a/epmet-user/epmet-user-server/pom.xml +++ b/epmet-user/epmet-user-server/pom.xml @@ -13,6 +13,11 @@ jar + + com.alibaba + easyexcel + 2.2.6 + com.epmet epmet-user-client diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java index a03b43299d..2f89248a3e 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java @@ -356,4 +356,10 @@ public class IcResiUserController { } + @PostMapping("import/excel") + public Result importExcelByEasyExcel() { + Object header = icResiUserService.importExcel(); + return new Result().ok(header); + } + } diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/DynamicEasyExcelListener.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/DynamicEasyExcelListener.java new file mode 100644 index 0000000000..0abf0f28d0 --- /dev/null +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/DynamicEasyExcelListener.java @@ -0,0 +1,73 @@ +package com.epmet.excel.handler; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 创建一个监听器 + */ +@Slf4j +public class DynamicEasyExcelListener extends AnalysisEventListener> { + + /** + * 表头数据(存储所有的表头数据) + */ + private List> headList = new ArrayList<>(); + + /** + * 数据体 + */ + private List> dataList = new ArrayList<>(); +// Map dataList = new HashMap<>(); + + /** + * 这里会一行行的返回头 + * + * @param headMap + * @param context + */ + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + log.info("解析到一条头数据:{}", JSON.toJSONString(headMap)); + //存储全部表头数据 + headList.add(headMap); + } + + /** + * 这个每一条数据解析都会来调用 + * + * @param data + * one row value. Is is same as {@link AnalysisContext#readRowHolder()} + * @param context + */ + @Override + public void invoke(Map data, AnalysisContext context) { + log.info("解析到一条数据:{}", JSON.toJSONString(data)); + dataList.add(data); + } + + /** + * 所有数据解析完成了 都会来调用 + * + * @param context + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 这里也要保存数据,确保最后遗留的数据也存储到数据库 + log.info("所有数据解析完成!"); + } + + public List> getHeadList() { + return headList; + } + + public List> getDataList() { + return dataList; + } +} \ No newline at end of file diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcResiExcelImportHandler.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcResiExcelImportHandler.java new file mode 100644 index 0000000000..8ae901cd51 --- /dev/null +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcResiExcelImportHandler.java @@ -0,0 +1,12 @@ +package com.epmet.excel.handler; + +import cn.afterturn.easypoi.handler.impl.ExcelDataHandlerDefaultImpl; + +import java.util.Map; + +public class IcResiExcelImportHandler extends ExcelDataHandlerDefaultImpl> { + @Override + public Object importHandler(Map obj, String name, Object value) { + return super.importHandler(obj, name, value); + } +} diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java index 3e582adbb5..cb1f9e748d 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java @@ -130,4 +130,5 @@ public interface IcResiUserService extends BaseService { */ Map queryIcResiDetail(IcResiDetailFormDTO pageFormDTO); + Object importExcel(); } \ No newline at end of file diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java index 25b86988b1..587e34a03f 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java @@ -17,6 +17,7 @@ package com.epmet.service.impl; +import com.alibaba.excel.EasyExcelFactory; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -24,10 +25,13 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; import com.epmet.commons.tools.constant.FieldConstant; import com.epmet.commons.tools.constant.NumConstant; +import com.epmet.commons.tools.constant.ServiceConstant; import com.epmet.commons.tools.constant.StrConstant; import com.epmet.commons.tools.enums.GenderEnum; import com.epmet.commons.tools.enums.HouseTypeEnum; +import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.RenException; +import com.epmet.commons.tools.feign.ResultDataResolver; import com.epmet.commons.tools.page.PageData; import com.epmet.commons.tools.security.dto.TokenDto; import com.epmet.commons.tools.utils.ConvertUtils; @@ -37,17 +41,16 @@ import com.epmet.dao.IcResiUserDao; import com.epmet.dto.CustomerAgencyDTO; import com.epmet.dto.IcResiUserDTO; import com.epmet.dto.form.*; -import com.epmet.dto.result.AllGridsByUserIdResultDTO; -import com.epmet.dto.result.HomeUserResultDTO; -import com.epmet.dto.result.HouseInfoDTO; -import com.epmet.dto.result.IcFormResColumnDTO; +import com.epmet.dto.result.*; import com.epmet.entity.IcResiUserEntity; +import com.epmet.excel.handler.DynamicEasyExcelListener; import com.epmet.feign.GovOrgOpenFeignClient; import com.epmet.feign.OperCustomizeOpenFeignClient; import com.epmet.redis.IcResiUserRedis; import com.epmet.service.IcResiUserService; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -57,6 +60,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.File; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -69,7 +73,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class IcResiUserServiceImpl extends BaseServiceImpl implements IcResiUserService { +public class IcResiUserServiceImpl extends BaseServiceImpl implements IcResiUserService, ResultDataResolver { private Logger logger = LogManager.getLogger(IcResiUserServiceImpl.class); @Autowired private IcResiUserRedis icResiUserRedis; @@ -417,4 +421,301 @@ public class IcResiUserServiceImpl extends BaseServiceImpl> headList = readListener.getHeadList(); + List> dataList = readListener.getDataList(); + + Map> headers = mergeHead(headList); + + // 查询form相关信息 + CustomerFormQueryDTO form = new CustomerFormQueryDTO(); + form.setFormCode("resi_base_info"); + Result> result = operCustomizeOpenFeignClient.listItems(form); + List customerItems = getResultDataOrThrowsException(result, ServiceConstant.OPER_CUSTOMIZE_SERVER, EpmetErrorCode.SERVER_ERROR.getCode(), "【居民信息excel导入】查询表单相关信息失败"); + + // 清洗表头数据 + Map abandonedHeaders = washHeaders(headers, customerItems); + + //合并多级表头 + HashMap> combinedHeaders = combineHeaders(headers); + + // 得到客户配置item数据 + Map formItemMap = customerItems.stream().collect( + Collectors.toMap(formItem -> { + String groupLabel = formItem.getGroupLabel(); + String label = formItem.getLabel(); + if (StringUtils.isNotBlank(groupLabel)) { + return groupLabel.concat(":").concat(label); + } else { + return label; + } + }, formItem -> formItem) + ); + HashMap> headerColumnWrapper = integrate(formItemMap, combinedHeaders, dataList, abandonedHeaders); + + return headerColumnWrapper; + } + + /** + * @description 合并头 + * + * @param headers + * @return + * @author wxz + * @date 2021.10.28 21:27:18 + */ + private HashMap> combineHeaders(Map> headers) { + HashMap> itemAndColIndexs = new HashMap<>(); + + headers.forEach((k, v) -> { + String tempKey = String.join(":", v); + List colIndexs = itemAndColIndexs.get(tempKey); + if (colIndexs == null) { + colIndexs = new ArrayList<>(); + itemAndColIndexs.put(tempKey, colIndexs); + } + colIndexs.add(k); + }); + + return itemAndColIndexs; + } + + /** + * @description 清洗headers + * + * @param headers + * @param items + * @return + * @author wxz + * @date 2021.10.28 21:07:12 + */ + private Map washHeaders(Map> headers, List items) { + List itemLabels = items.stream().map(i -> i.getLabel()).collect(Collectors.toList()); + Map abandonedHeaders = new HashMap<>(); + for (Map.Entry> entry:headers.entrySet()) { + Integer colIdx = entry.getKey(); + List v = entry.getValue(); + int lastPartIndex = v.size() - 1; + String lastValuePart = v.get(lastPartIndex); + if (itemLabels.indexOf(lastValuePart) == -1) { + // 该部分为options,它的上一级是item,那么去掉options这一级 + v.remove(lastPartIndex); + abandonedHeaders.put(colIdx, lastValuePart); + } + } + + return abandonedHeaders; + //headers.forEach((k, v) -> { + // + //}); + } + + /** + * @description 数据整合 + * + * @return + * @author wxz + * @date 2021.10.28 17:08:51 + */ + private HashMap> integrate(Map formItemMap, Map> combinedHeaders, + List> datas, Map abandonedHeaders) { + HashMap> data = new HashMap<>(); + + for (Map.Entry> entry : combinedHeaders.entrySet()) { + String combinedHeader = entry.getKey(); + + FormItem item = formItemMap.get(combinedHeader); + + if (item == null) { + // 如果数据库中没有该项,可能是用户自己定义的项,忽略 + continue; + } + + ColumnWrapper columnWrapper = new ColumnWrapper(); + + // 填充options + columnWrapper.setItemType(item.getItemType()); + String groupLabel = item.getGroupLabel(); + String combinedLabel = StringUtils.isBlank(groupLabel) ? item.getLabel() : groupLabel.concat(":").concat(item.getLabel()); + columnWrapper.setCombinedLabel(combinedLabel); + columnWrapper.setColumnName(item.getColumnName()); + columnWrapper.setColIndexs(entry.getValue()); + + if ("remote".equals(item.getOptionSourceType())) { + Map options = listRemoteOptions(item.getOptionSourceValue()); + columnWrapper.setOptions(options); + } else { + Map options = item.getOptions().stream().collect(Collectors.toMap(OptionDTO::getLabel, OptionDTO::getValue)); + columnWrapper.setOptions(options); + } + + /*switch (item.getItemType()) { + case "input": + case "textarea": + case "datepicker": + case "timerange": + //输入性的 + break; + case "checkbox": + break; + }*/ + + } + return data; + } + + /** + * 获取checkbox列值 + * @param options + * @param writedColIdxs + * @param abandonedHeaders + * @return + */ + private String getCheckBoxColValue(List options, List writedColIdxs, Map abandonedHeaders) { + + Map optionMap = options.stream().collect(Collectors.toMap(OptionDTO::getLabel, OptionDTO::getValue)); + + List optionValues = writedColIdxs.stream().map(i -> { + String optionName = abandonedHeaders.get(i); + return optionMap.get(optionName); + }).collect(Collectors.toList()); + + return String.join(",", optionValues); + } + + /** + * 远程获取options + * @param uri + * @return + */ + private Map listRemoteOptions(String uri) { + + return null; + + // 通用api调用,无法实现 + /*if (!uri.startsWith("/api")) uri = "/api".concat(uri); + + NamingService namingService = discoveryProperties.namingServiceInstance(); + ResponseEntity>> response = null; + try { + // 调用gateway服务,查询相关接口 + Instance gatewayInstance = namingService.getAllInstances(ServiceConstant.EPMET_GATEWAY).get(0); + String ip = gatewayInstance.getIp(); + int port = gatewayInstance.getPort(); + + String url = String.format("http://%s:%s%s", ip, port, uri); + + ParameterizedTypeReference>> tr = new ParameterizedTypeReference>>() {}; + response = new RestTemplate().exchange(url, HttpMethod.POST, null, tr); + } catch (NacosException e) { + e.printStackTrace(); + } + + if (response != null && (response.getStatusCode() == HttpStatus.OK)) { + List options = response.getBody().getData(); + if (options == null) { + System.out.println(6); + } + return options.stream().collect(Collectors.toMap(OptionResultDTO::getLabel, OptionResultDTO::getValue)); + } else { + throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode()); + }*/ + + } + + /** + * @description 合并表头 + * + * @param headList + * @return + * @author wxz + * @date 2021.10.27 16:17:34 + */ + private Map> mergeHead(List> headList) { + Map l1 = headList.get(0); + Map l2 = headList.get(1); + Map l3 = headList.get(2); + + String l1LastHeadName = ""; + String l2LastHeadName = ""; + + //Map resultMap = new HashMap<>(); + HashMap> result = new HashMap<>(); + + for (Map.Entry entry : l1.entrySet()) { + + StringBuilder headerNameConcatStr = new StringBuilder(); + + Integer key = entry.getKey(); + String l1TempValue = entry.getValue(); + + String l2TempValue = l2.get(key); + String l3TempValue = l3.get(key); + + if (StringUtils.isNotBlank(l1TempValue)) { + l1LastHeadName = l1TempValue; + } + + if (StringUtils.isNotBlank(l2TempValue)) { + l2LastHeadName = l2TempValue; + } + + // 开始拼接 + if (StringUtils.isNotBlank(l3TempValue)) { + //headerNameConcatStr.append(l1LastHeadName).append(":").append(l2LastHeadName).append(":").append(l3TempValue); + //resultMap.put(key, headerNameConcatStr.toString()); + ArrayList parts = new ArrayList<>(); + parts.add(l1LastHeadName); + parts.add(l2LastHeadName); + parts.add(l3TempValue); + result.put(key, parts); + continue; + } + + if (StringUtils.isNotBlank(l2TempValue)) { + //headerNameConcatStr.append(l1LastHeadName).append(":").append(l2LastHeadName); + //resultMap.put(key, headerNameConcatStr.toString()); + ArrayList parts = new ArrayList<>(); + parts.add(l1LastHeadName); + parts.add(l2LastHeadName); + result.put(key, parts); + continue; + } + + if (StringUtils.isNotBlank(l1TempValue)) { + //headerNameConcatStr.append(l1LastHeadName); + //resultMap.put(key, headerNameConcatStr.toString()); + ArrayList parts = new ArrayList<>(); + parts.add(l1LastHeadName); + result.put(key, parts); + continue; + } + + } + return result; + } + + /** + * @description 列信息封装 + * + * @return + * @author wxz + * @date 2021.10.28 22:18:05 + */ + @Data + public static class ColumnWrapper { + private String combinedLabel; + private String columnName; + private String itemType; + private List colIndexs; + //private List colContents; + private String colValue; + + // key:label,value:value + private Map options; + } } \ No newline at end of file From 5a397acffa91632e50363f72a4e50f16537e410d Mon Sep 17 00:00:00 2001 From: yinzuomei <576302893@qq.com> Date: Tue, 2 Nov 2021 10:53:16 +0800 Subject: [PATCH 2/4] test --- .../epmet/dto/form/DynamicQueryFormDTO.java | 22 +++++++++++++++++++ .../controller/IcResiUserController.java | 8 +++++++ .../java/com/epmet/dao/IcResiUserDao.java | 15 +++++++++++++ .../com/epmet/service/IcResiUserService.java | 10 +++++---- .../service/impl/IcResiUserServiceImpl.java | 14 ++++++++++++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/DynamicQueryFormDTO.java diff --git a/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/DynamicQueryFormDTO.java b/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/DynamicQueryFormDTO.java new file mode 100644 index 0000000000..42e163838b --- /dev/null +++ b/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/DynamicQueryFormDTO.java @@ -0,0 +1,22 @@ +package com.epmet.dto.form; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; + +/** + * @Description test + * @Author yinzuomei + * @Date 2021/11/2 10:38 上午 + */ +@Data +public class DynamicQueryFormDTO implements Serializable { + private String customerId; + private String formCode="resi_base_info"; + @NotBlank(message = "resultTableName不能为空") + private String resultTableName; + private List conditions; +} + diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java index a03b43299d..78b281e44d 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java @@ -356,4 +356,12 @@ public class IcResiUserController { } + @PostMapping("test") + public Result>> test(@LoginUser TokenDto tokenDto,@RequestBody DynamicQueryFormDTO formDTO){ + formDTO.setCustomerId(tokenDto.getCustomerId()); + return new Result>>().ok(icResiUserService.dynamicQuery(formDTO.getCustomerId(), + formDTO.getFormCode(), + formDTO.getResultTableName(), + formDTO.getConditions())); + } } diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/dao/IcResiUserDao.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/dao/IcResiUserDao.java index 47b63f6eec..1d4f66a4cb 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/dao/IcResiUserDao.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/dao/IcResiUserDao.java @@ -80,4 +80,19 @@ public interface IcResiUserDao extends BaseDao { int updateToDel(String icResiUserId); int updateSubTableToDel(@Param("subTalbeName") String subTalbeName, @Param("icResiUserId")String icResiUserId); + + /** + * 接口名称 + * + * @param customerId 客户id + * @param resultTableName 获取哪个表的数据??? + * @param conditions 前端传入的查询入参 + * @return java.util.List> + * @author yinzuomei + * @date 2021/11/2 10:35 上午 + */ + List> dynamicQuery(@Param("customerId")String customerId, + @Param("resultTableName")String resultTableName, + @Param("conditions") List conditions, + @Param("subTables") List subTables); } \ No newline at end of file diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java index 3e582adbb5..129dd16df0 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcResiUserService.java @@ -21,10 +21,7 @@ import com.epmet.commons.mybatis.service.BaseService; import com.epmet.commons.tools.page.PageData; import com.epmet.commons.tools.security.dto.TokenDto; import com.epmet.dto.IcResiUserDTO; -import com.epmet.dto.form.DelIcResiUserFormDTO; -import com.epmet.dto.form.IcResiDetailFormDTO; -import com.epmet.dto.form.IcResiUserFormDTO; -import com.epmet.dto.form.IcResiUserPageFormDTO; +import com.epmet.dto.form.*; import com.epmet.dto.result.HomeUserResultDTO; import com.epmet.entity.IcResiUserEntity; @@ -130,4 +127,9 @@ public interface IcResiUserService extends BaseService { */ Map queryIcResiDetail(IcResiDetailFormDTO pageFormDTO); + + List> dynamicQuery(String customerId, + String formCode, + String resultTableName, + List conditions); } \ No newline at end of file diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java index 25b86988b1..109ae5b3a5 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcResiUserServiceImpl.java @@ -417,4 +417,18 @@ public class IcResiUserServiceImpl extends BaseServiceImpl> dynamicQuery(String customerId, + String formCode, + String resultTableName, + List conditions){ + CustomerFormQueryDTO queryDTO=new CustomerFormQueryDTO(); + queryDTO.setCustomerId(customerId); + queryDTO.setFormCode(formCode); + Result> subTablesRes=operCustomizeOpenFeignClient.querySubTables(queryDTO); + List subTables=new ArrayList<>(); + if(subTablesRes.success()&&CollectionUtils.isNotEmpty(subTablesRes.getData())){ + subTables =subTablesRes.getData(); + } + return baseDao.dynamicQuery(customerId,resultTableName,conditions,subTables); + } } \ No newline at end of file From 4155550ea5d07b3b3992e1c41f53d748587f9fda Mon Sep 17 00:00:00 2001 From: yinzuomei <576302893@qq.com> Date: Tue, 2 Nov 2021 11:07:32 +0800 Subject: [PATCH 3/4] test1 --- .../main/resources/mapper/IcResiUserDao.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/epmet-user/epmet-user-server/src/main/resources/mapper/IcResiUserDao.xml b/epmet-user/epmet-user-server/src/main/resources/mapper/IcResiUserDao.xml index 26e20f7407..616d55e711 100644 --- a/epmet-user/epmet-user-server/src/main/resources/mapper/IcResiUserDao.xml +++ b/epmet-user/epmet-user-server/src/main/resources/mapper/IcResiUserDao.xml @@ -104,4 +104,22 @@ update ${subTalbeName} set del_flag='1' where IC_RESI_USER=#{icResiUserId} + + \ No newline at end of file From 249caedb55470f676721c68e14fe168f1f73b917 Mon Sep 17 00:00:00 2001 From: jianjun Date: Tue, 2 Nov 2021 11:20:04 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=AF=BC=E5=87=BA=20=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/IcResiUserController.java | 34 ++++++++++++++---- .../main/resources/excel/ic_resi_info_cid.xls | Bin 79872 -> 79872 bytes 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java index 6f6c955a42..f93c505efb 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcResiUserController.java @@ -57,6 +57,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URLEncoder; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; /** @@ -330,21 +331,40 @@ public class IcResiUserController { pageFormDTO.setPageFlag(false); //PageData> mapPageData = icResiUserService.pageResiMap(pageFormDTO); //List> list = mapPageData.getList(); - List> list = (List>)JSON.parse("[{\"IS_SPECIAL\":\"1\",\"IS_XFRY\":\"0\",\"REMARKS\":\"beizhu\",\"IS_PARTY\":\"1\",\"icResiUserId\":\"yzmtest2\",\"HOME_ID\":\"中海国际社区一里城1号楼1单元101\",\"HOUSE_TYPE\":\"平房\",\"UNIT_NAME\":\"1单元\",\"GRID_ID\":\"市北区-市北区第三网格3\",\"IS_DB\":\"0\",\"GENDER\":\"男\",\"BIRTHDAY\":\"2021-10-04\",\"IS_VETERANS\":\"0\",\"IS_MB\":\"0\",\"IS_UNEMPLOYED\":\"0\",\"DEMAND_NAME\":null,\"IS_KC\":\"0\",\"IS_ENSURE_HOUSE\":\"0\",\"IS_SD\":\"0\",\"NAME\":\"尹作梅\",\"RDSJ\":null,\"IS_VOLUNTEER\":\"1\",\"GRID_ID_VALUE\":\"e74829ffc43d5470eba6b5e060c11e63\",\"IS_SZ\":\"0\",\"IS_CJ\":\"0\",\"HOME_ID_VALUE\":\"200\",\"DEMAND_CATEGORY_IDS\":null,\"VILLAGE_NAME\":\"中海国际社区一里城\",\"IS_DBH\":\"0\",\"IS_SN\":\"0\",\"BUILD_NAME\":\"1号楼\",\"IS_YLFN\":\"0\",\"IS_UNITED_FRONT\":\"0\",\"ID_CARD\":\"371325199310260529\",\"MOBILE\":\"15764229697\",\"IS_OLD_PEOPLE\":\"0\",\"DOOR_NAME\":\"101\"},{\"IS_SPECIAL\":\"1\",\"IS_XFRY\":\"0\",\"REMARKS\":\"beizhu\",\"IS_PARTY\":\"1\",\"icResiUserId\":\"yzmtest\",\"HOME_ID\":\"中海国际社区一里城1号楼1单元101\",\"HOUSE_TYPE\":\"平房\",\"UNIT_NAME\":\"1单元\",\"GRID_ID\":\"市北区-市北区第三网格3\",\"IS_DB\":\"0\",\"GENDER\":\"男\",\"BIRTHDAY\":\"2021-10-04\",\"IS_VETERANS\":\"0\",\"IS_MB\":\"0\",\"IS_UNEMPLOYED\":\"0\",\"DEMAND_NAME\":\"心理咨询\",\"IS_KC\":\"0\",\"IS_ENSURE_HOUSE\":\"0\",\"IS_SD\":\"0\",\"NAME\":\"尹作梅\",\"RDSJ\":\"2021-10-28 00:00:00\",\"IS_VOLUNTEER\":\"1\",\"GRID_ID_VALUE\":\"e74829ffc43d5470eba6b5e060c11e63\",\"IS_SZ\":\"0\",\"IS_CJ\":\"0\",\"HOME_ID_VALUE\":\"200\",\"DEMAND_CATEGORY_IDS\":\"10180002\",\"VILLAGE_NAME\":\"中海国际社区一里城\",\"IS_DBH\":\"0\",\"IS_SN\":\"0\",\"BUILD_NAME\":\"1号楼\",\"IS_YLFN\":\"0\",\"IS_UNITED_FRONT\":\"0\",\"ID_CARD\":\"371325199310260529\",\"MOBILE\":\"15764229697\",\"IS_OLD_PEOPLE\":\"0\",\"DOOR_NAME\":\"101\"}]" - ); - Map mapData = new HashMap<>(); + List> list = icResiUserService.dynamicQuery(pageFormDTO.getCustomerId(), pageFormDTO.getFormCode(), BASE_TABLE_NAME, pageFormDTO.getConditions()); + //list = (List>)JSON.parse("[{\"IS_BDHJ\":\"1\",\"IS_SPECIAL\":\"1\",\"IS_XFRY\":\"0\",\"REMARKS\":\"beizhu\",\"IS_PARTY\":\"1\",\"icResiUserId\":\"yzmtest2\",\"HOME_ID\":\"中海国际社区一里城1号楼1单元101\",\"HOUSE_TYPE\":\"平房\",\"UNIT_NAME\":\"1单元\",\"GRID_ID\":\"市北区-市北区第三网格3\",\"IS_DB\":\"0\",\"GENDER\":\"男\",\"BIRTHDAY\":\"2021-10-04\",\"IS_VETERANS\":\"0\",\"IS_MB\":\"0\",\"IS_UNEMPLOYED\":\"0\",\"DEMAND_NAME\":null,\"IS_KC\":\"0\",\"IS_ENSURE_HOUSE\":\"0\",\"IS_SD\":\"0\",\"NAME\":\"尹作梅\",\"RDSJ\":null,\"IS_VOLUNTEER\":\"1\",\"GRID_ID_VALUE\":\"e74829ffc43d5470eba6b5e060c11e63\",\"IS_SZ\":\"0\",\"IS_CJ\":\"0\",\"HOME_ID_VALUE\":\"200\",\"DEMAND_CATEGORY_IDS\":null,\"VILLAGE_NAME\":\"中海国际社区一里城\",\"IS_DBH\":\"0\",\"IS_SN\":\"0\",\"BUILD_NAME\":\"1号楼\",\"IS_YLFN\":\"0\",\"IS_UNITED_FRONT\":\"0\",\"ID_CARD\":\"371325199310260529\",\"MOBILE\":\"15764229697\",\"IS_OLD_PEOPLE\":\"0\",\"DOOR_NAME\":\"101\"},{\"IS_SPECIAL\":\"1\",\"IS_XFRY\":\"0\",\"REMARKS\":\"beizhu\",\"IS_PARTY\":\"1\",\"icResiUserId\":\"yzmtest\",\"HOME_ID\":\"中海国际社区一里城1号楼1单元101\",\"HOUSE_TYPE\":\"平房\",\"UNIT_NAME\":\"1单元\",\"GRID_ID\":\"市北区-市北区第三网格3\",\"IS_DB\":\"0\",\"GENDER\":\"男\",\"BIRTHDAY\":\"2021-10-04\",\"IS_VETERANS\":\"0\",\"IS_MB\":\"0\",\"IS_UNEMPLOYED\":\"0\",\"DEMAND_NAME\":\"心理咨询\",\"IS_KC\":\"0\",\"IS_ENSURE_HOUSE\":\"0\",\"IS_SD\":\"0\",\"NAME\":\"尹作梅\",\"RDSJ\":\"2021-10-28 00:00:00\",\"IS_VOLUNTEER\":\"1\",\"GRID_ID_VALUE\":\"e74829ffc43d5470eba6b5e060c11e63\",\"IS_SZ\":\"0\",\"IS_CJ\":\"0\",\"HOME_ID_VALUE\":\"200\",\"DEMAND_CATEGORY_IDS\":\"10180002\",\"VILLAGE_NAME\":\"中海国际社区一里城\",\"IS_DBH\":\"0\",\"IS_SN\":\"0\",\"BUILD_NAME\":\"1号楼\",\"IS_YLFN\":\"0\",\"IS_UNITED_FRONT\":\"0\",\"ID_CARD\":\"371325199310260529\",\"MOBILE\":\"15764229697\",\"IS_OLD_PEOPLE\":\"0\",\"DOOR_NAME\":\"101\"}]"); log.info("list:{}", JSON.toJSONString(list)); - mapData.put("list", list); + CustomerFormResultDTO resiFormItems = getResiFormItems(pageFormDTO.getCustomerId()); String templatePath = "excel/ic_resi_info_cid.xls"; - TemplateExportParams params = new TemplateExportParams(templatePath, 0,1); + TemplateExportParams params = new TemplateExportParams(templatePath,true); + + Map> sheetMap = new HashMap<>(); + Map mapData = new HashMap<>(); + mapData.put("list", list); + sheetMap.put(0,mapData); + AtomicInteger n = new AtomicInteger(); + resiFormItems.getItemList().forEach(item->{ + if (item.getChildGroup() != null){ + if (!item.getChildGroup().getTableName().equals(BASE_TABLE_NAME)) { + sheetMap.put( n.incrementAndGet(),mapData); + System.out.println(n.get()); + } + } + }); + for (FormGroupDTO group : resiFormItems.getGroupList()) { + + } + + + - Workbook workbook = ExcelExportUtil.exportExcel(new TemplateExportParams(templatePath), mapData); + Workbook workbook = ExcelExportUtil.exportExcel(sheetMap, params); //header response.setHeader("content-Type", "application/vnd.ms-excel"); - response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("继续追踪导出详情-" + ".xls", "UTF-8")); + response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("居民信息.xls", "UTF-8")); workbook.write(response.getOutputStream()); /* //方式1 通过mv导出 diff --git a/epmet-user/epmet-user-server/src/main/resources/excel/ic_resi_info_cid.xls b/epmet-user/epmet-user-server/src/main/resources/excel/ic_resi_info_cid.xls index 51a5d41a945f26f68fb9b5b5e7fb36b05ed6d092..b6a67b92057a4a34c4e65381aaa929e24b3f3344 100644 GIT binary patch delta 5896 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 YXc_v+$v?I2A0*1{qHo*95|NzzKelEmd;kCd delta 5203 zcmbW53v`sl702&8lnV30Ku?8wh0EY8uB10Nk~X&LMRYlfMSsi zsHmLaMy}3(6-SWw`{B?xAIJ9LCiX&HB)PK zCgew{DH@)DN%m^;l!RQ)HcpcV67u_6TleJb$szMpP41WSloVaATbr)Sv5cbxKSrej zPh!BAhKCKs)`VOt);*le9j*dqi_&;M2wD(d=^7?sTa&{*7L={R#-kdA(>x3P|u z4ZF(EY|EfW`OIl^Z2zW0$9;_Guo{X)m{lRxTDP%UZJxeKu`prm*G8T`#E+v{KSU&?-rjK&wHe z`sybGZ;*`_fo_yE1++%eRM1V5E(ZOKzgLsFc&(I0AiG)8bkI6UGe83_p9vapNHJ(& zmMEx0j{6a4y*hV((8iMZwsl!<3z~=+Sx|^n-guYd5QjxCi_M|5j&qfjTr6{7FgCgq7P(=M>6cg2x8D$~$_lsI^9*U?v zlnx6D=oaRLZLlx?or7gNM3WVzm#yb)e_E^#P3ifAvYjYW-ModUtR{|p@osJ3I_=6R zLjH}Gja!K>UzWY0u(qOHmsQ5bAd&Bi?W{{*v2ukj%UShQ`L?RRE@X2v$}u~%3#Cq! zUe+{VkJiGy`;#gn!iLZpM+{L`)i{j(oB zUz_%Qf4-0;hGbC|hQx%H_DV?8$1q`vrM(uZIJG%ap1))l48G#t)fGe)b=NN-nsVJ? zq@r3c>Ok}I%CcIb`D+YmZ49)aPVc$8^7j}^q-dKqjizaJF%_R}rMp}VaL$`67IxE# zg+zb9?vi>jRP1*HMNoR#CBn+dIgqBi*@a7Lp((3Md|zH8zMCt>*R?==6U&=U(=l+8 z7?|x611+qjBJWBJsSaqS>HeHSGx)Z?aHb7e^RYPQ43lTlOwHsljpp9irS@a(L?e;U z_pejmZT2Zj8&h*%$YZLr^%EA`fMFu*VFS|P7D;Zj zy3-($0#Vu|iGeEks(Q*hfMc}nRUdlXF4-|y2V>+kn-ckD9zK`f~H9-_i6*v<^bpNo5WXU74t zt@GEptvNgogR?nrORondiQNxO|}zO zvHDYVLM^=WaVH+`Gxmj?;sK3U1d7)ymmUAY!Lq~&C>|J8&zrg@I0hDcg$T5Z$6#Q( zk1enKXiaf5QhqaQXt`tZW}Dtc=>N(0(#73!vcWRg&1c9g>72UXUal@uDOj zs7I0?^b)^zX{P%2&RL2b+ozo$Ud9)_I<2RIv6D9D(elWTF?t^P{rqrO5D#j?X`7E- z7e|#DXKkIxBgWz(Co6Y!y+hP@lxWK_QkzcOnA&+@tto4#p;-_4UD6KiBs^C@dR~_O z#a`@|cH6E>5_Z21QPZmtVfL3c-nGu0{=h)|h`i*|bNJ8;_*Dl02YSC3!)wNlL*p>bH`7px61qk4DD^?gaeJ zf_37`)?!k@7Dq{3?;>8sZ5+j)IeLmJaDbj*3Z8sX!VAdgl?1Ahy>N>d@?^+ygBoN5 z;r$|ruljg|rI!Mv@b$;jT)Hliv~R%S|2&kYhL7i39A9av`vK0W1N``@LVnH3WOdWY zus1&5!7|;7k*>nz)Kvb)*P9&u_@_XF{;~;)#I>2wEG#$kgMHHxP<8QaC%fGKWIxd< zGowzMy6E&4vuB@S<_|o#*#3dQn63rJi}YL~Fut`p#s78ak>GTmI}*z66Vn)d6JoSu zG+%VOFTUKxp5Z6H@%7}nnPQrKz%WjKFT5#9oF8vV66eQ3N#guCWY7;=RMCiDa>HsT z{HGU><~iJIe8tkto+&=I&20NHS-$}H#*YVB5x;D^JwDIFygd`s+0AaZpRgI2!;g}b z#5W(y*50L>D@K^KEiv*~%V%*PI)}ana^-8lZSq39Hx}+W4@WrLlE;GPI~#U?+Y`!T k_nN%7R-8O=#Ss>T&W`R;_UfKj#