forked from github/dataease
feat(仪表板): 增加世界地图及相关配置
This commit is contained in:
parent
c731df25e1
commit
7f7cdeb0dd
@ -54,6 +54,7 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
// 验证链接
|
||||
filterChainDefinitionMap.put("/api/link/validate**", ANON);
|
||||
filterChainDefinitionMap.put("/api/map/areaEntitys/**", ANON);
|
||||
filterChainDefinitionMap.put("/api/map/globalEntitys/**", ANON);
|
||||
filterChainDefinitionMap.put("/linkJump/queryPanelJumpInfo/**", ANON);
|
||||
filterChainDefinitionMap.put("/linkJump/queryTargetPanelJumpInfo", ANON);
|
||||
|
||||
|
@ -9,7 +9,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Value("${geo.rootpath:file:/opt/dataease/data/feature/full/}")
|
||||
@Value("${geo.rootpath:file:/opt/dataease/data/feature/}")
|
||||
private String geoPath;
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,20 @@
|
||||
package io.dataease.listener;
|
||||
|
||||
import io.dataease.map.service.MapTransferService;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Component
|
||||
public class GlobalMapTransferListener implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
@Resource
|
||||
private MapTransferService mapTransferService;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
mapTransferService.execute();
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package io.dataease.map.api;
|
||||
|
||||
import io.dataease.map.dto.entity.AreaEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import io.dataease.map.dto.request.MapNodeRequest;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -19,4 +19,9 @@ public interface MapApi {
|
||||
@GetMapping("/globalEntitys/{pcode}")
|
||||
List<AreaEntity> globalEntitys(@PathVariable String pcode);
|
||||
|
||||
@PostMapping(value = "/saveMapNode", consumes = {"multipart/form-data"})
|
||||
void saveMapNode(MapNodeRequest request, MultipartFile file) throws Exception;
|
||||
|
||||
@PostMapping("/delMapNode")
|
||||
void delMapNode(MapNodeRequest request);
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package io.dataease.map.dto.request;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class MapNodeRequest implements Serializable {
|
||||
@ApiModelProperty("区域代码")
|
||||
private String code;
|
||||
@ApiModelProperty("区域名称")
|
||||
private String name;
|
||||
@ApiModelProperty("上级代码")
|
||||
private String pcode;
|
||||
@ApiModelProperty("上级级别")
|
||||
private Integer plevel;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.map.dto.response;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class MapNodeReadReponse implements Serializable {
|
||||
|
||||
@ApiModelProperty("区域代码")
|
||||
private String code;
|
||||
@ApiModelProperty("区域名称")
|
||||
private String name;
|
||||
@ApiModelProperty("区域级别")
|
||||
private Integer level;
|
||||
@ApiModelProperty("上级区域")
|
||||
private MapNodeReadReponse parent;
|
||||
@ApiModelProperty("geoGson")
|
||||
private String json;
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
package io.dataease.map.server;
|
||||
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.map.api.MapApi;
|
||||
import io.dataease.map.dto.entity.AreaEntity;
|
||||
import io.dataease.map.dto.request.MapNodeRequest;
|
||||
import io.dataease.map.service.MapService;
|
||||
import io.dataease.map.utils.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@ -35,4 +37,15 @@ public class MapServer implements MapApi {
|
||||
}
|
||||
return mapService.entitysByPid(areaEntities, pcode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveMapNode(@RequestPart("request") MapNodeRequest request, @RequestPart(value = "file") MultipartFile file) throws Exception{
|
||||
mapService.saveMapNode(request, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delMapNode(@RequestBody MapNodeRequest request) {
|
||||
mapService.delMapNode(request);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,27 @@
|
||||
package io.dataease.map.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.io.file.FileReader;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import io.dataease.commons.exception.DEException;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.listener.util.CacheUtils;
|
||||
import io.dataease.map.dto.entity.AreaEntity;
|
||||
import io.dataease.map.dto.request.MapNodeRequest;
|
||||
import io.dataease.map.utils.MapUtils;
|
||||
import io.dataease.plugins.common.base.domain.AreaMappingGlobal;
|
||||
import io.dataease.plugins.common.base.domain.AreaMappingGlobalExample;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class MapService {
|
||||
@ -21,7 +34,7 @@ public class MapService {
|
||||
return areaEntities;
|
||||
}
|
||||
|
||||
@Cacheable("sys_map_areas")
|
||||
@Cacheable("sys_map_areas_global")
|
||||
public List<AreaEntity> globalEntities() {
|
||||
List<AreaEntity> areaEntities = MapUtils.readGlobalAreaEntity();
|
||||
return areaEntities;
|
||||
@ -45,4 +58,293 @@ public class MapService {
|
||||
|
||||
}
|
||||
|
||||
public String generateAreaCode(String pCode) {
|
||||
Long pValue = Long.parseLong(pCode);
|
||||
MapService mapService = CommonBeanFactory.getBean(MapService.class);
|
||||
List<AreaEntity> areaEntities = mapService.globalEntities();
|
||||
List<AreaEntity> brothers = entitysByPid(areaEntities, pCode);
|
||||
|
||||
brothers.sort(Comparator.comparing(item -> Long.parseLong(item.getCode())));
|
||||
AreaEntity lastBrother = brothers.get(brothers.size() - 1);
|
||||
|
||||
Long lastCode = Long.parseLong(lastBrother.getCode());
|
||||
|
||||
long areaCodeSuffix = lastCode - pValue;
|
||||
|
||||
int step = 0;
|
||||
|
||||
while (areaCodeSuffix % 10 == 0) {
|
||||
step++;
|
||||
areaCodeSuffix /= 10;
|
||||
}
|
||||
|
||||
areaCodeSuffix++;
|
||||
|
||||
while (step > 0) {
|
||||
areaCodeSuffix *= 10;
|
||||
step--;
|
||||
}
|
||||
|
||||
long targetCode = areaCodeSuffix + pValue;
|
||||
return String.valueOf(targetCode);
|
||||
}
|
||||
|
||||
private void delFileByNodes(List<AreaMappingGlobal> nodes, Integer pLevel) {
|
||||
Set<String> sets = nodes.stream().flatMap(node -> codesByNode(node, pLevel).stream()).collect(Collectors.toSet());
|
||||
sets.forEach(code -> {
|
||||
String countryCode = code.substring(0, 3);
|
||||
String path = dirPath + "/full/" + countryCode + "/" + code +"_full.json";
|
||||
if (FileUtil.exist(path)) {
|
||||
FileUtil.del(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Set<String> codesByNode(AreaMappingGlobal node, Integer pLevel) {
|
||||
Set<String> sets = new TreeSet<>();
|
||||
|
||||
if (pLevel == 2) {
|
||||
if(StringUtils.isNotBlank(node.getProvinceCode())) sets.add(node.getProvinceCode());
|
||||
if(StringUtils.isNotBlank(node.getCityCode())) sets.add(node.getCityCode());
|
||||
if(StringUtils.isNotBlank(node.getCountyCode())) sets.add(node.getCountyCode());
|
||||
} else if (pLevel == 3) {
|
||||
if(StringUtils.isNotBlank(node.getCityCode())) sets.add(node.getCityCode());
|
||||
if(StringUtils.isNotBlank(node.getCountyCode())) sets.add(node.getCountyCode());
|
||||
} else if (pLevel == 4) {
|
||||
if(StringUtils.isNotBlank(node.getCountyCode())) sets.add(node.getCountyCode());
|
||||
} else {
|
||||
if(StringUtils.isNotBlank(node.getCountryCode())) sets.add(node.getCountryCode());
|
||||
if(StringUtils.isNotBlank(node.getProvinceCode())) sets.add(node.getProvinceCode());
|
||||
if(StringUtils.isNotBlank(node.getCityCode())) sets.add(node.getCityCode());
|
||||
if(StringUtils.isNotBlank(node.getCountyCode())) sets.add(node.getCountyCode());
|
||||
}
|
||||
return sets;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delMapNode(MapNodeRequest request) {
|
||||
String pCode = request.getPcode();
|
||||
Integer pLevel = request.getPlevel();
|
||||
String code = request.getCode();
|
||||
AreaMappingGlobalExample example = new AreaMappingGlobalExample();
|
||||
AreaMappingGlobal curRoot = new AreaMappingGlobal();
|
||||
List<AreaMappingGlobal> nodes = null;
|
||||
if(pLevel == 0) {
|
||||
nodes = MapUtils.selectByExample(example);
|
||||
MapUtils.deleteByExample(example);
|
||||
delFileByNodes(nodes, pLevel);
|
||||
} else if (pLevel == 1) {
|
||||
example.createCriteria().andCountryCodeEqualTo(code);
|
||||
nodes = MapUtils.selectByExample(example);
|
||||
MapUtils.deleteByExample(example);
|
||||
delFileByNodes(nodes, pLevel);
|
||||
} else if (pLevel == 2) {
|
||||
example.createCriteria().andCountryCodeEqualTo(pCode).andProvinceCodeEqualTo(code);
|
||||
nodes = MapUtils.selectByExample(example);
|
||||
MapUtils.deleteByExample(example);
|
||||
example.clear();
|
||||
example.createCriteria().andCountryCodeEqualTo(pCode);
|
||||
if (!MapUtils.exampleExist(example) && CollectionUtil.isNotEmpty(nodes)) {
|
||||
AreaMappingGlobal template = nodes.get(0);
|
||||
curRoot.setCountryCode(template.getCountryCode());
|
||||
curRoot.setCountryName(template.getCountryName());
|
||||
MapUtils.addNode(curRoot);
|
||||
}
|
||||
delFileByNodes(nodes, pLevel);
|
||||
} else if (pLevel == 3) {
|
||||
|
||||
example.createCriteria().andProvinceCodeEqualTo(pCode).andCityCodeEqualTo(code);
|
||||
nodes = MapUtils.selectByExample(example);
|
||||
|
||||
MapUtils.deleteByExample(example);
|
||||
example.clear();
|
||||
example.createCriteria().andProvinceCodeEqualTo(pCode);
|
||||
|
||||
if (!MapUtils.exampleExist(example) && CollectionUtil.isNotEmpty(nodes)) {
|
||||
AreaMappingGlobal template = nodes.get(0);
|
||||
curRoot.setCountryCode(template.getCountryCode());
|
||||
curRoot.setCountryName(template.getCountryName());
|
||||
curRoot.setProvinceCode(template.getProvinceCode());
|
||||
curRoot.setProvinceName(template.getProvinceName());
|
||||
MapUtils.addNode(curRoot);
|
||||
}
|
||||
delFileByNodes(nodes, pLevel);
|
||||
} else if (pLevel == 4) {
|
||||
example.createCriteria().andCityCodeEqualTo(pCode).andCountyCodeEqualTo(code);
|
||||
nodes = MapUtils.selectByExample(example);
|
||||
|
||||
MapUtils.deleteByExample(example);
|
||||
example.clear();
|
||||
example.createCriteria().andProvinceCodeEqualTo(pCode);
|
||||
|
||||
if (!MapUtils.exampleExist(example) && CollectionUtil.isNotEmpty(nodes)) {
|
||||
AreaMappingGlobal template = nodes.get(0);
|
||||
curRoot.setCountryCode(template.getCountryCode());
|
||||
curRoot.setCountryName(template.getCountryName());
|
||||
curRoot.setProvinceCode(template.getProvinceCode());
|
||||
curRoot.setProvinceName(template.getProvinceName());
|
||||
curRoot.setCityCode(template.getCityCode());
|
||||
curRoot.setCityName(template.getCityName());
|
||||
MapUtils.addNode(curRoot);
|
||||
}
|
||||
delFileByNodes(nodes, pLevel);
|
||||
}
|
||||
CacheUtils.removeAll("sys_map_areas_global");
|
||||
}
|
||||
|
||||
private void validateFile(MultipartFile file) {
|
||||
long size = file.getSize();
|
||||
String name = file.getName();
|
||||
if (size / 1024 / 1024 > 30) {
|
||||
DEException.throwException("large file that exceed 30M is not supported");
|
||||
}
|
||||
if (!StringUtils.endsWith(name, ".json")) {
|
||||
DEException.throwException("only json file supported");
|
||||
}
|
||||
}
|
||||
@Transactional
|
||||
public void saveMapNode(MapNodeRequest request, MultipartFile file) throws Exception{
|
||||
validateFile(file);
|
||||
String pCode = request.getPcode();
|
||||
Integer plevel = request.getPlevel();
|
||||
String code = request.getCode();
|
||||
|
||||
if(StringUtils.isBlank(code)) {
|
||||
String newAreaCode = generateAreaCode(pCode);
|
||||
request.setCode(newAreaCode);
|
||||
}
|
||||
|
||||
AreaMappingGlobalExample example = new AreaMappingGlobalExample();
|
||||
|
||||
|
||||
if (plevel == 1) {
|
||||
example.createCriteria().andCountryCodeEqualTo(code);
|
||||
}
|
||||
else if (plevel == 2) {
|
||||
example.createCriteria().andCountryCodeEqualTo(pCode).andProvinceCodeEqualTo(code);
|
||||
}
|
||||
else if (plevel == 3) {
|
||||
example.createCriteria().andProvinceCodeEqualTo(pCode).andCityCodeEqualTo(code);
|
||||
}else if (plevel == 4) {
|
||||
example.createCriteria().andCityCodeEqualTo(pCode).andCountyCodeEqualTo(code);
|
||||
} else {
|
||||
DEException.throwException("只支持3级行政区");
|
||||
}
|
||||
List<AreaMappingGlobal> lists = MapUtils.selectByExample(example);
|
||||
if (CollectionUtil.isNotEmpty(lists)) {
|
||||
DEException.throwException("区域代码已存在");
|
||||
}
|
||||
|
||||
example.clear();
|
||||
AreaMappingGlobalExample pExample = new AreaMappingGlobalExample();
|
||||
if (plevel == 1) {
|
||||
pExample.createCriteria().andCountryCodeIsNull().andProvinceCodeIsNull().andCityCodeIsNull().andCountyCodeIsNull();
|
||||
List<AreaMappingGlobal> existLists = MapUtils.selectByExample(pExample);
|
||||
if (CollectionUtil.isNotEmpty(existLists)) {
|
||||
AreaMappingGlobal node = existLists.get(0);
|
||||
node.setCountryCode(code);
|
||||
node.setCountryName(request.getName());
|
||||
MapUtils.update(node);
|
||||
}else {
|
||||
AreaMappingGlobal node = new AreaMappingGlobal();
|
||||
node.setCountryCode(code);
|
||||
node.setCountryName(request.getName());
|
||||
MapUtils.addNode(node);
|
||||
}
|
||||
}
|
||||
else if (plevel == 2) {
|
||||
pExample.createCriteria().andCountryCodeEqualTo(pCode).andProvinceCodeIsNull().andCityCodeIsNull().andCountyCodeIsNull();
|
||||
List<AreaMappingGlobal> existLists = MapUtils.selectByExample(pExample);
|
||||
if (CollectionUtil.isNotEmpty(existLists)) {
|
||||
AreaMappingGlobal node = existLists.get(0);
|
||||
node.setProvinceCode(code);
|
||||
node.setProvinceName(request.getName());
|
||||
MapUtils.update(node);
|
||||
}else {
|
||||
AreaMappingGlobal country = country(pCode);
|
||||
AreaMappingGlobal node = new AreaMappingGlobal();
|
||||
node.setCountryCode(pCode);
|
||||
node.setCountryName(country.getCountryName());
|
||||
node.setProvinceCode(code);
|
||||
node.setProvinceName(request.getName());
|
||||
MapUtils.addNode(node);
|
||||
}
|
||||
}
|
||||
else if (plevel == 3) {
|
||||
pExample.createCriteria().andProvinceCodeEqualTo(pCode).andCityCodeIsNull();
|
||||
List<AreaMappingGlobal> existLists = MapUtils.selectByExample(pExample);
|
||||
if (CollectionUtil.isNotEmpty(existLists)) {
|
||||
AreaMappingGlobal node = existLists.get(0);
|
||||
node.setCityCode(code);
|
||||
node.setCityName(request.getName());
|
||||
MapUtils.update(node);
|
||||
}else {
|
||||
AreaMappingGlobal province = province(pCode);
|
||||
AreaMappingGlobal node = new AreaMappingGlobal();
|
||||
node.setCountryCode(province.getCountryCode());
|
||||
node.setCountryName(province.getCountryName());
|
||||
node.setProvinceCode(pCode);
|
||||
node.setProvinceName(province.getProvinceName());
|
||||
node.setCityCode(code);
|
||||
node.setCityName(request.getName());
|
||||
MapUtils.addNode(node);
|
||||
}
|
||||
} else if (plevel == 4) {
|
||||
pExample.createCriteria().andCountryCodeEqualTo(pCode).andCountyCodeIsNull();
|
||||
List<AreaMappingGlobal> existLists = MapUtils.selectByExample(pExample);
|
||||
if (CollectionUtil.isNotEmpty(existLists)) {
|
||||
AreaMappingGlobal node = existLists.get(0);
|
||||
node.setCountyCode(code);
|
||||
node.setCountyName(request.getName());
|
||||
MapUtils.update(node);
|
||||
}else {
|
||||
AreaMappingGlobal city = city(pCode);
|
||||
AreaMappingGlobal node = new AreaMappingGlobal();
|
||||
node.setCountryCode(city.getCountryCode());
|
||||
node.setCountryName(city.getCountryName());
|
||||
node.setProvinceCode(city.getProvinceCode());
|
||||
node.setProvinceName(city.getProvinceName());
|
||||
node.setCityCode(pCode);
|
||||
node.setCityName(request.getName());
|
||||
node.setCountyCode(code);
|
||||
node.setCountyName(request.getName());
|
||||
MapUtils.addNode(node);
|
||||
}
|
||||
} else {
|
||||
DEException.throwException("只支持3级行政区");
|
||||
}
|
||||
uploadMapFile(file, code);
|
||||
CacheUtils.removeAll("sys_map_areas_global");
|
||||
}
|
||||
|
||||
public void uploadMapFile(MultipartFile file, String areaCode) throws Exception{
|
||||
String dir = dirPath + "full/";
|
||||
File fileDir = new File(dir);
|
||||
if (!fileDir.exists()) {
|
||||
fileDir.mkdirs();
|
||||
}
|
||||
String countryCode = areaCode.substring(0, 3);
|
||||
String targetPath = dir + countryCode + "/" + areaCode+"_full.json";
|
||||
File target = new File(targetPath);
|
||||
file.transferTo(target);
|
||||
}
|
||||
|
||||
private AreaMappingGlobal country(String pCode) {
|
||||
AreaMappingGlobalExample pExample = new AreaMappingGlobalExample();
|
||||
pExample.createCriteria().andCountryCodeEqualTo(pCode);
|
||||
return MapUtils.selectByExample(pExample).stream().findFirst().get();
|
||||
}
|
||||
|
||||
private AreaMappingGlobal province(String pCode) {
|
||||
AreaMappingGlobalExample pExample = new AreaMappingGlobalExample();
|
||||
pExample.createCriteria().andProvinceCodeEqualTo(pCode);
|
||||
return MapUtils.selectByExample(pExample).stream().findFirst().get();
|
||||
}
|
||||
|
||||
private AreaMappingGlobal city(String pCode) {
|
||||
AreaMappingGlobalExample pExample = new AreaMappingGlobalExample();
|
||||
pExample.createCriteria().andCityCodeEqualTo(pCode);
|
||||
return MapUtils.selectByExample(pExample).stream().findFirst().get();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package io.dataease.map.service;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import io.dataease.plugins.common.base.domain.ChartView;
|
||||
import io.dataease.plugins.common.base.domain.ChartViewExample;
|
||||
import io.dataease.plugins.common.base.domain.ChartViewWithBLOBs;
|
||||
import io.dataease.plugins.common.base.mapper.ChartViewMapper;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class MapTransferService {
|
||||
|
||||
@Value("${geo.rootpath:/opt/dataease/data/feature/}")
|
||||
private String geoPath;
|
||||
|
||||
private static final List<String> MATCH_TYPES = new ArrayList<>();
|
||||
private static final Gson gson = new Gson();
|
||||
private static final String AREA_CODE_KEY = "areaCode";
|
||||
private static final String GLOBAL_CHINA_PREFIX = "156";
|
||||
|
||||
private static final String FILE_SEPARATOR = "/";
|
||||
private static final String FULL_KEY = "full";
|
||||
private static final String BORDER_KEY = "border";
|
||||
|
||||
private static final String FULL_FILE_SUFFIX = "_full.json";
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
MATCH_TYPES.add("map");
|
||||
MATCH_TYPES.add("buddle-map");
|
||||
}
|
||||
@Resource
|
||||
private ChartViewMapper chartViewMapper;
|
||||
|
||||
|
||||
|
||||
public void execute() {
|
||||
ChartViewExample example = new ChartViewExample();
|
||||
List<ChartViewWithBLOBs> chartViews = chartViewMapper.selectByExampleWithBLOBs(example);
|
||||
chartViews.forEach(view -> {
|
||||
if (typeMatch(view) && StringUtils.isNotBlank(view.getCustomAttr())) {
|
||||
Map<String, Object> customAttrMap = convert(view.getCustomAttr());
|
||||
if (customMatch(customAttrMap)) {
|
||||
view.setCustomAttr(gson.toJson(customAttrMap));
|
||||
chartViewMapper.updateByPrimaryKeyWithBLOBs(view);
|
||||
}
|
||||
}
|
||||
});
|
||||
moveMapFiles();
|
||||
}
|
||||
|
||||
public void moveMapFiles() {
|
||||
String chinaRootPath = geoPath + FULL_KEY + FILE_SEPARATOR;
|
||||
File chinaRootDir = new File(chinaRootPath);
|
||||
File[] files = chinaRootDir.listFiles();
|
||||
Map<String, List<File>> listMap = Arrays.stream(files).filter(FileUtil::isFile).collect(Collectors.groupingBy(this::fileType));
|
||||
if (ObjectUtils.isEmpty(listMap)) return;
|
||||
moveFiles(listMap, BORDER_KEY);
|
||||
moveFiles(listMap, FULL_KEY);
|
||||
}
|
||||
|
||||
private void moveFiles(Map<String, List<File>> listMap, String fileType) {
|
||||
String dirPath = geoPath + fileType + FILE_SEPARATOR;
|
||||
Optional.ofNullable(listMap.get(fileType)).ifPresent(files -> {
|
||||
files.forEach(file -> {
|
||||
String fileName = file.getName();
|
||||
String newFilePath = dirPath + GLOBAL_CHINA_PREFIX + FILE_SEPARATOR + GLOBAL_CHINA_PREFIX + fileName;
|
||||
FileUtil.move(file, new File(newFilePath), true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private String fileType(File file) {
|
||||
return file.getName().endsWith(FULL_FILE_SUFFIX) ? FULL_KEY : BORDER_KEY;
|
||||
}
|
||||
|
||||
private Boolean typeMatch(ChartView chartView) {
|
||||
return MATCH_TYPES.stream().anyMatch(type -> StringUtils.equals(type, chartView.getType()));
|
||||
}
|
||||
|
||||
private Map<String, Object> convert(String customJson) {
|
||||
return gson.fromJson(customJson, Map.class);
|
||||
}
|
||||
|
||||
private Boolean customMatch(Map<String, Object> customAttrMap) {
|
||||
Object codeObj = null;
|
||||
if((codeObj = customAttrMap.get(AREA_CODE_KEY)) != null) {
|
||||
String code = codeObj.toString();
|
||||
boolean matych = code.length() == 6;
|
||||
customAttrMap.put(AREA_CODE_KEY, GLOBAL_CHINA_PREFIX + code);
|
||||
return matych;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -46,6 +46,15 @@ public class MapUtils {
|
||||
return mappingGlobals;
|
||||
}
|
||||
|
||||
public static List<AreaMappingGlobal> selectByExample(AreaMappingGlobalExample example) {
|
||||
List<AreaMappingGlobal> mappingGlobals = areaMappingGlobalMapper.selectByExample(Optional.ofNullable(example).orElse(new AreaMappingGlobalExample()));
|
||||
return mappingGlobals;
|
||||
}
|
||||
|
||||
public static Boolean exampleExist(AreaMappingGlobalExample example) {
|
||||
return areaMappingGlobalMapper.countByExample(example) > 0;
|
||||
}
|
||||
|
||||
public static List<Map<String, Object>> readCodeList() {
|
||||
AreaMappingExample example = new AreaMappingExample();
|
||||
List<AreaMapping> areaMappings = areaMappingMapper.selectByExample(example);
|
||||
@ -75,30 +84,25 @@ public class MapUtils {
|
||||
String city_code = map.getCityCode();
|
||||
String county_code = map.getCountyCode();
|
||||
// 是否是跨级直辖
|
||||
Boolean isCrossLevel = StrUtil.equals(province_code, city_code)
|
||||
&& !StrUtil.equals(province_code, "156710000");
|
||||
Boolean isCrossLevel = StrUtil.equals(province_code, city_code) && !StrUtil.equals(province_code, "156710000");
|
||||
|
||||
if (!countryMap.containsKey(country_code)) {
|
||||
String country_name = map.getCountryName();
|
||||
AreaEntity child = AreaEntity.builder().code(country_code).name(country_name)
|
||||
.pcode(globalRoot.getCode()).build();
|
||||
|
||||
AreaEntity child = AreaEntity.builder().code(country_code).name(country_name).pcode(globalRoot.getCode()).build();
|
||||
countryMap.put(country_code, child);
|
||||
globalRoot.addChild(child);
|
||||
}
|
||||
|
||||
AreaEntity currentCountry = countryMap.get(country_code);
|
||||
|
||||
String province_name = map.getProvinceName();
|
||||
if (!provinceMap.containsKey(province_code)) {
|
||||
AreaEntity child = AreaEntity.builder().code(province_code).name(province_name)
|
||||
.pcode(currentCountry.getCode()).build();
|
||||
if (StringUtils.isNotBlank(province_code) && !provinceMap.containsKey(province_code)) {
|
||||
AreaEntity currentCountry = countryMap.get(country_code);
|
||||
String province_name = map.getProvinceName();
|
||||
AreaEntity child = AreaEntity.builder().code(province_code).name(province_name).pcode(currentCountry.getCode()).build();
|
||||
provinceMap.put(province_code, child);
|
||||
currentCountry.addChild(child);
|
||||
}
|
||||
|
||||
// 当前省
|
||||
AreaEntity currentProvince = provinceMap.get(province_code);
|
||||
|
||||
|
||||
String city_name = map.getCityName();
|
||||
if (isCrossLevel) {
|
||||
@ -106,8 +110,9 @@ public class MapUtils {
|
||||
city_name = map.getCountyName();
|
||||
}
|
||||
if (StringUtils.isNotBlank(city_code) && !cityMap.containsKey(city_code)) {
|
||||
AreaEntity child = AreaEntity.builder().code(city_code).name(city_name).pcode(currentProvince.getCode())
|
||||
.build();
|
||||
// 当前省
|
||||
AreaEntity currentProvince = provinceMap.get(province_code);
|
||||
AreaEntity child = AreaEntity.builder().code(city_code).name(city_name).pcode(currentProvince.getCode()).build();
|
||||
cityMap.put(city_code, child);
|
||||
currentProvince.addChild(child);
|
||||
}
|
||||
@ -199,4 +204,16 @@ public class MapUtils {
|
||||
return AreaEntity.builder().code("000000000").name("地球村").build();
|
||||
}
|
||||
|
||||
public static void addNode(AreaMappingGlobal node) {
|
||||
areaMappingGlobalMapper.insert(node);
|
||||
}
|
||||
|
||||
public static void update(AreaMappingGlobal node) {
|
||||
areaMappingGlobalMapper.updateByPrimaryKey(node);
|
||||
}
|
||||
|
||||
public static void deleteByExample(AreaMappingGlobalExample example) {
|
||||
areaMappingGlobalMapper.deleteByExample(Optional.ofNullable(example).orElse(new AreaMappingGlobalExample()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,4 +36,31 @@ ADD COLUMN `phone_prefix` varchar(255) NULL COMMENT '手机号前缀' AFTER `sub
|
||||
INSERT INTO `my_plugin` (`name`, `store`, `free`, `cost`, `category`, `descript`, `version`, `creator`, `load_mybatis`,
|
||||
`install_time`, `module_name`, `ds_type`)
|
||||
VALUES ('Mongo 数据源插件', 'default', '0', '0', 'datasource', 'Mongo 数据源插件', '1.0-SNAPSHOT', 'DATAEASE', '0',
|
||||
'1650765903630', 'mongo-backend', 'mongobi');
|
||||
'1650765903630', 'mongo-backend', 'mongobi');
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `area_mapping_global`;
|
||||
CREATE TABLE `area_mapping_global` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`country_code` varchar(255) DEFAULT NULL COMMENT '国家代码',
|
||||
`country_name` varchar(255) DEFAULT NULL COMMENT '国家名称',
|
||||
`province_name` varchar(255) DEFAULT NULL COMMENT '省名称',
|
||||
`province_code` varchar(255) DEFAULT NULL COMMENT '省代码',
|
||||
`city_name` varchar(255) DEFAULT NULL COMMENT '市名称',
|
||||
`city_code` varchar(255) DEFAULT NULL COMMENT '市代码',
|
||||
`county_name` varchar(255) DEFAULT NULL COMMENT '县名称',
|
||||
`county_code` varchar(255) DEFAULT NULL COMMENT '县代码',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
|
||||
BEGIN;
|
||||
insert into area_mapping_global (province_code, province_name, city_code, city_name, county_code, county_name)
|
||||
select province_code, province_name, city_code, city_name, county_code, county_name from area_mapping;
|
||||
|
||||
update area_mapping_global set
|
||||
country_code = '156100000',
|
||||
country_name = '中华人民共和国',
|
||||
province_code = concat('156', province_code),
|
||||
city_code = concat('156', city_code),
|
||||
county_code = concat('156', county_code);
|
||||
COMMIT;
|
@ -138,6 +138,15 @@
|
||||
diskPersistent="false"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="sys_map_areas_global"
|
||||
eternal="true"
|
||||
maxElementsInMemory="100"
|
||||
maxElementsOnDisk="3000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="false"
|
||||
/>
|
||||
|
||||
|
||||
<!--用户授权数据源缓存-->
|
||||
<cache
|
||||
|
@ -62,6 +62,7 @@
|
||||
"vue-friendly-iframe": "^0.20.0",
|
||||
"vue-fullscreen": "^2.5.2",
|
||||
"vue-i18n": "7.3.2",
|
||||
"vue-json-views": "^1.3.0",
|
||||
"vue-proportion-directive": "^1.1.0",
|
||||
"vue-router": "3.0.6",
|
||||
"vue-to-pdf": "^1.0.0",
|
||||
|
@ -2,7 +2,7 @@ import request from '@/utils/request'
|
||||
|
||||
export const areaMapping = () => {
|
||||
return request({
|
||||
url: '/api/map/areaEntitys/0',
|
||||
url: '/api/map/globalEntitys/0',
|
||||
method: 'get',
|
||||
loading: true
|
||||
})
|
||||
@ -17,9 +17,28 @@ export const globalMapping = () => {
|
||||
}
|
||||
|
||||
export function geoJson(areaCode) {
|
||||
const countryCode = areaCode.substring(0, 3)
|
||||
return request({
|
||||
url: '/geo/' + areaCode + '_full.json',
|
||||
url: '/geo/full/' + countryCode + '/' + areaCode + '_full.json',
|
||||
method: 'get',
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
export function saveMap(data) {
|
||||
return request({
|
||||
url: '/api/map/saveMapNode',
|
||||
method: 'post',
|
||||
loading: true,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function removeMap(data) {
|
||||
return request({
|
||||
url: '/api/map/delMapNode',
|
||||
method: 'post',
|
||||
loading: true,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
@ -475,7 +475,8 @@ export default {
|
||||
ldap: 'LDAP Setting',
|
||||
oidc: 'OIDC Setting',
|
||||
theme: 'Theme Setting',
|
||||
cas: 'CAS Setting'
|
||||
cas: 'CAS Setting',
|
||||
map: 'MAP Setting'
|
||||
},
|
||||
license: {
|
||||
i18n_no_license_record: 'No License Record',
|
||||
@ -2130,5 +2131,19 @@ export default {
|
||||
},
|
||||
plugin_style: {
|
||||
border: 'Border'
|
||||
},
|
||||
|
||||
map_setting: {
|
||||
area_level: 'Area Level',
|
||||
area_code: 'Area Code',
|
||||
please_input: 'please key',
|
||||
parent_area: 'Parent Area',
|
||||
area_code_tip: 'The format of area code is 9 digits',
|
||||
area_name: 'Area Name',
|
||||
parent_name: 'Parent Area',
|
||||
geo_json: 'Geo Json',
|
||||
fileplaceholder: 'Please upload the JSON format coordinate file',
|
||||
delete_confirm: 'And child nodes will be deleted. Confirm to execute ?',
|
||||
cur_node: 'Current node'
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +475,8 @@ export default {
|
||||
ldap: 'LDAP設置',
|
||||
oidc: 'OIDC設置',
|
||||
theme: '主題設置',
|
||||
cas: 'CAS設置'
|
||||
cas: 'CAS設置',
|
||||
map: '地圖設置'
|
||||
},
|
||||
license: {
|
||||
i18n_no_license_record: '沒有 License 記錄',
|
||||
@ -2141,5 +2142,18 @@ export default {
|
||||
},
|
||||
plugin_style: {
|
||||
border: '邊框'
|
||||
},
|
||||
map_setting: {
|
||||
area_level: '區域等級',
|
||||
area_code: '區域代碼',
|
||||
please_input: '請填寫',
|
||||
parent_area: '上級區域',
|
||||
area_code_tip: '區域代碼格式為9位數字',
|
||||
area_name: '區域名稱',
|
||||
parent_name: '上級區域',
|
||||
geo_json: '坐標文件',
|
||||
fileplaceholder: '請上傳json格式坐標文件',
|
||||
delete_confirm: '及子節點都會被刪除,確認執行?',
|
||||
cur_node: '當前節點'
|
||||
}
|
||||
}
|
||||
|
@ -476,7 +476,8 @@ export default {
|
||||
ldap: 'LDAP设置',
|
||||
oidc: 'OIDC设置',
|
||||
theme: '主题设置',
|
||||
cas: 'CAS设置'
|
||||
cas: 'CAS设置',
|
||||
map: '地图设置'
|
||||
},
|
||||
license: {
|
||||
i18n_no_license_record: '没有 License 记录',
|
||||
@ -2153,5 +2154,18 @@ export default {
|
||||
},
|
||||
sql_variable: {
|
||||
variable_mgm: '参数设置'
|
||||
},
|
||||
map_setting: {
|
||||
area_level: '区域等级',
|
||||
area_code: '区域代码',
|
||||
please_input: '请填写',
|
||||
parent_area: '上级区域',
|
||||
area_code_tip: '区域代码格式为9位数字',
|
||||
area_name: '区域名称',
|
||||
parent_name: '上级区域',
|
||||
geo_json: '坐标文件',
|
||||
fileplaceholder: '请上传json格式坐标文件',
|
||||
delete_confirm: '及子节点都会被删除,确认执行?',
|
||||
cur_node: '当前节点'
|
||||
}
|
||||
}
|
||||
|
259
frontend/src/views/system/SysParam/MapSetting/MapSettingLeft.vue
Normal file
259
frontend/src/views/system/SysParam/MapSetting/MapSettingLeft.vue
Normal file
@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<el-col class="tree-style">
|
||||
<el-col>
|
||||
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
size="mini"
|
||||
:placeholder="$t('commons.search')"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
class="main-area-input"
|
||||
/>
|
||||
|
||||
</el-row>
|
||||
|
||||
<el-col class="custom-tree-container">
|
||||
<div class="block">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
class="filter-tree"
|
||||
:data="treeDatas"
|
||||
:props="defaultProps"
|
||||
:filter-node-method="filterNode"
|
||||
:expand-on-click-node="false"
|
||||
node-key="code"
|
||||
:accordion="true"
|
||||
highlight-current
|
||||
:default-expanded-keys="expandedKeys"
|
||||
@current-change="nodeClick"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node father">
|
||||
<span style="display: flex;flex: 1;width: 0;">
|
||||
|
||||
<span style="margin-left: 6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" :title="data.name">{{ node.data.name }}</span>
|
||||
</span>
|
||||
<span v-if="!data.code.startWith('156')" class="child">
|
||||
<span @click.stop>
|
||||
<span class="el-dropdown-link">
|
||||
<el-button
|
||||
icon="el-icon-plus"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="addHandler(data, node)"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<span v-if="!data.code.startWith('000')" style="margin-left: 12px;" @click.stop>
|
||||
<span class="el-dropdown-link">
|
||||
<el-button
|
||||
icon="el-icon-delete"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="removeHandler(data, node)"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
|
||||
</el-col>
|
||||
|
||||
</el-col>
|
||||
|
||||
</el-col>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { removeMap } from '@/api/map/map'
|
||||
export default {
|
||||
name: 'MapSettingLeft',
|
||||
props: {
|
||||
treeDatas: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterText: '',
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
},
|
||||
data: [],
|
||||
expandedKeys: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.label.indexOf(value) !== -1
|
||||
},
|
||||
|
||||
nodeClick(data, node) {
|
||||
let parent = null
|
||||
if (node.parent.data instanceof Array) {
|
||||
parent = node.parent.data[0]
|
||||
} else {
|
||||
parent = node.parent.data
|
||||
}
|
||||
const nodeInfo = {
|
||||
code: data.code,
|
||||
name: data.name,
|
||||
pcode: data.pcode,
|
||||
pname: parent.name
|
||||
}
|
||||
this.$emit('show-node-info', this.setStatus(nodeInfo, 'read-only'))
|
||||
},
|
||||
addHandler(data, node) {
|
||||
let form = {
|
||||
pLevel: node.level,
|
||||
pCode: data.code
|
||||
}
|
||||
if (node.level > 4) {
|
||||
this.$error('不支持4级行政级别')
|
||||
form = {}
|
||||
}
|
||||
this.$emit('emit-add', this.setStatus(form, 'add'))
|
||||
},
|
||||
removeHandler(data, node) {
|
||||
let parent = null
|
||||
if (node.parent.data instanceof Array) {
|
||||
parent = node.parent.data[0]
|
||||
} else {
|
||||
parent = node.parent.data
|
||||
}
|
||||
const param = {
|
||||
code: data.code,
|
||||
pcode: parent.code,
|
||||
plevel: node.parent.level,
|
||||
name: data.name
|
||||
}
|
||||
const msg = this.$t('map_setting.cur_node') + '[' + data.name + ']' + this.$t('map_setting.delete_confirm')
|
||||
this.$confirm(msg, '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
removeMap(param).then(res => {
|
||||
this.$emit('refresh-tree')
|
||||
this.$success(this.$t('commons.delete_success'))
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$info(this.$t('commons.delete_cancel'))
|
||||
})
|
||||
},
|
||||
setStatus(data, status) {
|
||||
const form = JSON.parse(JSON.stringify(data))
|
||||
return Object.assign(form, {
|
||||
status: status || 'read-only'
|
||||
})
|
||||
},
|
||||
showNewNode(code) {
|
||||
this.$refs.tree.setCurrentKey(code)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-divider--horizontal {
|
||||
margin: 12px 0
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.custom-tree-container{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.tree-list>>>.el-tree-node__expand-icon.is-leaf{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right:8px;
|
||||
}
|
||||
|
||||
.custom-tree-node-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding:0 8px;
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.title-css {
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.scene-title{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
.scene-title-name{
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.father .child {
|
||||
visibility: hidden;
|
||||
}
|
||||
.father:hover .child {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.dialog-css >>> .el-dialog__body {
|
||||
padding: 10px 20px 20px;
|
||||
}
|
||||
|
||||
.inner-dropdown-menu{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%
|
||||
}
|
||||
.tree-style {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,349 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-empty v-if="status === 'empty'" description="请在左侧选择区域" />
|
||||
|
||||
<el-descriptions v-else-if="status === 'read-only'" title="区域信息" :column="1">
|
||||
|
||||
<el-descriptions-item :label="$t('map_setting.area_code')">{{ nodeInfo.code }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :label="$t('map_setting.area_name')">{{ nodeInfo.name }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :label="$t('map_setting.parent_name')">{{ nodeInfo.pname }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :label="$t('map_setting.geo_json')">
|
||||
<json-view :data="json" />
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<!--基础配置表单-->
|
||||
<el-form
|
||||
v-else
|
||||
ref="formInline"
|
||||
v-loading="loading"
|
||||
:model="formInline"
|
||||
:rules="rules"
|
||||
class="demo-form-inline"
|
||||
size="small"
|
||||
>
|
||||
<el-input v-show="false" v-model="formInline.pLevel" />
|
||||
|
||||
<el-row>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form-item :label="$t('map_setting.parent_area')" prop="pCode">
|
||||
<el-tree-select
|
||||
v-if="treeShow"
|
||||
ref="deSelectTree"
|
||||
v-model="formInline.pCode"
|
||||
popover-class="test-class-wrap"
|
||||
:data="treeDatas"
|
||||
:select-params="selectParams"
|
||||
:tree-params="treeParams"
|
||||
:filter-node-method="_filterFun"
|
||||
:tree-render-fun="_renderFun"
|
||||
@searchFun="_searchFun"
|
||||
@node-click="changeNode"
|
||||
@select-clear="selectClear"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form-item :label="$t('map_setting.area_code')" prop="code">
|
||||
<el-input v-model="formInline.code" :placeholder="$t('map_setting.please_input')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form-item :label="$t('map_setting.area_name')" prop="name">
|
||||
<el-input v-model="formInline.name" maxlength="30" show-word-limit :placeholder="$t('map_setting.please_input')" />
|
||||
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form-item :label="$t('map_setting.geo_json')">
|
||||
<el-upload
|
||||
style="float: right;margin-left: 10px"
|
||||
class="upload-demo"
|
||||
action=""
|
||||
accept=".json"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="uploadValidate"
|
||||
:on-error="handleError"
|
||||
:show-file-list="false"
|
||||
:file-list="filesTmp"
|
||||
:http-request="uploadMapFile"
|
||||
>
|
||||
<el-button style="display: inline-block" size="mini" type="success" plain>
|
||||
{{ $t('commons.upload') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button
|
||||
style="float:right;margin-top: 3px"
|
||||
size="mini"
|
||||
type="danger"
|
||||
plain
|
||||
@click="removeFile"
|
||||
>
|
||||
{{ $t('commons.clear') }}
|
||||
</el-button>
|
||||
<el-input
|
||||
v-model="formInline.fileName"
|
||||
:disabled="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div>
|
||||
|
||||
<el-button type="success" size="small" @click="save('formInline')">
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import jsonView from 'vue-json-views'
|
||||
import { geoJson, saveMap } from '@/api/map/map'
|
||||
import ElTreeSelect from '@/components/ElTreeSelect'
|
||||
|
||||
export default {
|
||||
name: 'MapSettingRight',
|
||||
components: { jsonView, ElTreeSelect },
|
||||
props: {
|
||||
status: {
|
||||
type: String,
|
||||
default: 'empty'
|
||||
},
|
||||
treeDatas: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formInline: { pCode: '' },
|
||||
loading: false,
|
||||
rules: {
|
||||
pCode: [
|
||||
{ required: true, message: this.$t('map_setting.parent_name') + this.$t('commons.cannot_be_null'), trigger: 'change' }
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: this.$t('map_setting.area_code') + this.$t('commons.cannot_be_null'), trigger: ['change', 'blur'] },
|
||||
{ pattern: /^\d{9}$/, message: this.$t('map_setting.area_code_tip'), trigger: ['change', 'blur'] }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: this.$t('map_setting.area_name') + this.$t('commons.cannot_be_null'), trigger: ['change', 'blur'] }
|
||||
],
|
||||
fileName: [
|
||||
{ required: true, message: this.$t('map_setting.geo_json') + this.$t('commons.cannot_be_null'), trigger: 'change' }
|
||||
]
|
||||
},
|
||||
levelOptions: [
|
||||
{ value: 1, label: '国家' },
|
||||
{ value: 2, label: '一级行政区划(省)' },
|
||||
{ value: 3, label: '二级行政区划(市)' },
|
||||
{ value: 4, label: '三级行政区划(区县)' },
|
||||
{ value: 5, label: '四级行政区划(乡镇)' }
|
||||
],
|
||||
suffixes: new Set(['json']),
|
||||
errList: [],
|
||||
filesTmp: [],
|
||||
|
||||
nodeInfo: {
|
||||
code: -1,
|
||||
name: '',
|
||||
level: -1,
|
||||
pcode: -1,
|
||||
pname: ''
|
||||
},
|
||||
noGsoJson: { success: false, message: 'no json file' },
|
||||
json: {},
|
||||
selectParams: {
|
||||
clearable: true,
|
||||
placeholder: this.$t('commons.please_select') + this.$t('map_setting.parent_name')
|
||||
},
|
||||
treeParams: {
|
||||
showParent: true,
|
||||
clickParent: true,
|
||||
filterable: true,
|
||||
// 只想要子节点,不需要父节点
|
||||
leafOnly: false,
|
||||
includeHalfChecked: false,
|
||||
'check-strictly': false,
|
||||
'default-expand-all': false,
|
||||
'expand-on-click-node': false,
|
||||
'render-content': this._renderFun,
|
||||
data: [],
|
||||
props: {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
rootId: '000000000',
|
||||
disabled: 'disabled',
|
||||
parentId: 'pcode',
|
||||
value: 'code'
|
||||
}
|
||||
},
|
||||
treeShow: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
treeDatas: function(val) {
|
||||
this.treeParams.data = val
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.query()
|
||||
},
|
||||
methods: {
|
||||
handleExceed(files, fileList) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'))
|
||||
},
|
||||
handleError() {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'))
|
||||
},
|
||||
uploadValidate(file) {
|
||||
const suffix = file.name.substring(file.name.lastIndexOf('.') + 1)
|
||||
if (!this.suffixes.has(suffix)) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_format'))
|
||||
return false
|
||||
}
|
||||
|
||||
if (file.size / 1024 / 1024 > 30) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_size'))
|
||||
return false
|
||||
}
|
||||
this.errList = []
|
||||
return true
|
||||
},
|
||||
uploadMapFile(file) {
|
||||
this.formInline.fileName = file.file.name
|
||||
this.formInline.file = file.file
|
||||
},
|
||||
removeFile() {
|
||||
this.formInline.fileName = null
|
||||
this.formInline.file = null
|
||||
},
|
||||
buildFormData(file, files, param) {
|
||||
const formData = new FormData()
|
||||
if (file) {
|
||||
formData.append('file', file)
|
||||
}
|
||||
if (files) {
|
||||
files.forEach(f => {
|
||||
formData.append('files', f)
|
||||
})
|
||||
}
|
||||
formData.append('request', new Blob([JSON.stringify(param)], { type: 'application/json' }))
|
||||
return formData
|
||||
},
|
||||
save(formInline) {
|
||||
const param = {
|
||||
code: this.formInline.code,
|
||||
name: this.formInline.name,
|
||||
pcode: this.formInline.pCode,
|
||||
plevel: this.formInline.pLevel
|
||||
}
|
||||
|
||||
this.$refs[formInline].validate(valid => {
|
||||
if (valid) {
|
||||
this.saveHandler(param)
|
||||
} else {
|
||||
// this.result = false
|
||||
}
|
||||
})
|
||||
},
|
||||
saveHandler(param) {
|
||||
const formData = this.buildFormData(this.formInline.file, null, param)
|
||||
saveMap(formData).then(response => {
|
||||
const flag = response.success
|
||||
if (flag) {
|
||||
this.$emit('refresh-tree', param)
|
||||
this.$success(this.$t('commons.save_success'))
|
||||
} else {
|
||||
this.$message.error(this.$t('commons.save_failed'))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
emitAdd(form) {
|
||||
this.formInline = JSON.parse(JSON.stringify(form))
|
||||
this.treeShow = false
|
||||
this.$nextTick(() => {
|
||||
this.treeShow = true
|
||||
})
|
||||
},
|
||||
|
||||
loadForm(form) {
|
||||
if (form && form.code) {
|
||||
this.nodeInfo = JSON.parse(JSON.stringify(form))
|
||||
this.setGeoJson()
|
||||
}
|
||||
},
|
||||
setGeoJson() {
|
||||
if (!this.nodeInfo || !this.nodeInfo.code) {
|
||||
this.json = JSON.parse(JSON.stringify(this.noGsoJson))
|
||||
return
|
||||
}
|
||||
const cCode = this.nodeInfo.code
|
||||
if (this.$store.getters.geoMap[cCode]) {
|
||||
const json = this.$store.getters.geoMap[cCode]
|
||||
this.json = JSON.parse(JSON.stringify(json))
|
||||
return
|
||||
}
|
||||
|
||||
geoJson(cCode).then(res => {
|
||||
this.$store.dispatch('map/setGeo', {
|
||||
key: cCode,
|
||||
value: res
|
||||
}).then(() => {
|
||||
this.json = JSON.parse(JSON.stringify(res))
|
||||
})
|
||||
})
|
||||
},
|
||||
_filterFun(value, data, node) {
|
||||
if (!value) return true
|
||||
return data.id.toString().indexOf(value.toString()) !== -1
|
||||
},
|
||||
// 树点击
|
||||
_nodeClickFun(data, node, vm) {
|
||||
},
|
||||
// 树过滤
|
||||
_searchFun(value) {
|
||||
this.$refs.deSelectTree.filterFun(value)
|
||||
},
|
||||
// 自定义render
|
||||
_renderFun(h, { node, data, store }) {
|
||||
const { props, clickParent } = this.treeParams
|
||||
return (
|
||||
<span class={['custom-tree-node', !clickParent && data[props.children] && data[props.children].length ? 'disabled' : null]}>
|
||||
<span>{node.label}</span>
|
||||
</span>
|
||||
)
|
||||
},
|
||||
changeNode(data, node) {
|
||||
if (node.level > 4) {
|
||||
this.$error('不支持4级行政级别')
|
||||
this.formInline.pLevel = null
|
||||
this.formInline.pCode = null
|
||||
return
|
||||
}
|
||||
this.formInline.pLevel = node.level
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
66
frontend/src/views/system/SysParam/MapSetting/index.vue
Normal file
66
frontend/src/views/system/SysParam/MapSetting/index.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<de-container v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<de-aside-container type="mapset">
|
||||
<map-setting-left ref="map_setting_tree" :tree-datas="treeDatas" @emit-add="emitAdd" @refresh-tree="refreshTree" @show-node-info="loadForm" />
|
||||
</de-aside-container>
|
||||
|
||||
<de-main-container>
|
||||
<map-setting-right ref="map_setting_form" :tree-datas="treeDatas" :status="formStatus" @refresh-tree="refreshTree" />
|
||||
</de-main-container>
|
||||
</de-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DeMainContainer from '@/components/dataease/DeMainContainer'
|
||||
import DeContainer from '@/components/dataease/DeContainer'
|
||||
import DeAsideContainer from '@/components/dataease/DeAsideContainer'
|
||||
import { areaMapping } from '@/api/map/map'
|
||||
import MapSettingLeft from './MapSettingLeft'
|
||||
import MapSettingRight from './MapSettingRight'
|
||||
export default {
|
||||
name: 'MapSetting',
|
||||
components: { DeMainContainer, DeContainer, DeAsideContainer, MapSettingLeft, MapSettingRight },
|
||||
data() {
|
||||
return {
|
||||
formStatus: 'empty',
|
||||
treeDatas: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadTreeData()
|
||||
},
|
||||
methods: {
|
||||
emitAdd(form) {
|
||||
this.setStatus(form.status)
|
||||
this.$refs && this.$refs['map_setting_form'] && this.$refs['map_setting_form'].emitAdd(form)
|
||||
},
|
||||
|
||||
loadForm(nodeInfo) {
|
||||
this.setStatus(nodeInfo.status)
|
||||
this.$refs && this.$refs['map_setting_form'] && this.$refs['map_setting_form'].loadForm(nodeInfo)
|
||||
},
|
||||
|
||||
setStatus(status) {
|
||||
this.formStatus = status
|
||||
},
|
||||
loadTreeData() {
|
||||
Object.keys(this.treeDatas).length === 0 && areaMapping().then(res => {
|
||||
this.treeDatas = res.data
|
||||
})
|
||||
},
|
||||
refreshTree(node) {
|
||||
areaMapping().then(res => {
|
||||
this.treeDatas = res.data
|
||||
if (node && node.code) {
|
||||
this.$refs && this.$refs['map_setting_tree'] && this.$refs['map_setting_tree'].showNewNode(node.code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
@ -42,11 +42,16 @@
|
||||
<plugin-com v-if="isPluginLoaded" ref="CasSetting" component-name="CasSetting" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :lazy="true" :label="$t('sysParams.map')" name="ten">
|
||||
<map-setting v-if="activeName === 'ten'" ref="mapSetting" />
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</layout-content>
|
||||
</template>
|
||||
<script>
|
||||
import BasicSetting from './BasicSetting'
|
||||
import MapSetting from './MapSetting'
|
||||
import EmailSetting from './EmailSetting'
|
||||
import SimpleMode from './SimpleModeSetting'
|
||||
import ClusterMode from './ClusterModeSetting'
|
||||
@ -57,7 +62,7 @@ import { pluginLoaded } from '@/api/user'
|
||||
import { engineMode } from '@/api/system/engine'
|
||||
export default {
|
||||
|
||||
components: { BasicSetting, EmailSetting, LayoutContent, PluginCom, SimpleMode, ClusterMode, KettleSetting },
|
||||
components: { BasicSetting, EmailSetting, LayoutContent, PluginCom, SimpleMode, ClusterMode, KettleSetting, MapSetting },
|
||||
data() {
|
||||
return {
|
||||
activeName: 'zero',
|
||||
|
1
mapFiles/full/000/000000000_full.json
Normal file
1
mapFiles/full/000/000000000_full.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user