mirror of
https://github.com/dataease/dataease.git
synced 2025-02-25 12:03:05 +08:00
Merge branch 'dev' of github.com:dataease/dataease into dev
This commit is contained in:
commit
e64d401025
@ -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.custom.rootpath:file:/opt/dataease/data/custom/}")
|
||||
private String geoPath;
|
||||
|
||||
@Override
|
||||
|
@ -4,6 +4,8 @@ import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.dataease.auth.annotation.DePermission;
|
||||
import io.dataease.auth.annotation.DePermissionProxy;
|
||||
import io.dataease.auth.annotation.DePermissions;
|
||||
import io.dataease.auth.service.impl.ExtAuthServiceImpl;
|
||||
import io.dataease.commons.constants.PanelConstants;
|
||||
import io.dataease.controller.request.panel.PanelGroupBaseInfoRequest;
|
||||
import io.dataease.plugins.common.base.domain.PanelGroup;
|
||||
import io.dataease.commons.constants.DePermissionType;
|
||||
@ -17,6 +19,7 @@ import io.dataease.dto.panel.PanelGroupDTO;
|
||||
import io.dataease.service.panel.PanelGroupService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.pentaho.di.core.util.UUIDUtil;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -39,6 +42,8 @@ public class PanelGroupController {
|
||||
|
||||
@Resource
|
||||
private PanelGroupService panelGroupService;
|
||||
@Resource
|
||||
private ExtAuthServiceImpl authService;
|
||||
|
||||
@ApiOperation("查询树")
|
||||
@PostMapping("/tree")
|
||||
@ -59,9 +64,15 @@ public class PanelGroupController {
|
||||
@DePermission(type = DePermissionType.PANEL, value = "pid", level = ResourceAuthLevel.PANNEL_LEVEL_MANAGE)
|
||||
}, logical = Logical.AND)
|
||||
@I18n
|
||||
public PanelGroup save(@RequestBody PanelGroupRequest request) throws Exception{
|
||||
public PanelGroupDTO save(@RequestBody PanelGroupRequest request) throws Exception{
|
||||
String panelId = panelGroupService.save(request);
|
||||
return findOne(panelId);
|
||||
PanelGroupDTO result = findOne(panelId);
|
||||
// 如果新建来源来自模板市场,在返回数据中加入父级ID便于跳转展开仪表板树
|
||||
if(PanelConstants.NEW_PANEL_FROM.NEW_MARKET_TEMPLATE.equals(request.getNewFrom())){
|
||||
result.setParents(authService.parentResource(panelId,"panel"));
|
||||
result.setRequestId(UUIDUtil.getUUIDAsString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("更新")
|
||||
|
@ -33,5 +33,8 @@ public class PanelGroupDTO extends PanelGroupWithBLOBs implements ITreeBase<Pane
|
||||
private List<PanelGroupDTO> children;
|
||||
@ApiModelProperty("视图信息")
|
||||
private List<Map<String, ChartViewDTO>> viewsInfo;
|
||||
|
||||
@ApiModelProperty("父级ID")
|
||||
private List<String> parents;
|
||||
@ApiModelProperty("请求ID")
|
||||
private String requestId;
|
||||
}
|
||||
|
@ -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,19 +1,35 @@
|
||||
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.beans.factory.annotation.Value;
|
||||
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 {
|
||||
|
||||
private static final String dirPath = "/opt/dataease/data/feature/";
|
||||
@Value("${geo.custom.rootpath:/opt/dataease/data/custom/}")
|
||||
private String rootGeoPath;
|
||||
|
||||
|
||||
@Cacheable("sys_map_areas")
|
||||
public List<AreaEntity> areaEntities() {
|
||||
@ -21,7 +37,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 +61,295 @@ 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 = rootGeoPath + "/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.getOriginalFilename();
|
||||
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 countryCode = areaCode.substring(0, 3);
|
||||
String dir = rootGeoPath + "full/" + countryCode + "/";
|
||||
File fileDir = new File(dir);
|
||||
if (!fileDir.exists()) {
|
||||
fileDir.mkdirs();
|
||||
}
|
||||
|
||||
String targetPath = dir + 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,134 @@
|
||||
package io.dataease.map.service;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
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;
|
||||
|
||||
|
||||
@Value("${geo.custom.rootpath:/opt/dataease/data/custom/}")
|
||||
private String customGeoPath;
|
||||
|
||||
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();
|
||||
if(ArrayUtil.isEmpty(files)) return;
|
||||
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);
|
||||
moveGlobalFile();
|
||||
|
||||
}
|
||||
|
||||
private void moveFiles(Map<String, List<File>> listMap, String fileType) {
|
||||
String dirPath = customGeoPath + 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), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void moveGlobalFile() {
|
||||
String fileName = "000000000" + FULL_FILE_SUFFIX;
|
||||
String sourcePath = geoPath + FULL_KEY + FILE_SEPARATOR + "000" + FILE_SEPARATOR + fileName;
|
||||
File sourceFile = new File(sourcePath);
|
||||
if (!sourceFile.exists()) return;
|
||||
|
||||
String targetDirPath = customGeoPath + FULL_KEY + FILE_SEPARATOR + "000" + FILE_SEPARATOR;
|
||||
File targetDir = new File(targetDirPath);
|
||||
if (!targetDir.exists()) {
|
||||
targetDir.mkdirs();
|
||||
}
|
||||
String targetPath = targetDirPath + fileName;
|
||||
|
||||
File targetFile = new File(targetPath);
|
||||
|
||||
FileUtil.move(sourceFile, targetFile, false);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (StringUtils.isNotBlank(province_code) && !provinceMap.containsKey(province_code)) {
|
||||
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();
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,5 +39,35 @@ VALUES ('Mongo 数据源插件', 'default', '0', '0', 'datasource', 'Mongo 数
|
||||
'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;
|
||||
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (202, 0, 0, 1, '模板市场', 'template-market', 'panel/templateMarket/index', 7, 'dashboard', '/templateMarket', 0, 0, 0, null, NULL, NULL, NULL, 1620444227389);
|
||||
|
||||
INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('basic.templateAccessKey', 'dataease', 'text', NULL);
|
||||
INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('basic.templateMarketUlr', 'https://dataease.io/templates', 'text', 4);
|
||||
|
||||
|
@ -138,6 +138,15 @@
|
||||
diskPersistent="false"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="sys_map_areas_global"
|
||||
eternal="true"
|
||||
maxElementsInMemory="100"
|
||||
maxElementsOnDisk="3000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="false"
|
||||
/>
|
||||
|
||||
|
||||
<!--用户授权数据源缓存-->
|
||||
<cache
|
||||
|
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
],
|
||||
plugins: ['@babel/plugin-proposal-optional-chaining']
|
||||
}
|
||||
|
@ -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",
|
||||
@ -75,6 +76,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.0-0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.18.6",
|
||||
"@babel/register": "7.0.0",
|
||||
"@vue/cli-plugin-babel": "3.6.0",
|
||||
"@vue/cli-plugin-eslint": "^3.9.1",
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
<script>
|
||||
import { uuid } from 'vue-uuid'
|
||||
import { get } from '@/api/system/dynamic'
|
||||
|
||||
export default {
|
||||
name: 'AsyncComponent',
|
||||
inheritAttrs: true,
|
||||
@ -45,13 +44,11 @@ export default {
|
||||
let res
|
||||
if (!window.SyncComponentCache[this.url]) {
|
||||
window.SyncComponentCache[this.url] = get(this.url)
|
||||
|
||||
// window.SyncComponentCache[this.url] = Axios.get(this.url)
|
||||
res = await window.SyncComponentCache[this.url]
|
||||
} else {
|
||||
res = await window.SyncComponentCache[this.url]
|
||||
}
|
||||
|
||||
const Fn = Function
|
||||
this.mode = new Fn(`return ${res.data || res}`)()
|
||||
/* if (res && res.data) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-icon name="back" class="back-button" @click.native="jump" />
|
||||
<i class="el-icon-arrow-left back-button" @click="jump" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -34,7 +34,7 @@ export default {
|
||||
|
||||
.back-button {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
margin-right: 18px;
|
||||
font-weight: 600;
|
||||
|
||||
&:active {
|
||||
|
82
frontend/src/components/business/DeLayoutContent.vue
Normal file
82
frontend/src/components/business/DeLayoutContent.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="layout-container">
|
||||
<p class="route-title">
|
||||
<back-button v-if="showBack" :path="backPath" :name="backName" :to="backTo" />
|
||||
<span>{{ routeTitle }}</span>
|
||||
</p>
|
||||
<div class="container-wrapper" :class="[isDept ? 'dept-padding' : '']">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BackButton from '@/components/back-button'
|
||||
|
||||
export default {
|
||||
name: 'DeLayoutContent',
|
||||
components: { BackButton },
|
||||
props: {
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
header: String,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
backPath: String,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
backName: String,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
backTo: Object
|
||||
},
|
||||
computed: {
|
||||
routeTitle() {
|
||||
return this.header || this.$route.meta?.title || ''
|
||||
},
|
||||
showBack({ backPath, backName, backTo }) {
|
||||
return backPath || backName || backTo
|
||||
},
|
||||
isDept() {
|
||||
return ['system-dept', 'system-dept-form'].includes(this.$route.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout-container {
|
||||
transition: 0.3s;
|
||||
background-color: var(--ContentBG);
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 14%);
|
||||
box-sizing: border-box;
|
||||
background: #f5f6f7;
|
||||
overflow: hidden;
|
||||
padding: 24px 24px 24px 24px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.route-title {
|
||||
font-family: PingFang SC;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
text-align: left;
|
||||
color: #1F2329;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.container-wrapper {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
background: #fff;
|
||||
margin-top: 24px;
|
||||
padding: 24px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dept-padding {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -5,7 +5,7 @@
|
||||
:style="{'margin-left': !asideHidden ? 0 : '-' + currentWidth}"
|
||||
>
|
||||
<slot />
|
||||
<de-horizontal-drag-bar v-if="showDragBar" :type="type" />
|
||||
<de-horizontal-drag-bar v-if="isSystem" :type="type" />
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
@ -20,6 +20,10 @@ export default {
|
||||
type: String,
|
||||
default: '260px'
|
||||
},
|
||||
isCollapseWidth: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
enableAsideHidden: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -28,6 +32,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isTemplate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null
|
||||
@ -40,7 +48,11 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
currentWidth() {
|
||||
return this.type && getLayout(this.type) || this.width
|
||||
return this.isCollapseWidth || this.type && getLayout(this.type) || this.width
|
||||
},
|
||||
isSystem() {
|
||||
// 系统管理不需要拖拽菜单
|
||||
return this.isTemplate || (!this.$route.fullPath.includes('system') && this.showDragBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,15 +62,19 @@ export default {
|
||||
|
||||
.ms-aside-container {
|
||||
/* border: 1px solid #E6E6E6; */
|
||||
padding: 10px;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--SiderBG, #FFF);
|
||||
height: calc(100vh - 56px);
|
||||
border-right: 0px;
|
||||
position: relative;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
/* .collapse-style {
|
||||
height: calc(100vh - 56px);
|
||||
} */
|
||||
|
||||
.hiddenBottom {
|
||||
width: 8px;
|
||||
height: 50px;
|
||||
|
223
frontend/src/components/gridTable/index.vue
Normal file
223
frontend/src/components/gridTable/index.vue
Normal file
@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<div class="flex-table">
|
||||
<el-table
|
||||
ref="table"
|
||||
v-bind="$attrs"
|
||||
v-on="tableEvent"
|
||||
height="2000"
|
||||
:data="tableData"
|
||||
:style="{ width: '100%' }"
|
||||
>
|
||||
<table-body :columns="columns">
|
||||
<slot></slot>
|
||||
</table-body>
|
||||
<slot name="__operation"></slot>
|
||||
</el-table>
|
||||
<div class="pagination-cont">
|
||||
<el-pagination
|
||||
background
|
||||
v-bind="paginationDefalut"
|
||||
v-on="paginationEvent"
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tableBody from "./tableBody";
|
||||
export default {
|
||||
components: { tableBody },
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
multipleSelection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
pagination: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
isRememberSelected: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
selectedFlags: {
|
||||
type: String,
|
||||
default: "id",
|
||||
},
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
paginationEvent: {},
|
||||
paginationDefalut: {
|
||||
currentPage: 1,
|
||||
pageSizes: [10, 20, 30, 40],
|
||||
pageSize: 10,
|
||||
layout: "total, prev, pager, next, sizes, jumper",
|
||||
total: 0,
|
||||
},
|
||||
multipleSelectionCach: [],
|
||||
tableEvent: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.handleListeners();
|
||||
},
|
||||
computed: {
|
||||
multipleSelectionAll() {
|
||||
return [...this.multipleSelectionCach, ...this.multipleSelection];
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
pagination: {
|
||||
handler() {
|
||||
this.paginationDefalut = {
|
||||
...this.paginationDefalut,
|
||||
...this.pagination,
|
||||
};
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
tableData: {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.table.doLayout();
|
||||
});
|
||||
if (!this.isRememberSelected) return;
|
||||
// 先拷贝 重新加载数据会触发SelectionChange 导致this.multipleSelection为空
|
||||
const multipleSelection = [...this.multipleSelection];
|
||||
this.$nextTick(() => {
|
||||
this.handlerSelected(multipleSelection);
|
||||
});
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
columns: {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.table.doLayout();
|
||||
});
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handlerSelected(multipleSelection) {
|
||||
this.multipleSelectionCach = [
|
||||
...this.multipleSelectionCach,
|
||||
...multipleSelection,
|
||||
];
|
||||
const flags = this.multipleSelectionCach.map(
|
||||
(ele) => ele[this.selectedFlags]
|
||||
);
|
||||
// 当前页的选中项索引
|
||||
const notCurrenArr = [];
|
||||
this.tableData.forEach((ele) => {
|
||||
const resultIndex = flags.indexOf(ele[this.selectedFlags]);
|
||||
if (resultIndex !== -1) {
|
||||
this.$refs.table.toggleRowSelection(ele, true);
|
||||
notCurrenArr.push(resultIndex);
|
||||
}
|
||||
});
|
||||
notCurrenArr.sort().reduceRight((pre, next) => {
|
||||
this.multipleSelectionCach.splice(next, 1);
|
||||
}, 0);
|
||||
},
|
||||
handleListeners() {
|
||||
Object.keys(this.$listeners).forEach((key) => {
|
||||
if (
|
||||
[
|
||||
"size-change",
|
||||
"current-change",
|
||||
"prev-click",
|
||||
"next-click",
|
||||
].includes(key)
|
||||
) {
|
||||
this.paginationEvent[key] = this.$listeners[key];
|
||||
} else {
|
||||
this.tableEvent[key] = this.$listeners[key];
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flex-table {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
::v-deep .el-table__header-wrapper {
|
||||
background-color: #f5f6f7;
|
||||
// border-top: 1px solid rgba(31, 35, 41, 0.15);
|
||||
}
|
||||
::v-deep .el-table__fixed-header-wrapper {
|
||||
th {
|
||||
background-color: var(--TableBG, #f5f6f7) !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-table__fixed-body-wrapper {
|
||||
tr {
|
||||
background-color: var(--TableBG, #ffffff) !important;
|
||||
}
|
||||
}
|
||||
.pagination-cont {
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
::v-deep .el-pager li {
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbbfc4;
|
||||
border-radius: 4px;
|
||||
color: #1f2329;
|
||||
box-sizing: border-box;
|
||||
line-height: 26px;
|
||||
font-family: SF Pro Text;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
::v-deep .btn-prev,
|
||||
::v-deep .btn-next {
|
||||
background: #fff;
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbbfc4;
|
||||
border-radius: 4px;
|
||||
color: #bbbfc4;
|
||||
}
|
||||
|
||||
::v-deep .el-pagination__total {
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #1f2329;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
::v-deep .number.active,
|
||||
::v-deep .el-input__inner:hover {
|
||||
border-color: #3370ff;
|
||||
color: #3370ff !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
::v-deep .el-icon-more {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
24
frontend/src/components/gridTable/tableBody.vue
Normal file
24
frontend/src/components/gridTable/tableBody.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
export default {
|
||||
name: "TableBody",
|
||||
functional: true,
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
render(h, context) {
|
||||
const nodes = [];
|
||||
const { columns } = context.props;
|
||||
const { children = [] } = context;
|
||||
if (!columns?.length) return children;
|
||||
children.forEach(ele => {
|
||||
if (columns.includes(ele.componentOptions.propsData.prop)) {
|
||||
nodes.push(ele)
|
||||
}
|
||||
})
|
||||
return nodes;
|
||||
},
|
||||
};
|
||||
</script>
|
2
frontend/src/icons/svg/button_right.svg
Normal file
2
frontend/src/icons/svg/button_right.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1658301542532" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="957" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
|
||||
</style></defs><path d="M-15.88624103 59.48859927h301.64928058c249.87872281 0 452.47392089 202.59519808 452.4739209 452.4739209S535.64176236 964.43644107 285.76303955 964.43644107H-15.88624103V59.48859927z" fill="#e6e6e6" p-id="958"></path><path d="M285.76303955 97.19475935H-15.88624103v829.53552164h301.64928058c229.06492245 0 414.76776082-185.70283837 414.76776081-414.76776082S514.82796201 97.19475935 285.76303955 97.19475935zM-15.88624103 59.48859927v904.9478418h301.64928058c249.87872281 0 452.47392089-202.59519808 452.4739209-452.4739209S535.64176236 59.48859927 285.76303955 59.48859927H-15.88624103z" fill="#e7e3e3" p-id="959"></path><path d="M113.40818187 377.31382255l134.46016681 134.46016682-134.46016681 134.42246066a9.42654002 9.42654002 0 0 0 0 13.34798068l13.31027449 13.3102745a9.42654002 9.42654002 0 0 0 13.34798065 0l147.8081475-147.77044133a18.85308003 18.85308003 0 0 0 0-26.65825517l-147.8081475-147.8081475a9.42654002 9.42654002 0 0 0-13.34798065 0l-13.31027449 13.34798069a9.42654002 9.42654002 0 0 0 0 13.34798065z" fill="#646A73" p-id="960"></path><path d="M280.93665106 377.31382255l134.42246066 134.46016682-134.42246066 134.42246066a9.42654002 9.42654002 0 0 0 0 13.34798068l13.3102745 13.3102745a9.42654002 9.42654002 0 0 0 13.34798068 0l147.80814749-147.77044133a18.85308003 18.85308003 0 0 0 0-26.65825517l-147.80814749-147.8081475a9.42654002 9.42654002 0 0 0-13.34798068 0l-13.3102745 13.34798069a9.42654002 9.42654002 0 0 0 0 13.34798065z" fill="#646A73" p-id="961"></path></svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -1 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618217742324" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7205" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 64C264.96 64 64 264.96 64 512s200.96 448 448 448 448-200.96 448-448S759.04 64 512 64z m0 831.712c-211.584 0-383.712-172.16-383.712-383.712 0-211.584 172.128-383.712 383.712-383.712 211.552 0 383.712 172.128 383.712 383.712 0 211.552-172.16 383.712-383.712 383.712z" p-id="7206"></path><path d="M671.968 512H512V288.064c0-17.76-14.24-32.128-32-32.128s-32 14.4-32 32.128V544c0 17.76 14.272 32 32 32h191.968c17.76 0 32.128-14.24 32.128-32s-14.368-32-32.128-32z" p-id="7207"></path></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.83301 1.33301C5.10915 1.33301 5.33301 1.55687 5.33301 1.83301V1.99967H10.6663V1.83301C10.6663 1.55687 10.8902 1.33301 11.1663 1.33301H11.4997C11.7758 1.33301 11.9997 1.55687 11.9997 1.83301V1.99967H13.9997C14.3679 1.99967 14.6663 2.29815 14.6663 2.66634V13.9997C14.6663 14.3679 14.3679 14.6663 13.9997 14.6663H1.99967C1.63148 14.6663 1.33301 14.3679 1.33301 13.9997L1.33301 2.66634C1.33301 2.29815 1.63148 1.99967 1.99967 1.99967H3.99967V1.83301C3.99967 1.55687 4.22353 1.33301 4.49967 1.33301H4.83301ZM10.6663 3.33301H5.33301V3.49967C5.33301 3.77582 5.10915 3.99967 4.83301 3.99967H4.49967C4.22353 3.99967 3.99967 3.77582 3.99967 3.49967V3.33301H2.66634V13.333H13.333V3.33301H11.9997V3.49967C11.9997 3.77582 11.7758 3.99967 11.4997 3.99967H11.1663C10.8902 3.99967 10.6663 3.77582 10.6663 3.49967V3.33301ZM5.99967 6.83301C5.99967 6.55687 5.77582 6.33301 5.49967 6.33301H4.49967C4.22353 6.33301 3.99967 6.55687 3.99967 6.83301V7.83301C3.99967 8.10915 4.22353 8.33301 4.49967 8.33301H5.49967C5.77582 8.33301 5.99967 8.10915 5.99967 7.83301V6.83301ZM6.99967 6.83301C6.99967 6.55687 7.22353 6.33301 7.49967 6.33301H8.49967C8.77582 6.33301 8.99967 6.55687 8.99967 6.83301V7.83301C8.99967 8.10915 8.77582 8.33301 8.49967 8.33301H7.49967C7.22353 8.33301 6.99967 8.10915 6.99967 7.83301V6.83301ZM5.99967 9.83301C5.99967 9.55687 5.77582 9.33301 5.49967 9.33301H4.49967C4.22353 9.33301 3.99967 9.55687 3.99967 9.83301V10.833C3.99967 11.1092 4.22353 11.333 4.49967 11.333H5.49967C5.77582 11.333 5.99967 11.1092 5.99967 10.833V9.83301ZM6.99967 9.83301C6.99967 9.55687 7.22353 9.33301 7.49967 9.33301H8.49967C8.77582 9.33301 8.99967 9.55687 8.99967 9.83301V10.833C8.99967 11.1092 8.77582 11.333 8.49967 11.333H7.49967C7.22353 11.333 6.99967 11.1092 6.99967 10.833V9.83301ZM11.9997 6.83301C11.9997 6.55687 11.7758 6.33301 11.4997 6.33301H10.4997C10.2235 6.33301 9.99967 6.55687 9.99967 6.83301V7.83301C9.99967 8.10915 10.2235 8.33301 10.4997 8.33301H11.4997C11.7758 8.33301 11.9997 8.10915 11.9997 7.83301V6.83301Z" fill="#3370FF"/>
|
||||
<path d="M11.9997 9.83301C11.9997 9.55687 11.7758 9.33301 11.4997 9.33301H10.4997C10.2235 9.33301 9.99967 9.55687 9.99967 9.83301V10.833C9.99967 11.1092 10.2235 11.333 10.4997 11.333H11.4997C11.7758 11.333 11.9997 11.1092 11.9997 10.833V9.83301Z" fill="#3370FF"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 867 B After Width: | Height: | Size: 2.3 KiB |
@ -131,9 +131,13 @@ export default {
|
||||
default_login: 'Normal'
|
||||
},
|
||||
commons: {
|
||||
manage_member: 'Managing members',
|
||||
user_confirm_remove_cancel:'Are you sure you want to remove the user from the role?',
|
||||
confirm_remove_cancel: 'Are you sure to delete the role?',
|
||||
default_value: 'Default Value',
|
||||
params_value: 'Param Value',
|
||||
publish: 'publish',
|
||||
input_role_name: 'Enter a role name',
|
||||
unpublished: 'unpublished',
|
||||
default_pwd: 'Default Pwd',
|
||||
stop: 'Stop',
|
||||
@ -159,6 +163,7 @@ export default {
|
||||
button: 'Button',
|
||||
man: 'Man',
|
||||
woman: 'Woman',
|
||||
keep_secret: 'keep secret',
|
||||
nick_name: 'Name',
|
||||
confirmPassword: 'Confirm Password',
|
||||
upload: 'Upload',
|
||||
@ -210,6 +215,8 @@ export default {
|
||||
member: 'Member',
|
||||
email: 'Email',
|
||||
phone: 'Phone',
|
||||
mobile_phone: 'Please enter your mobile phone number',
|
||||
mobile_phone_number: 'Phone number',
|
||||
role: 'Role',
|
||||
personal_info: 'Personal Info',
|
||||
api_keys: 'API Keys',
|
||||
@ -475,7 +482,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',
|
||||
@ -502,7 +510,7 @@ export default {
|
||||
please_choose_member: 'Please choose member',
|
||||
search_by_name: 'Search by name',
|
||||
modify_personal_info: 'Modify personal info',
|
||||
edit_password: 'Edit Password',
|
||||
edit_password: 'Reset Password',
|
||||
edit_information: 'Edit Information',
|
||||
input_name: 'Input Name',
|
||||
input_email: 'Input Email',
|
||||
@ -524,6 +532,12 @@ export default {
|
||||
modify: 'Modify User',
|
||||
input_name: 'Please enter user name',
|
||||
input_id: 'Please enter user ID',
|
||||
id_mandatory: 'id is mandatory',
|
||||
name_mandatory: 'name is mandatory',
|
||||
email_mandatory: 'email is mandatory',
|
||||
role_mandatory: 'role is mandatory',
|
||||
phone_format: 'mobile phone number format is incorrect',
|
||||
select_gender: 'Please select gender',
|
||||
input_email: 'Please input email',
|
||||
input_password: 'Please input a password',
|
||||
input_phone: 'Please enter the phone number',
|
||||
@ -535,7 +549,8 @@ export default {
|
||||
apikey_delete_confirm: 'Confirm to delete this API key?',
|
||||
input_id_placeholder: 'Please enter ID (Chinese is not supported)',
|
||||
source: 'User Source',
|
||||
choose_org: 'Choose Organization',
|
||||
choose_org: 'Please select a role',
|
||||
choose_role: '请选择角色',
|
||||
reset_password: 'Reset Password',
|
||||
current_user: 'Current User',
|
||||
origin_passwd: 'Origin Password',
|
||||
@ -600,7 +615,20 @@ export default {
|
||||
confirm_delete: 'Confirm delete role ',
|
||||
role_name: 'Role Name ',
|
||||
search_by_name: 'Search by name',
|
||||
pls_input_name: 'please input name'
|
||||
pls_input_name: 'please input name',
|
||||
search_by_name_email: 'Search by name or email',
|
||||
api_role: 'API role',
|
||||
role_exist: 'Failed to add, the role already exists',
|
||||
add_api_role: 'Add API role',
|
||||
can_not_move: `Can't be removed, keep at least one administrator`,
|
||||
manage_can_not_move: 'Administrator is a preset role of the system. By default, he has all the permissions of system management and cannot be deleted',
|
||||
manage_can_not_update: 'Administrator is a preset role of the system. By default, he has all the permissions of system management and cannot be edit',
|
||||
role_name: 'Role name',
|
||||
role_description: 'Role description',
|
||||
editer_role: 'Edit role',
|
||||
add_role: 'Add role',
|
||||
role_name_exist: 'The role name already exists',
|
||||
search_by_role: 'Search by role name',
|
||||
},
|
||||
menu: {
|
||||
parent_category: 'Parent Category',
|
||||
@ -635,7 +663,26 @@ export default {
|
||||
select_organization: 'Please select organization',
|
||||
search_by_name: 'Search by name',
|
||||
special_characters_are_not_supported: 'Format error (special characters are not supported and cannot start and end with \'-\')',
|
||||
select: 'Select organization'
|
||||
select: 'Select organization',
|
||||
member: 'member',
|
||||
organization: 'organization',
|
||||
add_user: 'Add user',
|
||||
search_by_name: 'Search by organization name',
|
||||
sure_move_user: 'Are you sure to remove this user from the organization?',
|
||||
move_success: 'Removed successfully',
|
||||
user: 'user',
|
||||
add_organization: 'Add organization',
|
||||
defalut_organization_canot_move: 'The default organization cannot be deleted',
|
||||
organization_name: 'Organization name',
|
||||
input_organization_name: 'Please enter the organization name',
|
||||
relate_top_organization: 'Associated parent organization',
|
||||
organization_name_exist: 'Organization name already exists',
|
||||
canot_delete: 'Cannot delete',
|
||||
remove_user_first: 'Please remove all users in the organization before deleting the organization',
|
||||
sure_delete_organization: 'Are you sure to delete this organization?',
|
||||
delete: 'delete',
|
||||
add_child_org: 'Add sub organization',
|
||||
edite_organization: 'Edit organization',
|
||||
},
|
||||
system_parameter_setting: {
|
||||
mailbox_service_settings: 'Mail Settings',
|
||||
@ -1499,6 +1546,10 @@ export default {
|
||||
sure_bt: 'Confirm'
|
||||
},
|
||||
panel: {
|
||||
template_market: 'Template Market',
|
||||
template_preview: 'Template Preview',
|
||||
apply: 'Apply',
|
||||
apply_this_template: 'Apply This Template',
|
||||
market_network_tips: 'View template Market template requires server and template Market( https://dataease.io/templates ), please check the network... ',
|
||||
enter_name_tips: 'Please enter the name of the panel',
|
||||
name: 'Name',
|
||||
@ -1829,6 +1880,7 @@ export default {
|
||||
dept: 'Dept',
|
||||
role: 'Role',
|
||||
user: 'User',
|
||||
set_rules: 'Set rules',
|
||||
sysParams_type: {
|
||||
user_id: 'User ID',
|
||||
user_name: 'User Name',
|
||||
@ -1852,7 +1904,34 @@ export default {
|
||||
view: 'View',
|
||||
use: 'Use',
|
||||
export: 'Export',
|
||||
manage: 'Manage'
|
||||
manage: 'Manage',
|
||||
row_column: 'Row and column permission settings',
|
||||
row_permission: 'Row permission rules',
|
||||
enable_row: 'Enable row permissions',
|
||||
add_condition: 'Add condition',
|
||||
add_relationship: 'Add relationship',
|
||||
white_list: 'White list',
|
||||
white_user_not: 'The above permission rules do not take effect for white list users',
|
||||
organization_or_role: 'Please select an organization or role',
|
||||
column_permission: 'Column permission rule',
|
||||
enable_column: 'Enable column permissions',
|
||||
search_by_field: 'Search by field name',
|
||||
add_condition: 'Add condition',
|
||||
add_relationship: 'Add relationship',
|
||||
filter_fields: 'Filter fields',
|
||||
selct_filter_fields: 'Please select a filter field',
|
||||
enter_keywords: 'Please enter keywords',
|
||||
screen_method: 'Screening method',
|
||||
select: 'Please select',
|
||||
fixed_value: 'Fixed value',
|
||||
defalut_method: 'Default condition',
|
||||
select_all: 'Select all',
|
||||
added: 'Added',
|
||||
manual_input: 'Manual input',
|
||||
please_fill: 'Please fill in one line and add 500 at most. Duplicate options and added options will be automatically filtered when identifying and entering',
|
||||
close: 'close',
|
||||
add: 'add to',
|
||||
sure: 'determine',
|
||||
},
|
||||
about: {
|
||||
auth_to: 'Authorized to',
|
||||
@ -2147,5 +2226,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'
|
||||
}
|
||||
}
|
||||
|
@ -131,9 +131,13 @@ export default {
|
||||
default_login: '普通登錄'
|
||||
},
|
||||
commons: {
|
||||
manage_member: '管理成員',
|
||||
user_confirm_remove_cancel: '確定將該用戶從角色中移除嗎?',
|
||||
confirm_remove_cancel: '確定刪除該角色嗎?',
|
||||
default_value: '默認值',
|
||||
params_value: '参数值',
|
||||
publish: '發布',
|
||||
input_role_name: '請輸入角色名稱',
|
||||
unpublished: '取消發布',
|
||||
default_pwd: '初始密碼',
|
||||
stop: '停止',
|
||||
@ -159,6 +163,7 @@ export default {
|
||||
gender: '性別',
|
||||
man: '男',
|
||||
woman: '女',
|
||||
keep_secret: '保密',
|
||||
nick_name: '姓名',
|
||||
confirmPassword: '確認密碼',
|
||||
upload: '上傳',
|
||||
@ -210,6 +215,8 @@ export default {
|
||||
member: '成員',
|
||||
email: '郵箱',
|
||||
phone: '電話',
|
||||
mobile_phone: '請輸入手機號',
|
||||
mobile_phone_number: '手機號碼',
|
||||
role: '角色',
|
||||
personal_info: '個人信息',
|
||||
api_keys: 'API Keys',
|
||||
@ -475,7 +482,8 @@ export default {
|
||||
ldap: 'LDAP設置',
|
||||
oidc: 'OIDC設置',
|
||||
theme: '主題設置',
|
||||
cas: 'CAS設置'
|
||||
cas: 'CAS設置',
|
||||
map: '地圖設置'
|
||||
},
|
||||
license: {
|
||||
i18n_no_license_record: '沒有 License 記錄',
|
||||
@ -502,7 +510,7 @@ export default {
|
||||
please_choose_member: '請選擇成員',
|
||||
search_by_name: '根據名稱搜索',
|
||||
modify_personal_info: '修改個人信息',
|
||||
edit_password: '修改密碼',
|
||||
edit_password: '重置密码',
|
||||
edit_information: '編輯信息',
|
||||
input_name: '請輸入名稱',
|
||||
input_email: '請輸入郵箱',
|
||||
@ -524,6 +532,12 @@ export default {
|
||||
modify: '修改用戶',
|
||||
input_name: '請輸入用戶姓名',
|
||||
input_id: '請輸入ID',
|
||||
id_mandatory: 'ID為必填',
|
||||
name_mandatory: '姓名為必填',
|
||||
email_mandatory: '郵箱為必填',
|
||||
role_mandatory: '角色為必填',
|
||||
phone_format: '手機號碼格式錯誤',
|
||||
select_gender: '請選擇性別',
|
||||
input_email: '請輸入郵箱',
|
||||
input_password: '請輸入密碼',
|
||||
input_phone: '請輸入電話號碼',
|
||||
@ -536,7 +550,7 @@ export default {
|
||||
apikey_delete_confirm: '這個 API Key 確定要刪除嗎?',
|
||||
input_id_placeholder: '請輸入ID (不支持中文)',
|
||||
source: '用戶來源',
|
||||
choose_org: '選擇組織',
|
||||
choose_org: '請選擇組織',
|
||||
reset_password: '重置密碼',
|
||||
current_user: '當前用戶',
|
||||
origin_passwd: '原始密碼',
|
||||
@ -602,7 +616,20 @@ export default {
|
||||
confirm_delete: '確認刪除角色 ',
|
||||
role_name: '角色名稱',
|
||||
search_by_name: '按名稱搜索',
|
||||
pls_input_name: '請輸入名稱'
|
||||
pls_input_name: '請輸入名稱',
|
||||
search_by_name_email: '通過姓名或郵箱搜索',
|
||||
api_role: 'API角色',
|
||||
role_exist: '添加失敗,該角色已存在',
|
||||
add_api_role: '添加API角色',
|
||||
can_not_move: '不可移除,至少保留一位管理員',
|
||||
manage_can_not_move: '管理員是系統預置角色,默認擁有系統管理全部權限,無法刪除',
|
||||
manage_can_not_update: '管理員是系統預置角色,默認擁有系統管理全部權限,無法編輯',
|
||||
role_name: '角色名稱',
|
||||
role_description: '角色描述',
|
||||
editer_role: '編輯角色',
|
||||
add_role: '添加角色',
|
||||
role_name_exist: '該角色名稱已存在',
|
||||
search_by_role: '通過角色名稱搜索',
|
||||
},
|
||||
menu: {
|
||||
parent_category: '上級目錄',
|
||||
@ -637,7 +664,26 @@ export default {
|
||||
select_organization: '請選擇組織',
|
||||
search_by_name: '根據名稱搜索',
|
||||
special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
|
||||
select: '選擇組織'
|
||||
select: '選擇組織',
|
||||
member: '成員',
|
||||
organization: '組織',
|
||||
add_user: '添加用戶',
|
||||
search_by_name: '通過組織名稱搜索',
|
||||
sure_move_user: '確定將該用戶從組織中移除嗎?',
|
||||
move_success: '移除成功',
|
||||
user: '用戶',
|
||||
add_organization: '添加組織',
|
||||
defalut_organization_canot_move: '默認組織無法刪除',
|
||||
organization_name: '組織名稱',
|
||||
input_organization_name: '請輸入組織名稱',
|
||||
relate_top_organization: '關聯上級組織',
|
||||
organization_name_exist: '組織名稱已存在',
|
||||
canot_delete: '無法刪除',
|
||||
remove_user_first: '請先移除組織中所有用戶,再進行刪除組織操作。',
|
||||
sure_delete_organization: '確定刪除該組織嗎?',
|
||||
delete: '刪除',
|
||||
add_child_org: '添加子組織',
|
||||
edite_organization: '編輯組織',
|
||||
},
|
||||
system_parameter_setting: {
|
||||
mailbox_service_settings: '郵件設置',
|
||||
@ -1500,11 +1546,15 @@ export default {
|
||||
sure_bt: '確定'
|
||||
},
|
||||
panel: {
|
||||
template_market: '模板市场',
|
||||
template_preview: '预览模板',
|
||||
apply: '应用',
|
||||
apply_this_template: '应用此模板',
|
||||
market_network_tips: '查看模板市场模板需要服务器与模板市场(https://dataease.io/templates)联通,请检查网络...',
|
||||
enter_name_tips: '请输入仪表板名称',
|
||||
name: '名称',
|
||||
apply_template: '应用模板',
|
||||
enter_template_name_tips: '请输入模板名称...',
|
||||
enter_template_name_tips: '搜索模板名称',
|
||||
pic_adaptation: '适应组件',
|
||||
pic_equiratio: '等比适应',
|
||||
pic_original: '原始尺寸',
|
||||
@ -1839,6 +1889,7 @@ export default {
|
||||
dept: '組織',
|
||||
role: '角色',
|
||||
user: '用戶',
|
||||
set_rules: '設置規則',
|
||||
sysParams: '系統變量',
|
||||
sysParams_type: {
|
||||
user_id: '用戶ID',
|
||||
@ -1864,7 +1915,34 @@ export default {
|
||||
view: '查看',
|
||||
use: '使用',
|
||||
export: '導出',
|
||||
manage: '管理'
|
||||
manage: '管理',
|
||||
row_column: '行列權限設置',
|
||||
row_permission: '行權限規則',
|
||||
enable_row: '啟用行權限',
|
||||
add_condition: '添加條件',
|
||||
add_relationship: '添加關系',
|
||||
white_list: '白名單',
|
||||
white_user_not: '以上權限規則對白名單用戶不生效',
|
||||
organization_or_role: '請選擇組織或角色',
|
||||
column_permission: '列權限規則',
|
||||
enable_column: '啟用列權限',
|
||||
search_by_field: '通過字段名稱搜索',
|
||||
add_condition: '添加條件',
|
||||
add_relationship: '添加關系',
|
||||
filter_fields: '篩選字段',
|
||||
selct_filter_fields: '請選擇篩選字段',
|
||||
enter_keywords: '請輸關鍵字',
|
||||
screen_method: '篩選方式',
|
||||
select: '請選擇',
|
||||
fixed_value: '固定值',
|
||||
defalut_method: '默認條件',
|
||||
select_all: '全 選',
|
||||
added: '已添加',
|
||||
manual_input: '手工輸入',
|
||||
please_fill: '請一行填一個,最多添加500個,識別錄入時會自動過濾重復的選項和已經添加過的選項',
|
||||
close: '關 閉',
|
||||
add: '添 加',
|
||||
sure: '確 定',
|
||||
},
|
||||
about: {
|
||||
auth_to: '授權給',
|
||||
@ -2158,5 +2236,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: '當前節點'
|
||||
}
|
||||
}
|
||||
|
@ -131,8 +131,12 @@ export default {
|
||||
default_login: '普通登录'
|
||||
},
|
||||
commons: {
|
||||
manage_member: '管理成员',
|
||||
confirm_remove_cancel: '确定删除该角色吗?',
|
||||
user_confirm_remove_cancel:'确定将该用户从角色中移除吗?',
|
||||
default_value: '默认值',
|
||||
params_value: '参数值',
|
||||
input_role_name: '请输入角色名称',
|
||||
publish: '发布',
|
||||
unpublished: '取消发布',
|
||||
default_pwd: '初始密码',
|
||||
@ -159,6 +163,7 @@ export default {
|
||||
gender: '性别',
|
||||
man: '男',
|
||||
woman: '女',
|
||||
keep_secret: '保密',
|
||||
nick_name: '姓名',
|
||||
confirmPassword: '确认密码',
|
||||
upload: '上传',
|
||||
@ -211,6 +216,8 @@ export default {
|
||||
member: '成员',
|
||||
email: '邮箱',
|
||||
phone: '电话',
|
||||
mobile_phone: '请输入手机号',
|
||||
mobile_phone_number: '手机号码',
|
||||
role: '角色',
|
||||
personal_info: '个人信息',
|
||||
api_keys: 'API Keys',
|
||||
@ -476,7 +483,8 @@ export default {
|
||||
ldap: 'LDAP设置',
|
||||
oidc: 'OIDC设置',
|
||||
theme: '主题设置',
|
||||
cas: 'CAS设置'
|
||||
cas: 'CAS设置',
|
||||
map: '地图设置'
|
||||
},
|
||||
license: {
|
||||
i18n_no_license_record: '没有 License 记录',
|
||||
@ -503,7 +511,7 @@ export default {
|
||||
please_choose_member: '请选择成员',
|
||||
search_by_name: '根据名称搜索',
|
||||
modify_personal_info: '修改个人信息',
|
||||
edit_password: '修改密码',
|
||||
edit_password: '重置密码',
|
||||
edit_information: '编辑信息',
|
||||
input_name: '请输入名称',
|
||||
input_email: '请输入邮箱',
|
||||
@ -521,15 +529,21 @@ export default {
|
||||
no_such_user: '无此用户信息, 请输入正确的用户 ID 或者 用户邮箱!'
|
||||
},
|
||||
user: {
|
||||
create: '新建用户',
|
||||
modify: '修改用户',
|
||||
input_name: '请输入用户姓名',
|
||||
create: '添加用户',
|
||||
modify: '编辑用户',
|
||||
input_name: '请输入姓名',
|
||||
input_id: '请输入ID',
|
||||
id_mandatory: 'ID为必填',
|
||||
name_mandatory: '姓名为必填',
|
||||
email_mandatory: '邮箱为必填',
|
||||
role_mandatory: '角色为必填',
|
||||
phone_format: '手机号码格式错误',
|
||||
input_email: '请输入邮箱',
|
||||
input_password: '请输入密码',
|
||||
input_phone: '请输入电话号码',
|
||||
input_roles: '请选择角色',
|
||||
select_users: '请选择用户',
|
||||
select_gender: '请选择性别',
|
||||
special_characters_are_not_supported: '不支持特殊字符',
|
||||
mobile_number_format_is_incorrect: '手机号码格式不正确',
|
||||
email_format_is_incorrect: '邮箱格式不正确',
|
||||
@ -537,7 +551,7 @@ export default {
|
||||
apikey_delete_confirm: '这个 API Key 确定要删除吗?',
|
||||
input_id_placeholder: '请输入ID (不支持中文)',
|
||||
source: '用户来源',
|
||||
choose_org: '选择组织',
|
||||
choose_org: '请选择组织',
|
||||
reset_password: '重置密码',
|
||||
current_user: '当前用户',
|
||||
origin_passwd: '原始密码',
|
||||
@ -603,7 +617,20 @@ export default {
|
||||
confirm_delete: '确认删除角色 ',
|
||||
role_name: '角色名称',
|
||||
search_by_name: '按名称搜索',
|
||||
pls_input_name: '请输入名称'
|
||||
pls_input_name: '请输入名称',
|
||||
search_by_name_email: '通过姓名或邮箱搜索',
|
||||
api_role: 'API角色',
|
||||
role_exist: '添加失败,该角色已存在',
|
||||
add_api_role: '添加API角色',
|
||||
can_not_move: '不可移除,至少保留一位管理员',
|
||||
manage_can_not_move: '管理员是系统预置角色,默认拥有系统管理全部权限,无法删除',
|
||||
manage_can_not_update: '管理员是系统预置角色,默认拥有系统管理全部权限,无法编辑',
|
||||
role_name: '角色名称',
|
||||
role_description: '角色描述',
|
||||
editer_role: '编辑角色',
|
||||
add_role: '添加角色',
|
||||
role_name_exist: '该角色名称已存在',
|
||||
search_by_role: '通过角色名称搜索',
|
||||
},
|
||||
menu: {
|
||||
parent_category: '上级目录',
|
||||
@ -638,7 +665,26 @@ export default {
|
||||
select_organization: '请选择组织',
|
||||
search_by_name: '根据名称搜索',
|
||||
special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
|
||||
select: '选择组织'
|
||||
select: '选择组织',
|
||||
member: '成员',
|
||||
organization: '组织',
|
||||
add_user: '添加用户',
|
||||
search_by_name: '通过组织名称搜索',
|
||||
sure_move_user: '确定将该用户从组织中移除吗?',
|
||||
move_success: '移除成功',
|
||||
user: '用户',
|
||||
add_organization: '添加组织',
|
||||
defalut_organization_canot_move: '默认组织无法删除',
|
||||
organization_name: '组织名称',
|
||||
input_organization_name: '请输入组织名称',
|
||||
relate_top_organization: '关联上级组织',
|
||||
organization_name_exist: '组织名称已存在',
|
||||
canot_delete: '无法删除',
|
||||
remove_user_first: '请先移除组织中所有用户,再进行删除组织操作。',
|
||||
sure_delete_organization: '确定删除该组织吗?',
|
||||
delete: '删除',
|
||||
add_child_org: '添加子组织',
|
||||
edite_organization: '编辑组织',
|
||||
},
|
||||
system_parameter_setting: {
|
||||
mailbox_service_settings: '邮件设置',
|
||||
@ -1508,11 +1554,15 @@ export default {
|
||||
sure_bt: '确定'
|
||||
},
|
||||
panel: {
|
||||
template_market: '模板市场',
|
||||
template_preview: '预览模板',
|
||||
apply: '应用',
|
||||
apply_this_template: '应用此模板',
|
||||
market_network_tips: '查看模板市场模板需要服务器与模板市场(https://dataease.io/templates)联通,请检查网络...',
|
||||
enter_name_tips: '请输入仪表板名称',
|
||||
name: '名称',
|
||||
apply_template: '应用模板',
|
||||
enter_template_name_tips: '请输入模板名称...',
|
||||
enter_template_name_tips: '搜索模板名称',
|
||||
pic_adaptation: '适应组件',
|
||||
pic_equiratio: '等比适应',
|
||||
pic_original: '原始尺寸',
|
||||
@ -1848,6 +1898,7 @@ export default {
|
||||
dept: '组织',
|
||||
role: '角色',
|
||||
user: '用户',
|
||||
set_rules: '设置规则',
|
||||
sysParams: '系统变量',
|
||||
sysParams_type: {
|
||||
user_id: '用户ID',
|
||||
@ -1873,7 +1924,34 @@ export default {
|
||||
view: '查看',
|
||||
use: '使用',
|
||||
export: '导出',
|
||||
manage: '管理'
|
||||
manage: '管理',
|
||||
row_column: '行列权限设置',
|
||||
row_permission: '行权限规则',
|
||||
enable_row: '启用行权限',
|
||||
add_condition: '添加条件',
|
||||
add_relationship: '添加关系',
|
||||
white_list: '白名单',
|
||||
white_user_not: '以上权限规则对白名单用户不生效',
|
||||
organization_or_role: '请选择组织或角色',
|
||||
column_permission: '列权限规则',
|
||||
enable_column: '启用列权限',
|
||||
search_by_field: '通过字段名称搜索',
|
||||
add_condition: '添加条件',
|
||||
add_relationship: '添加关系',
|
||||
filter_fields: '筛选字段',
|
||||
selct_filter_fields: '请选择筛选字段',
|
||||
enter_keywords: '请输关键字',
|
||||
screen_method: '筛选方式',
|
||||
select: '请选择',
|
||||
fixed_value: '固定值',
|
||||
defalut_method: '默认条件',
|
||||
select_all: '全 选',
|
||||
added: '已添加',
|
||||
manual_input: '手工输入',
|
||||
please_fill: '请一行填一个,最多添加500个,识别录入时会自动过滤重复的选项和已经添加过的选项',
|
||||
close: '关 闭',
|
||||
add: '添 加',
|
||||
sure: '确 定',
|
||||
},
|
||||
about: {
|
||||
auth_to: '授权给',
|
||||
@ -2170,5 +2248,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: '当前节点'
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +1,147 @@
|
||||
<template>
|
||||
<!-- <div :class="{'has-logo':showLogo}" :style="{'--active-bg': activeBg, '--theme':$store.state.settings.theme , '--left-menu-hovor': variables.leftMenuHovor}"> -->
|
||||
<div :class="{'has-logo':showLogo}">
|
||||
<div :class="{ 'has-logo': showLogo }">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:unique-opened="false"
|
||||
:collapse-transition="false"
|
||||
|
||||
mode="vertical"
|
||||
>
|
||||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
|
||||
<sidebar-item
|
||||
v-for="route in routes"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
/>
|
||||
</el-menu>
|
||||
<div
|
||||
:style="{ width: isCollapse ? '64px' : '260px' }"
|
||||
class="sidebar-collapse-btn"
|
||||
@click="changeSideWidth"
|
||||
>
|
||||
<i
|
||||
:style="{ transform: isCollapse ? 'rotate(90deg)' : 'rotate(-90deg)' }"
|
||||
class="el-icon-upload2"
|
||||
></i>
|
||||
{{ isCollapse ? "" : "收起导航" }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Logo from './Logo'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import variables from '@/styles/variables.scss'
|
||||
import { mapGetters } from "vuex";
|
||||
import Logo from "./Logo";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import variables from "@/styles/variables.scss";
|
||||
import path from "path";
|
||||
import { isExternal } from "@/utils/validate";
|
||||
export default {
|
||||
components: { SidebarItem, Logo },
|
||||
|
||||
computed: {
|
||||
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
]),
|
||||
...mapGetters(["sidebar"]),
|
||||
routes() {
|
||||
// return this.$router.options.routes
|
||||
return this.$store.state.permission.currentRoutes.children
|
||||
if (this.isCollapse) {
|
||||
return this.flatterRouter(
|
||||
this.$store.state.permission.currentRoutes.children
|
||||
);
|
||||
}
|
||||
return this.$store.state.permission.currentRoutes.children;
|
||||
},
|
||||
activeMenu() {
|
||||
const route = this.$route
|
||||
const { meta, path } = route
|
||||
const route = this.$route;
|
||||
const { meta, path } = route;
|
||||
// if set path, the sidebar will highlight the path you set
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu
|
||||
return meta.activeMenu;
|
||||
}
|
||||
return path
|
||||
return path;
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo
|
||||
return this.$store.state.settings.sidebarLogo;
|
||||
},
|
||||
variables() {
|
||||
return variables
|
||||
return variables;
|
||||
},
|
||||
isCollapse() {
|
||||
return false
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isCollapse: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
changeSideWidth() {
|
||||
this.isCollapse = !this.isCollapse;
|
||||
this.$emit("changeSideWidth", this.isCollapse ? "70px" : "");
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath;
|
||||
}
|
||||
|
||||
if (isExternal(this.basePath)) {
|
||||
return this.basePath;
|
||||
}
|
||||
}
|
||||
const currentRoutes = this.$store.state.permission.currentRoutes;
|
||||
if (currentRoutes && currentRoutes.path) {
|
||||
return path.resolve(currentRoutes.path, this.basePath, routePath);
|
||||
}
|
||||
},
|
||||
flatterRouter(arr = [], route = [], path = "") {
|
||||
arr.forEach((ele) => {
|
||||
this.formaterRoutePath(ele, path, route);
|
||||
});
|
||||
return route;
|
||||
},
|
||||
pathEndwith(path = "") {
|
||||
return path.endsWith("/") || !path ? path : path + "/";
|
||||
},
|
||||
formaterRoutePath(ele, routePath = "", route) {
|
||||
if (!ele.hidden) {
|
||||
if (!ele.children?.length) {
|
||||
ele.path = routePath + ele.path;
|
||||
route.push(ele);
|
||||
} else {
|
||||
this.flatterRouter(ele.children, route, this.pathEndwith(ele.path));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebar-collapse-btn {
|
||||
height: 48px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-top: 1px solid #1f232926;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
//styleName: 中文/桌面端/正文 14 22 Regular;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #646a73;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
margin-right: 8.8px;
|
||||
}
|
||||
}
|
||||
::v-deep .el-menu {
|
||||
.el-menu-item,
|
||||
.el-submenu__title {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
.el-tooltip {
|
||||
padding-left: 25px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
<div class="right-menu" style="color: var(--TopTextColor)">
|
||||
<template>
|
||||
<span class="hover-effect right-menu-item template-market-item" @click="changeTemplateMarketShow(true)">模板市场</span>
|
||||
<notification class="right-menu-item hover-effect" />
|
||||
<lang-select class="right-menu-item hover-effect" />
|
||||
<div style="height: 100%;padding: 0 8px;" class="right-menu-item hover-effect">
|
||||
|
@ -4,8 +4,8 @@
|
||||
<topbar v-if="!fullHeightFlag && finishLoad" :show-tips="showTips" />
|
||||
|
||||
<de-container :style="mainStyle">
|
||||
<de-aside-container v-if="!sidebar.hide" type="system" class="le-aside-container">
|
||||
<sidebar class="sidebar-container" />
|
||||
<de-aside-container v-if="!sidebar.hide" :isCollapseWidth="sideWidth" type="system" class="le-aside-container">
|
||||
<sidebar @changeSideWidth="(side) => sideWidth = side" class="sidebar-container" />
|
||||
</de-aside-container>
|
||||
|
||||
<de-main-container class="la-main-container" :class="{'full-height':fullHeightFlag}">
|
||||
@ -51,7 +51,8 @@ export default {
|
||||
componentName: 'PanelMain',
|
||||
showTips: false,
|
||||
finishLoad: false,
|
||||
buttonDisable: false
|
||||
buttonDisable: false,
|
||||
sideWidth: "",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -54,6 +54,42 @@
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">button_right</div>
|
||||
<div class="code-name">&#xe635;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">icon-maybe</div>
|
||||
<div class="code-name">&#xe631;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">icon_up-left_outlined</div>
|
||||
<div class="code-name">&#xe632;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">close</div>
|
||||
<div class="code-name">&#xe633;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">Frame 3425</div>
|
||||
<div class="code-name">&#xe634;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">icon-filter</div>
|
||||
<div class="code-name">&#xe636;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">icon_Batch_outlined</div>
|
||||
@ -726,9 +762,9 @@
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1657078050131') format('woff2'),
|
||||
url('iconfont.woff?t=1657078050131') format('woff'),
|
||||
url('iconfont.ttf?t=1657078050131') format('truetype');
|
||||
src: url('iconfont.woff2?t=1658301977080') format('woff2'),
|
||||
url('iconfont.woff?t=1658301977080') format('woff'),
|
||||
url('iconfont.ttf?t=1658301977080') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
@ -754,6 +790,60 @@
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-button_right"></span>
|
||||
<div class="name">
|
||||
button_right
|
||||
</div>
|
||||
<div class="code-name">.icon-button_right
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-icon-maybe"></span>
|
||||
<div class="name">
|
||||
icon-maybe
|
||||
</div>
|
||||
<div class="code-name">.icon-icon-maybe
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-icon_up-left_outlined"></span>
|
||||
<div class="name">
|
||||
icon_up-left_outlined
|
||||
</div>
|
||||
<div class="code-name">.icon-icon_up-left_outlined
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-close"></span>
|
||||
<div class="name">
|
||||
close
|
||||
</div>
|
||||
<div class="code-name">.icon-close
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-a-Frame3425"></span>
|
||||
<div class="name">
|
||||
Frame 3425
|
||||
</div>
|
||||
<div class="code-name">.icon-a-Frame3425
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-icon-filter"></span>
|
||||
<div class="name">
|
||||
icon-filter
|
||||
</div>
|
||||
<div class="code-name">.icon-icon-filter
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-icon_Batch_outlined"></span>
|
||||
<div class="name">
|
||||
@ -1762,6 +1852,54 @@
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-button_right"></use>
|
||||
</svg>
|
||||
<div class="name">button_right</div>
|
||||
<div class="code-name">#icon-button_right</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-icon-maybe"></use>
|
||||
</svg>
|
||||
<div class="name">icon-maybe</div>
|
||||
<div class="code-name">#icon-icon-maybe</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-icon_up-left_outlined"></use>
|
||||
</svg>
|
||||
<div class="name">icon_up-left_outlined</div>
|
||||
<div class="code-name">#icon-icon_up-left_outlined</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-close"></use>
|
||||
</svg>
|
||||
<div class="name">close</div>
|
||||
<div class="code-name">#icon-close</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-a-Frame3425"></use>
|
||||
</svg>
|
||||
<div class="name">Frame 3425</div>
|
||||
<div class="code-name">#icon-a-Frame3425</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-icon-filter"></use>
|
||||
</svg>
|
||||
<div class="name">icon-filter</div>
|
||||
<div class="code-name">#icon-icon-filter</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-icon_Batch_outlined"></use>
|
||||
|
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2459092 */
|
||||
src: url('iconfont.woff2?t=1657078050131') format('woff2'),
|
||||
url('iconfont.woff?t=1657078050131') format('woff'),
|
||||
url('iconfont.ttf?t=1657078050131') format('truetype');
|
||||
src: url('iconfont.woff2?t=1658301977080') format('woff2'),
|
||||
url('iconfont.woff?t=1658301977080') format('woff'),
|
||||
url('iconfont.ttf?t=1658301977080') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,30 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-button_right:before {
|
||||
content: "\e635";
|
||||
}
|
||||
|
||||
.icon-icon-maybe:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-icon_up-left_outlined:before {
|
||||
content: "\e632";
|
||||
}
|
||||
|
||||
.icon-close:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-a-Frame3425:before {
|
||||
content: "\e634";
|
||||
}
|
||||
|
||||
.icon-icon-filter:before {
|
||||
content: "\e636";
|
||||
}
|
||||
|
||||
.icon-icon_Batch_outlined:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -5,6 +5,48 @@
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "30729285",
|
||||
"name": "button_right",
|
||||
"font_class": "button_right",
|
||||
"unicode": "e635",
|
||||
"unicode_decimal": 58933
|
||||
},
|
||||
{
|
||||
"icon_id": "30705847",
|
||||
"name": "icon-maybe",
|
||||
"font_class": "icon-maybe",
|
||||
"unicode": "e631",
|
||||
"unicode_decimal": 58929
|
||||
},
|
||||
{
|
||||
"icon_id": "30725622",
|
||||
"name": "icon_up-left_outlined",
|
||||
"font_class": "icon_up-left_outlined",
|
||||
"unicode": "e632",
|
||||
"unicode_decimal": 58930
|
||||
},
|
||||
{
|
||||
"icon_id": "30725623",
|
||||
"name": "close",
|
||||
"font_class": "close",
|
||||
"unicode": "e633",
|
||||
"unicode_decimal": 58931
|
||||
},
|
||||
{
|
||||
"icon_id": "30725624",
|
||||
"name": "Frame 3425",
|
||||
"font_class": "a-Frame3425",
|
||||
"unicode": "e634",
|
||||
"unicode_decimal": 58932
|
||||
},
|
||||
{
|
||||
"icon_id": "30725626",
|
||||
"name": "icon-filter",
|
||||
"font_class": "icon-filter",
|
||||
"unicode": "e636",
|
||||
"unicode_decimal": 58934
|
||||
},
|
||||
{
|
||||
"icon_id": "30342179",
|
||||
"name": "icon_Batch_outlined",
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -21,6 +21,7 @@ $--border-color-lighter: #e6ebf5;
|
||||
$--table-border: 1px solid #dfe6ec;
|
||||
|
||||
$--font-path: "~element-ui/lib/theme-chalk/fonts";
|
||||
$--color-primary: #3370ff;
|
||||
|
||||
@import "~element-ui/packages/theme-chalk/src/index";
|
||||
// topBar
|
||||
|
@ -132,6 +132,31 @@ export function getLabel(chart) {
|
||||
fill: l.color,
|
||||
fontSize: parseInt(l.fontSize)
|
||||
}
|
||||
// label value formatter
|
||||
if (chart.type && chart.type !== 'waterfall') {
|
||||
label.formatter = function(param) {
|
||||
let yAxis
|
||||
let res = param.value
|
||||
try {
|
||||
yAxis = JSON.parse(chart.yaxis)
|
||||
} catch (e) {
|
||||
yAxis = JSON.parse(JSON.stringify(chart.yaxis))
|
||||
}
|
||||
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
if (f.name === param.category) {
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
} else {
|
||||
label = false
|
||||
}
|
||||
@ -150,6 +175,68 @@ export function getTooltip(chart) {
|
||||
const t = JSON.parse(JSON.stringify(customAttr.tooltip))
|
||||
if (t.show) {
|
||||
tooltip = {}
|
||||
// tooltip value formatter
|
||||
if (chart.type && chart.type !== 'waterfall') {
|
||||
tooltip.formatter = function(param) {
|
||||
let yAxis
|
||||
let res
|
||||
try {
|
||||
yAxis = JSON.parse(chart.yaxis)
|
||||
} catch (e) {
|
||||
yAxis = JSON.parse(JSON.stringify(chart.yaxis))
|
||||
}
|
||||
|
||||
let obj
|
||||
if (chart.type === 'word-cloud') {
|
||||
obj = { name: param.text, value: param.value }
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
}
|
||||
} else if (chart.type.includes('treemap')) {
|
||||
obj = { name: param.name, value: param.value }
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
}
|
||||
} else if (chart.type.includes('pie') || chart.type.includes('funnel')) {
|
||||
obj = { name: param.field, value: param.value }
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
}
|
||||
} else if (chart.type.includes('bar') || chart.type.includes('line') || chart.type.includes('scatter') || chart.type.includes('radar')) {
|
||||
obj = { name: param.category, value: param.value }
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
if (f.name === param.category) {
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = param.value
|
||||
}
|
||||
obj.value = res
|
||||
return obj
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tooltip = false
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
getYAxis
|
||||
} from '@/views/chart/chart/common/common_antv'
|
||||
import { Waterfall } from '@antv/g2plot'
|
||||
import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter'
|
||||
|
||||
export function baseWaterfallOptionAntV(plot, container, chart, action) {
|
||||
// theme
|
||||
@ -42,6 +43,7 @@ export function baseWaterfallOptionAntV(plot, container, chart, action) {
|
||||
yField: 'value',
|
||||
seriesField: 'category',
|
||||
appendPadding: getPadding(chart),
|
||||
meta: getMeta(chart),
|
||||
label: label,
|
||||
tooltip: tooltip,
|
||||
legend: {
|
||||
@ -102,3 +104,24 @@ export function baseWaterfallOptionAntV(plot, container, chart, action) {
|
||||
|
||||
return plot
|
||||
}
|
||||
|
||||
function getMeta(chart) {
|
||||
const meta = {}
|
||||
const yaxis = JSON.parse(chart.yaxis)
|
||||
if (yaxis && yaxis.length > 0) {
|
||||
const f = yaxis[0]
|
||||
meta.value = {
|
||||
alias: f.name,
|
||||
formatter: (value) => {
|
||||
let res
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(value, formatterItem)
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
@ -100,7 +100,7 @@
|
||||
<el-dropdown-item icon="el-icon-files" :command="beforeClickItem('filter')">
|
||||
<span>{{ $t('chart.filter') }}...</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="chart.render === 'antv' && (chart.type.includes('table') || chart.type === 'text')" icon="el-icon-notebook-2" divided :command="beforeClickItem('formatter')">
|
||||
<el-dropdown-item v-if="chart.render === 'antv'" icon="el-icon-notebook-2" divided :command="beforeClickItem('formatter')">
|
||||
<span>{{ $t('chart.value_formatter') }}...</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-edit-outline" divided :command="beforeClickItem('rename')">
|
||||
|
@ -100,7 +100,7 @@
|
||||
<el-dropdown-item icon="el-icon-files" :command="beforeClickItem('filter')">
|
||||
<span>{{ $t('chart.filter') }}...</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="chart.render === 'antv' && (chart.type.includes('table') || chart.type === 'text')" icon="el-icon-notebook-2" divided :command="beforeClickItem('formatter')">
|
||||
<el-dropdown-item v-if="chart.render === 'antv'" icon="el-icon-notebook-2" divided :command="beforeClickItem('formatter')">
|
||||
<span>{{ $t('chart.value_formatter') }}...</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-edit-outline" divided :command="beforeClickItem('rename')">
|
||||
|
@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { formatterType, unitList, valueFormatter } from '@/views/chart/chart/formatter'
|
||||
import { formatterItem, formatterType, unitList, valueFormatter } from '@/views/chart/chart/formatter'
|
||||
|
||||
export default {
|
||||
name: 'ValueFormatterEdit',
|
||||
@ -54,10 +54,18 @@ export default {
|
||||
exampleResult: '20000000'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
mounted() {
|
||||
this.getExampleValue()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (!this.formatterItem.formatterCfg) {
|
||||
this.formatterItem.formatterCfg = formatterItem
|
||||
}
|
||||
},
|
||||
getExampleValue() {
|
||||
this.exampleResult = valueFormatter(20000000, this.formatterItem.formatterCfg)
|
||||
}
|
||||
|
@ -609,7 +609,6 @@ export default {
|
||||
created() {
|
||||
// Global listening for key events
|
||||
listenGlobalKeyDown()
|
||||
this.init(this.$store.state.panel.panelInfo.id)
|
||||
},
|
||||
mounted() {
|
||||
this.initEvents()
|
||||
@ -622,6 +621,7 @@ export default {
|
||||
})
|
||||
})
|
||||
this.loadMultiplexingViewTree()
|
||||
this.init(this.$store.state.panel.panelInfo.id)
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('component-on-drag', this.componentOnDrag)
|
||||
|
@ -41,19 +41,16 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// $route(to, from) {
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('to-msg-share', this.toMsgShare)
|
||||
bus.$on('PanelSwitchComponent', this.panelSwitchComponent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('to-msg-share', this.toMsgShare)
|
||||
bus.$off('PanelSwitchComponent', this.panelSwitchComponent)
|
||||
},
|
||||
created() {
|
||||
bus.$emit('PanelSwitchComponent', { name: 'PanelMain' })
|
||||
bus.$on('PanelSwitchComponent', this.panelSwitchComponent)
|
||||
this.$store.dispatch('app/toggleSideBarHide', true)
|
||||
const routerParam = this.$router.currentRoute.params
|
||||
this.toMsgShare(routerParam)
|
||||
|
@ -241,6 +241,7 @@ export default {
|
||||
components: { GrantAuth, LinkGenerate, EditPanel, TreeSelector },
|
||||
data() {
|
||||
return {
|
||||
historyRequestId: null,
|
||||
lastActiveNode: null, // 激活的节点 在这个节点下面动态放置子节点
|
||||
lastActiveNodeData: null,
|
||||
activeTree: 'self', // 识别当前操作的树类型self 是仪表板列表树 system 是默认仪表板树
|
||||
@ -376,14 +377,19 @@ export default {
|
||||
this.$store.commit('setComponentData', [])
|
||||
this.$store.commit('setCanvasStyle', DEFAULT_COMMON_CANVAS_STYLE_STRING)
|
||||
this.defaultTree(true)
|
||||
this.tree(true)
|
||||
this.initCache()
|
||||
bus.$on('newPanelFromMarket', this.newPanelFromMarket)
|
||||
const routerParam = this.$router.currentRoute.params
|
||||
if (routerParam && routerParam.nodeType === 'panel' && this.historyRequestId !== routerParam.requestId) {
|
||||
this.historyRequestId = routerParam.requestId
|
||||
this.tree()
|
||||
this.edit(routerParam, null)
|
||||
} else {
|
||||
this.tree(true)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
newPanelFromMarket(panelInfo) {
|
||||
if (panelInfo) {
|
||||
this.defaultTree()
|
||||
this.tree()
|
||||
this.edit(panelInfo, null)
|
||||
}
|
||||
@ -741,16 +747,17 @@ export default {
|
||||
// 激活并点击当前节点
|
||||
activeNodeAndClick(panelInfo) {
|
||||
if (panelInfo) {
|
||||
this.$nextTick(() => {
|
||||
const _this = this
|
||||
_this.$nextTick(() => {
|
||||
// 延迟设置CurrentKey
|
||||
this.$refs.panel_list_tree.setCurrentKey(panelInfo.id)
|
||||
_this.$refs.panel_list_tree.setCurrentKey(panelInfo.id)
|
||||
// 去除default_tree 的影响
|
||||
this.$refs.default_panel_tree.setCurrentKey(null)
|
||||
this.$nextTick(() => {
|
||||
_this.$refs.default_panel_tree.setCurrentKey(null)
|
||||
_this.$nextTick(() => {
|
||||
document.querySelector('.is-current').firstChild.click()
|
||||
// 如果是仪表板列表的仪表板 直接进入编辑界面
|
||||
if (panelInfo.nodeType === 'panel') {
|
||||
this.edit(this.lastActiveNodeData, this.lastActiveNode)
|
||||
_this.edit(this.lastActiveNodeData, this.lastActiveNode)
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -759,12 +766,16 @@ export default {
|
||||
// 激活当前节点
|
||||
activeNodeAndClickOnly(panelInfo) {
|
||||
if (panelInfo) {
|
||||
this.$nextTick(() => {
|
||||
const _this = this
|
||||
_this.$nextTick(() => {
|
||||
// 延迟设置CurrentKey
|
||||
this.$refs.panel_list_tree.setCurrentKey(panelInfo.id)
|
||||
_this.$refs.panel_list_tree.setCurrentKey(panelInfo.id)
|
||||
// 去除default_tree 的影响
|
||||
this.$refs.default_panel_tree.setCurrentKey(null)
|
||||
this.$nextTick(() => {
|
||||
_this.$refs.default_panel_tree.setCurrentKey(null)
|
||||
if (panelInfo.parents) {
|
||||
_this.expandedArray = panelInfo.parents
|
||||
}
|
||||
_this.$nextTick(() => {
|
||||
document.querySelector('.is-current').firstChild.click()
|
||||
})
|
||||
})
|
||||
|
@ -4,7 +4,7 @@
|
||||
<el-tabs v-model="activeName" class="tab-panel" :stretch="true" @tab-click="handleClick">
|
||||
<el-tab-pane name="PanelList">
|
||||
<span slot="label"><i class="el-icon-document tablepanel-i" />{{ $t('panel.panel_list') }}</span>
|
||||
<panel-list v-if="activeName==='PanelList'" ref="panelList" />
|
||||
<panel-list v-show="activeName==='PanelList'" ref="panelList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="panels_star" :lazy="true">
|
||||
<span slot="label"><i class="el-icon-star-off tablepanel-i" />{{ $t('panel.store') }}</span>
|
||||
@ -51,7 +51,7 @@ export default {
|
||||
watch: {
|
||||
// 切换展示页面后 重新点击一下当前节点
|
||||
'$store.state.panel.mainActiveName': function(newVal, oldVal) {
|
||||
if (newVal === 'PanelMain' && this.lastActiveNode && this.lastActiveNodeData) {
|
||||
if (newVal === 'PanelMain' && this.lastActiveNodeData) {
|
||||
this.activeNodeAndClickOnly(this.lastActiveNodeData)
|
||||
}
|
||||
},
|
||||
@ -70,7 +70,7 @@ export default {
|
||||
localStorage.setItem('plugin-views', null)
|
||||
this.$store.commit('initViewRender', [])
|
||||
})
|
||||
this.clear()
|
||||
// this.clear()
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<de-container>
|
||||
<de-aside-container>
|
||||
<de-aside-container isTemplate>
|
||||
<el-tabs v-model="currentTemplateType" @tab-click="handleClick">
|
||||
<el-tab-pane name="self">
|
||||
<span slot="label"><i class="el-icon-star-off tablepanel-i" />{{ $t('panel.user_template') }}</span>
|
||||
|
@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :class="asideActive?'aside-active':'aside-inActive'">
|
||||
<svg-icon v-show="!asideActive" icon-class="button_right" class="open-button" @click="asideActiveChange(true)" />
|
||||
<el-row v-show="asideActive" style="padding: 12px 12px 0 12px ">
|
||||
<el-row>
|
||||
<span class="icon iconfont icon-close icon20 insert" @click="closePreview()" />
|
||||
<span class="main-title">{{$t('panel.template_preview')}}</span>
|
||||
<span style="float: right" class="icon iconfont icon-icon_up-left_outlined insert icon20" @click="asideActiveChange(false)" />
|
||||
</el-row>
|
||||
<el-row class="margin-top16 search-area">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
size="small"
|
||||
class="title-name-search"
|
||||
:placeholder="$t('panel.enter_template_name_tips')"
|
||||
clearable="true"
|
||||
/>
|
||||
<span class="icon iconfont icon-icon-filter insert icon20 filter-icon-span" :class="extFilterActive?'filter-icon-active':''" @click="extFilterActiveChange()" />
|
||||
</el-row>
|
||||
<el-row v-show="extFilterActive">
|
||||
<el-select v-model="marketActiveTab" class="margin-top16" size="small" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in marketTabs"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-divider />
|
||||
</el-row>
|
||||
|
||||
<el-row v-show="asideActive" class="aside-list" :class="extFilterActive?'aside-list-filter-active':''">
|
||||
<template-market-preview-item
|
||||
v-for="(templateItem) in currentMarketTemplateShowList"
|
||||
v-show="templateItem.showFlag"
|
||||
:key="templateItem.id"
|
||||
:template="templateItem"
|
||||
:base-url="baseUrl"
|
||||
:active="active(templateItem)"
|
||||
@previewTemplate="previewTemplate"
|
||||
/>
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col class="main-area" :class="asideActive ? 'main-area-active': ''">
|
||||
<el-row>
|
||||
<span v-if="curTemplate" class="template-title">{{ curTemplate.title }}</span>
|
||||
<el-button style="float: right" type="primary" size="small" @click="templateApply(curTemplate)">{{$t('panel.apply_this_template')}}</el-button>
|
||||
</el-row>
|
||||
<el-row class="img-main">
|
||||
<img height="100%" :src="templatePreviewUrl" alt="">
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { searchMarket, getCategories } from '@/api/templateMarket'
|
||||
import { groupTree, panelSave } from '@/api/panel/panel'
|
||||
import bus from '@/utils/bus'
|
||||
import { DEFAULT_COMMON_CANVAS_STYLE_STRING } from '@/views/panel/panel'
|
||||
import TemplateMarketPreviewItem from '@/views/panel/templateMarket/component/TemplateMarketPreviewItem'
|
||||
|
||||
export default {
|
||||
name: 'MarketPreview',
|
||||
components: { TemplateMarketPreviewItem },
|
||||
props: {
|
||||
previewId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
extFilterActive: false,
|
||||
asideActive: true,
|
||||
previewVisible: false,
|
||||
templatePreviewUrl: null,
|
||||
marketTabs: null,
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
panelForm: {
|
||||
name: null,
|
||||
pid: null,
|
||||
nodeType: 'panel',
|
||||
templateUrl: null,
|
||||
newFrom: 'new_market_template',
|
||||
panelType: 'self',
|
||||
panelStyle: JSON.stringify(DEFAULT_COMMON_CANVAS_STYLE_STRING),
|
||||
panelData: '[]'
|
||||
},
|
||||
panelGroupList: [],
|
||||
curApplyTemplate: null,
|
||||
folderSelectShow: false,
|
||||
baseUrl: 'https://dataease.io/templates',
|
||||
currentMarketTemplateShowList: [],
|
||||
networkStatus: true,
|
||||
curTemplate: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
marketActiveTab() {
|
||||
this.initTemplateShow()
|
||||
},
|
||||
searchText() {
|
||||
this.initTemplateShow()
|
||||
},
|
||||
previewId(val) {
|
||||
const _this = this
|
||||
_this.currentMarketTemplateShowList.forEach(template => {
|
||||
if (val === template.id) {
|
||||
_this.previewTemplate(template)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initMarketTemplate()
|
||||
this.getGroupTree()
|
||||
},
|
||||
methods: {
|
||||
initMarketTemplate() {
|
||||
searchMarket({}).then(rsp => {
|
||||
this.baseUrl = rsp.data.baseUrl
|
||||
this.currentMarketTemplateShowList = rsp.data.contents
|
||||
}).catch(() => {
|
||||
this.networkStatus = false
|
||||
})
|
||||
getCategories().then(rsp => {
|
||||
this.marketTabs = rsp.data
|
||||
this.marketActiveTab = this.marketTabs[0]
|
||||
}).catch(() => {
|
||||
this.networkStatus = false
|
||||
})
|
||||
if (this.previewId) {
|
||||
const _this = this
|
||||
_this.currentMarketTemplateShowList.forEach(template => {
|
||||
if (_this.previewId === template.id) {
|
||||
_this.previewTemplate(template)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getGroupTree() {
|
||||
groupTree({ nodeType: 'folder' }).then(res => {
|
||||
this.panelGroupList = res.data
|
||||
})
|
||||
},
|
||||
normalizer(node) {
|
||||
// 去掉children=null的属性
|
||||
if (node.children === null || node.children === 'null') {
|
||||
delete node.children
|
||||
}
|
||||
},
|
||||
templateApply(template) {
|
||||
this.$emit('templateApply', template)
|
||||
},
|
||||
closeDialog() {
|
||||
this.$emit('closeDialog')
|
||||
},
|
||||
handleClick(item) {
|
||||
|
||||
},
|
||||
initTemplateShow() {
|
||||
this.currentMarketTemplateShowList.forEach(template => {
|
||||
template.showFlag = this.templateShow(template)
|
||||
})
|
||||
},
|
||||
templateShow(templateItem) {
|
||||
let categoryMarch = false
|
||||
let searchMarch = false
|
||||
templateItem.categories.forEach(category => {
|
||||
if (category.name === this.marketActiveTab) {
|
||||
categoryMarch = true
|
||||
}
|
||||
})
|
||||
if (!this.searchText || templateItem.title.indexOf(this.searchText) > -1) {
|
||||
searchMarch = true
|
||||
}
|
||||
return categoryMarch && searchMarch
|
||||
},
|
||||
previewTemplate(template) {
|
||||
this.curTemplate = template
|
||||
if (template.thumbnail.indexOf('http') > -1) {
|
||||
this.templatePreviewUrl = template.thumbnail
|
||||
} else {
|
||||
this.templatePreviewUrl = this.baseUrl + template.thumbnail
|
||||
}
|
||||
},
|
||||
asideActiveChange(prop) {
|
||||
this.asideActive = prop
|
||||
},
|
||||
extFilterActiveChange() {
|
||||
this.extFilterActive = !this.extFilterActive
|
||||
},
|
||||
closePreview() {
|
||||
this.$emit('closePreview')
|
||||
},
|
||||
active(template) {
|
||||
return this.curTemplate && this.curTemplate.id === template.id
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aside-list {
|
||||
padding: 0px 12px 12px 12px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 200px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.aside-list-filter-active {
|
||||
height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.template-main {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 2px 0 rgba(31, 31, 31, 0.15), 0 1px 2px 0 rgba(31, 31, 31, 0.15);
|
||||
border: solid 2px #fff;
|
||||
padding-bottom: 24px;
|
||||
min-height: calc(100vh - 190px);
|
||||
}
|
||||
|
||||
.market-main {
|
||||
padding: 24px
|
||||
}
|
||||
|
||||
.title-left {
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.title-right {
|
||||
float: right;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
.dialog-footer-self {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.search-button-self {
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.topbar-icon-active {
|
||||
cursor: pointer;
|
||||
transition: .1s;
|
||||
border-radius: 3px;
|
||||
font-size: 22px;
|
||||
background-color: rgb(245, 245, 245);
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
height: 80vh;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #9ea6b2;
|
||||
}
|
||||
|
||||
.aside-active {
|
||||
width: 206px;
|
||||
height: calc(100vh - 56px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid rgba(31,31,31,0.15);
|
||||
}
|
||||
|
||||
.aside-inActive{
|
||||
position: relative;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.main-area-active {
|
||||
width: calc(100% - 206px)!important;
|
||||
}
|
||||
|
||||
.main-area {
|
||||
width: 100%;
|
||||
padding:24px;
|
||||
text-align: center;
|
||||
height: calc(100vh - 56px);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.title-name-search {
|
||||
width: 140px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.icon20 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.insert {
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
font-family: PingFang SC;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: var(--TextPrimary, #1F2329);
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
transition: .1s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.template-title{
|
||||
float: left;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.margin-top16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.img-main{
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
border: solid 2px #fff;
|
||||
height: calc(100% - 50px)!important;
|
||||
}
|
||||
.open-button{
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
.open-button:hover{
|
||||
color: #3a8ee6;
|
||||
}
|
||||
.filter-icon-span{
|
||||
float: left;
|
||||
border: 1px solid #DCDFE6;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.filter-icon-active{
|
||||
border: 1px solid #3370FF;
|
||||
color: #3370FF;
|
||||
}
|
||||
|
||||
.search-area{
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
@ -7,8 +7,8 @@
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="template-button">
|
||||
<el-button size="mini" type="primary" icon="el-icon-view" @click="templatePreview">预览</el-button>
|
||||
<el-button size="mini" type="success" icon="el-icon-files" @click="apply">应用</el-button>
|
||||
<el-button size="mini" style="width: 141px" @click="templatePreview">{{ $t('panel.preview') }}</el-button>
|
||||
<el-button size="mini" style="width: 141px" type="primary" @click="apply">{{ $t('panel.apply') }}</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
@ -55,7 +55,7 @@ export default {
|
||||
this.$emit('templateApply', this.template)
|
||||
},
|
||||
templatePreview() {
|
||||
this.$emit('templatePreview', this.thumbnailUrl)
|
||||
this.$emit('templatePreview', this.template.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,20 +66,20 @@ export default {
|
||||
.testcase-template {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 10px 30px;
|
||||
margin: 24px 0 0 24px;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
border: solid 2px #fff;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
height: 250px;
|
||||
border-radius: 4px;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: gray;
|
||||
text-align: center;
|
||||
margin: 10px auto;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
margin-left: 12px;
|
||||
margin-top: 12px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
@ -87,8 +87,8 @@ export default {
|
||||
|
||||
.template-img {
|
||||
background-size: 100% 100%;
|
||||
height: 170px;
|
||||
width: 300px;
|
||||
height: 180px;
|
||||
width: 318px;
|
||||
margin: 0 auto;
|
||||
border: solid 2px #fff;
|
||||
box-sizing: border-box;
|
||||
@ -96,7 +96,7 @@ export default {
|
||||
|
||||
.template-img:hover {
|
||||
border: solid 1px #4b8fdf;
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
color: deepskyblue;
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -110,7 +110,7 @@ export default {
|
||||
position:absolute;
|
||||
bottom: 5px;
|
||||
left: 0px;
|
||||
width: 300px;
|
||||
width: 318px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
{
|
||||
['template-item-main-active']: active
|
||||
},
|
||||
'template-item-main'
|
||||
]"
|
||||
@click.stop="previewTemplate"
|
||||
>
|
||||
<div class="template-item-img" :style="classBackground" />
|
||||
<span class="demonstration">{{ template.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TemplateMarketPreviewItem',
|
||||
props: {
|
||||
template: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
baseUrl: {
|
||||
type: String
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
classBackground() {
|
||||
return {
|
||||
background: `url(${this.thumbnailUrl}) no-repeat`,
|
||||
'background-size': `100% 100%`
|
||||
}
|
||||
},
|
||||
thumbnailUrl() {
|
||||
if (this.template.thumbnail.indexOf('http') > -1) {
|
||||
return this.template.thumbnail
|
||||
} else {
|
||||
return this.baseUrl + this.template.thumbnail
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
previewTemplate() {
|
||||
this.$emit('previewTemplate', this.template)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.template-item-main {
|
||||
margin: 0 0 12px 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 182px;
|
||||
height: 116px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #DEE0E3 ;
|
||||
border-radius: 4px;
|
||||
flex: none;
|
||||
order: 0;
|
||||
flex-grow: 0;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.template-item-main-active{
|
||||
border: 2px solid #3370FF ;
|
||||
|
||||
}
|
||||
.template-item-img{
|
||||
position: absolute;
|
||||
width: 182px;
|
||||
height: 86px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
position: absolute;
|
||||
width: 166px;
|
||||
height: 20px;
|
||||
left: 8px;
|
||||
top: 91px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
display: block;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.template-item-main:hover {
|
||||
border: solid 2px gray;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,30 +1,24 @@
|
||||
<template>
|
||||
<el-row class="outer-body">
|
||||
<!--预览模式-->
|
||||
<MarketPreview v-show="previewModel" :preview-id="templatePreviewId" @closePreview="previewModel=false" @templateApply="templateApply" />
|
||||
<!--列表模式-->
|
||||
<el-row v-show="!previewModel" class="market-main">
|
||||
<el-row>
|
||||
<el-row>
|
||||
<el-col span="4" style="text-align: left">
|
||||
<svg-icon
|
||||
icon-class="icon_left_outlined"
|
||||
class="topbar-icon-active"
|
||||
@click="closeDialog"
|
||||
/>
|
||||
<el-col span="12">
|
||||
<span class="title-left">{{ $t('panel.template_market') }}</span>
|
||||
</el-col>
|
||||
<el-col v-if="networkStatus" span="18">
|
||||
<el-row>
|
||||
<el-col span="20">
|
||||
<el-input v-model="searchText" :placeholder="$t('panel.enter_template_name_tips')" clearable="true" />
|
||||
<el-col span="12">
|
||||
<el-input v-model="searchText" size="small" class="title-right" :placeholder="$t('panel.enter_template_name_tips')" clearable="true" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col span="20" style="margin-top: 15px">
|
||||
<el-tabs v-model="marketActiveTab" @tab-click="handleClick">
|
||||
<el-tab-pane v-for="tabItem in marketTabs" :key="tabItem" :label="tabItem" :name="tabItem" />
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="networkStatus">
|
||||
<el-row v-loading="$store.getters.loadingMap[$store.getters.currentPath]" style="text-align: center;">
|
||||
<el-row v-if="networkStatus" class="template-main">
|
||||
<el-row v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<template-market-item
|
||||
v-for="(templateItem) in currentMarketTemplateShowList"
|
||||
v-show="templateItem.showFlag"
|
||||
@ -34,6 +28,12 @@
|
||||
@templateApply="templateApply"
|
||||
@templatePreview="templatePreview"
|
||||
/>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row v-else class="custom-position">
|
||||
{{ $t('panel.market_network_tips') }}
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
|
||||
:title="$t('panel.apply_template')"
|
||||
@ -65,18 +65,7 @@
|
||||
<el-button size="mini" type="primary" :disabled="!panelForm.name || !panelForm.pid" @click="apply">{{ $t('commons.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--预览-->
|
||||
<el-dialog top="5vh" width="80%" append-to-body="true" :visible.sync="previewVisible">
|
||||
<img width="100%" :src="templatePreviewUrl" alt="">
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row v-else class="custom-position">
|
||||
{{ $t('panel.market_network_tips') }}
|
||||
</el-row>
|
||||
|
||||
</el-row>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -85,14 +74,16 @@ import TemplateMarketItem from '@/views/panel/templateMarket/component/TemplateM
|
||||
import { groupTree, panelSave } from '@/api/panel/panel'
|
||||
import bus from '@/utils/bus'
|
||||
import { DEFAULT_COMMON_CANVAS_STYLE_STRING } from '@/views/panel/panel'
|
||||
import MarketPreview from '@/views/panel/templateMarket/component/MarketPreview'
|
||||
|
||||
export default {
|
||||
name: 'TemplateMarket',
|
||||
components: { TemplateMarketItem },
|
||||
components: { MarketPreview, TemplateMarketItem },
|
||||
data() {
|
||||
return {
|
||||
previewModel: false,
|
||||
previewVisible: false,
|
||||
templatePreviewUrl: null,
|
||||
templatePreviewId: '',
|
||||
marketTabs: null,
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
@ -178,7 +169,7 @@ export default {
|
||||
showClose: true
|
||||
})
|
||||
this.folderSelectShow = false
|
||||
bus.$emit('newPanelFromMarket', response.data)
|
||||
this.$router.push({ name: 'panel', params: response.data })
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
@ -207,9 +198,9 @@ export default {
|
||||
}
|
||||
return categoryMarch && searchMarch
|
||||
},
|
||||
templatePreview(url) {
|
||||
this.templatePreviewUrl = url
|
||||
this.previewVisible = true
|
||||
templatePreview(previewId) {
|
||||
this.templatePreviewId = previewId
|
||||
this.previewModel = true
|
||||
},
|
||||
newPanel() {
|
||||
|
||||
@ -219,6 +210,26 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.template-main{
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
border: solid 2px #fff;
|
||||
padding-bottom: 24px;
|
||||
min-height: calc(100vh - 190px);
|
||||
}
|
||||
.market-main{
|
||||
padding:24px
|
||||
}
|
||||
.title-left{
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
}
|
||||
.title-right{
|
||||
float: right;
|
||||
width: 320px;
|
||||
}
|
||||
.dialog-footer-self{
|
||||
text-align: center;
|
||||
}
|
||||
@ -256,5 +267,9 @@ export default {
|
||||
flex-flow: row nowrap;
|
||||
color: #9ea6b2;
|
||||
}
|
||||
.outer-body{
|
||||
width: 100%;
|
||||
height: calc(100vh - 56px);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
265
frontend/src/views/system/SysParam/MapSetting/MapSettingLeft.vue
Normal file
265
frontend/src/views/system/SysParam/MapSetting/MapSettingLeft.vue
Normal file
@ -0,0 +1,265 @@
|
||||
<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="!isChina(data.code)" 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="!isGlobal(data.code)" 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)
|
||||
},
|
||||
isChina(code) {
|
||||
return code && code.startsWith('156')
|
||||
},
|
||||
isGlobal(code) {
|
||||
return code && code.startsWith('000')
|
||||
}
|
||||
}
|
||||
}
|
||||
</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]" style="height: calc(100vh - 150px);">
|
||||
|
||||
<de-aside-container type="mapset" style="height: 100%;">
|
||||
<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 style="height: 100%;">
|
||||
<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>
|
@ -10,6 +10,10 @@
|
||||
<email-setting />
|
||||
</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-tab-pane v-if="isPluginLoaded" :lazy="true" :label="$t('sysParams.display')" name="second">
|
||||
<plugin-com v-if="isPluginLoaded" ref="DisplaySetting" component-name="DisplaySetting" />
|
||||
</el-tab-pane>
|
||||
@ -47,6 +51,7 @@
|
||||
</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,10 +1,10 @@
|
||||
<template>
|
||||
<layout-content v-if="!noLayout" v-loading="jsname && !innerLoadingNames.includes(jsname) && $store.getters.loadingMap[$store.getters.currentPath]" :header="header" :back-name="backName">
|
||||
<de-layout-content v-if="!noLayout" v-loading="jsname && !innerLoadingNames.includes(jsname) && $store.getters.loadingMap[$store.getters.currentPath]" :header="header" :back-name="backName">
|
||||
<async-component v-if="showAsync" :url="url" @execute-axios="executeAxios" @on-add-languanges="addLanguages" @on-plugin-layout="setLayoutInfo" @plugin-call-back="pluginCallBack" />
|
||||
<div v-else>
|
||||
<h1>未知组件无法展示</h1>
|
||||
</div>
|
||||
</layout-content>
|
||||
</de-layout-content>
|
||||
<div v-else>
|
||||
<async-component v-if="showAsync" :url="url" @execute-axios="executeAxios" @on-add-languanges="addLanguages" @on-plugin-layout="setLayoutInfo" @plugin-call-back="pluginCallBack" />
|
||||
<div v-else>
|
||||
@ -15,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import DeLayoutContent from '@/components/business/DeLayoutContent'
|
||||
import AsyncComponent from '@/components/AsyncComponent'
|
||||
import i18n from '@/lang'
|
||||
import bus from '@/utils/bus'
|
||||
@ -23,7 +23,7 @@ import { execute } from '@/api/system/dynamic'
|
||||
export default {
|
||||
name: 'Dynamic',
|
||||
components: {
|
||||
LayoutContent,
|
||||
DeLayoutContent,
|
||||
AsyncComponent
|
||||
},
|
||||
props: {
|
||||
@ -69,8 +69,8 @@ export default {
|
||||
options.callBack(res)
|
||||
}
|
||||
}).catch(e => {
|
||||
if (options.callBack) {
|
||||
options.callBack(e)
|
||||
if (options.error) {
|
||||
options.error(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
363
frontend/src/views/system/user/filterUser.vue
Normal file
363
frontend/src/views/system/user/filterUser.vue
Normal file
@ -0,0 +1,363 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
title="筛选条件"
|
||||
:visible.sync="userDrawer"
|
||||
custom-class="user-drawer"
|
||||
size="680px"
|
||||
direction="rtl"
|
||||
>
|
||||
<div class="filter">
|
||||
<span>状态</span>
|
||||
<div class="filter-item">
|
||||
<span
|
||||
@click="statusChange(ele.id)"
|
||||
:class="[activeStatus.includes(ele.id) ? 'active' : '']"
|
||||
:key="ele.id"
|
||||
v-for="ele in status"
|
||||
>{{ ele.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter">
|
||||
<span>组织</span>
|
||||
<div class="filter-item">
|
||||
<span
|
||||
@click="activeDeptChange(ele.id)"
|
||||
:class="[activeDept.includes(ele.id) ? 'active' : '']"
|
||||
:key="ele.id"
|
||||
v-for="ele in selectDepts"
|
||||
>{{ ele.label }}</span>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
popper-class="user-popper"
|
||||
width="200"
|
||||
trigger="click"
|
||||
>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
popper-class="user-popper dept"
|
||||
width="200"
|
||||
trigger="click"
|
||||
>
|
||||
<el-tree
|
||||
:load="loadNode"
|
||||
:lazy="true"
|
||||
:expand-on-click-node="false"
|
||||
:data="depts"
|
||||
:props="defaultProps"
|
||||
@node-click="handleNodeClick"
|
||||
></el-tree>
|
||||
|
||||
<el-select
|
||||
ref="roleSelect"
|
||||
v-model="selectDepts"
|
||||
slot="reference"
|
||||
popper-class="tree-select"
|
||||
multiple
|
||||
:placeholder="$t('commons.please_select')"
|
||||
@change="changeRole"
|
||||
@remove-tag="changeRole"
|
||||
value-key="id"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in selectDepts"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-popover>
|
||||
<span slot="reference">+ 更多</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter">
|
||||
<span>角色</span>
|
||||
<div class="filter-item">
|
||||
<span
|
||||
@click="activeRoleChange(ele.id)"
|
||||
:class="[activeRole.includes(ele.id) ? 'active' : '']"
|
||||
:key="ele.id"
|
||||
v-for="ele in rolesValue"
|
||||
>{{ ele.name }}</span
|
||||
>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
popper-class="user-popper"
|
||||
width="200"
|
||||
trigger="click"
|
||||
>
|
||||
<el-select
|
||||
ref="roleSelect"
|
||||
v-model="rolesValue"
|
||||
multiple
|
||||
:placeholder="$t('commons.please_select')"
|
||||
@change="changeRole"
|
||||
@remove-tag="changeRole"
|
||||
value-key="id"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in roles"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<span slot="reference">+ 更多</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<el-button class="btn normal" @click="reset">{{
|
||||
$t("commons.reset")
|
||||
}}</el-button>
|
||||
<el-button type="primary" class="btn" @click="search">{{
|
||||
$t("commons.adv_search.search")
|
||||
}}</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import bus from '@/utils/bus'
|
||||
import { allRoles } from "@/api/system/user";
|
||||
import { getDeptTree, treeByDeptId } from "@/api/system/dept";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: [],
|
||||
roles: [],
|
||||
status: [{
|
||||
id: 1,
|
||||
label: '启用'
|
||||
},{
|
||||
id: 0,
|
||||
label: '禁用'
|
||||
}],
|
||||
activeStatus: [],
|
||||
rolesValue: [],
|
||||
activeRole: [],
|
||||
depts: [],
|
||||
selectDepts: [],
|
||||
activeDept: [],
|
||||
defaultProps: {
|
||||
children: "children",
|
||||
label: "label",
|
||||
isLeaf: "leaf",
|
||||
},
|
||||
userDrawer: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initRoles();
|
||||
},
|
||||
methods: {
|
||||
// 获取弹窗内部门数据
|
||||
treeByDeptId() {
|
||||
treeByDeptId(0).then((res) => {
|
||||
this.depts = res.data || [];
|
||||
});
|
||||
},
|
||||
changeRole() {
|
||||
const roles = this.rolesValue.map((item) => item.id);
|
||||
this.activeRole = this.activeRole.filter((ele) => roles.includes(ele));
|
||||
},
|
||||
activeRoleChange(id) {
|
||||
const roleIndex = this.activeRole.findIndex((ele) => ele === id);
|
||||
if (roleIndex === -1) {
|
||||
this.activeRole.push(id);
|
||||
} else {
|
||||
this.activeRole.splice(roleIndex, 1);
|
||||
}
|
||||
},
|
||||
handleNodeClick({ id, label }) {
|
||||
const deptIndex = this.selectDepts.findIndex((ele) => ele.id === id);
|
||||
if (deptIndex === -1) {
|
||||
this.selectDepts.push({ id, label });
|
||||
} else {
|
||||
this.selectDepts.splice(deptIndex, 1);
|
||||
this.changeDepts();
|
||||
}
|
||||
},
|
||||
activeDeptChange(id) {
|
||||
const deptIndex = this.activeDept.findIndex((ele) => ele === id);
|
||||
if (deptIndex === -1) {
|
||||
this.activeDept.push(id);
|
||||
} else {
|
||||
this.activeDept.splice(deptIndex, 1);
|
||||
}
|
||||
},
|
||||
statusChange(id) {
|
||||
const statusIndex = this.activeStatus.findIndex((ele) => ele === id);
|
||||
if (statusIndex === -1) {
|
||||
this.activeStatus.push(id);
|
||||
} else {
|
||||
this.activeStatus.splice(statusIndex, 1);
|
||||
}
|
||||
},
|
||||
changeDepts() {
|
||||
const depts = this.selectDepts.map((item) => item.id);
|
||||
this.activeDept = this.activeDept.filter((ele) => depts.includes(ele));
|
||||
},
|
||||
loadNode(node, resolve) {
|
||||
if (!this.depts.length) {
|
||||
this.treeByDeptId();
|
||||
return;
|
||||
}
|
||||
getDeptTree(node.data.id).then((res) => {
|
||||
resolve(
|
||||
res.data.map((dept) => {
|
||||
return this.normalizer(dept);
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
normalizer(node) {
|
||||
return {
|
||||
id: node.deptId,
|
||||
label: node.name,
|
||||
leaf: !node.hasChildren,
|
||||
};
|
||||
},
|
||||
initRoles() {
|
||||
allRoles().then((res) => {
|
||||
this.roles = res.data;
|
||||
});
|
||||
},
|
||||
search() {
|
||||
this.userDrawer = false;
|
||||
this.$emit('search', this.formatCondition())
|
||||
},
|
||||
formatCondition() {
|
||||
const fildMap = {'r.role_id': this.activeRole, 'd.dept_id': this.activeDept, 'u.enabled': this.activeStatus}
|
||||
const conditions = []
|
||||
Object.keys(fildMap).forEach(ele => {
|
||||
if (fildMap[ele].length) {
|
||||
conditions.push({
|
||||
field: ele,
|
||||
operator: 'in',
|
||||
value: fildMap[ele]
|
||||
})
|
||||
}
|
||||
})
|
||||
return conditions;
|
||||
},
|
||||
init() {
|
||||
this.userDrawer = true;
|
||||
},
|
||||
reset() {
|
||||
this.activeStatus = [];
|
||||
this.activeRole = [];
|
||||
this.activeDept = [];
|
||||
this.search()
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.user-drawer {
|
||||
.el-drawer__header {
|
||||
padding: 16px 21px 16px 24px;
|
||||
font-family: PingFang SC;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
color: #1f2329;
|
||||
border-bottom: 1px solid rgba(187, 191, 196, 0.5);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-drawer__body {
|
||||
padding: 12px 24px 24px 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 46px;
|
||||
> :nth-child(1) {
|
||||
margin-right: 88px;
|
||||
color: #1f2329;
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
.filter-item {
|
||||
span {
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
margin-right: 12px;
|
||||
text-align: center;
|
||||
padding: 1px 6px;
|
||||
background: #f5f6f7;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
span {
|
||||
margin-right: 0;
|
||||
padding: 0;
|
||||
span {
|
||||
margin-right: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
background: rgba(51, 112, 255, 0.1);
|
||||
color: #0c296e;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
border-radius: 4px;
|
||||
padding: 5px 26px 5px 26px;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.normal {
|
||||
color: #1f2329;
|
||||
border: 1px solid #bbbfc4;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.foot {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.user-popper {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
.popper__arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.tree-select {
|
||||
.el-select-dropdown__empty,
|
||||
.popper__arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.user-popper.dept {
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
@ -1,352 +0,0 @@
|
||||
<template>
|
||||
<layout-content :header="formType=='add' ? $t('user.create') : $t('user.modify')" back-name="system-user">
|
||||
<el-form ref="createUserForm" :model="form" :rules="rule" size="small" label-width="80px" label-position="right">
|
||||
<el-form-item label="ID" prop="username">
|
||||
<el-input v-model="form.username" :disabled="formType !== 'add'" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.phone')" prop="phone">
|
||||
<el-input v-model="form.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.nick_name')" prop="nickName">
|
||||
<el-input v-model="form.nickName" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.email')" prop="email">
|
||||
<el-input v-model="form.email" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item v-if="formType !== 'modify'" :label="$t('commons.password')" prop="password">
|
||||
<el-input v-model="form.password" autocomplete="off" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formType !== 'modify'" :label="$t('commons.confirmPassword')" prop="confirmPassword">
|
||||
<el-input v-model="form.confirmPassword" autocomplete="off" show-password />
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item :label="$t('commons.gender')" prop="gender">
|
||||
<el-radio-group v-model="form.gender" style="width: 178px">
|
||||
<el-radio :label="$t('commons.man')">{{ $t('commons.man') }}</el-radio>
|
||||
<el-radio :label="$t('commons.woman')">{{ $t('commons.woman') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.status')" prop="enabled">
|
||||
<el-radio-group v-model="form.enabled" :disabled="formType !== 'add' && form.isAdmin" style="width: 140px">
|
||||
<el-radio :label="1">{{ $t('commons.enable') }}</el-radio>
|
||||
<el-radio :label="0">{{ $t('commons.disable') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="isPluginLoaded" :label="$t('commons.organization')" prop="deptId">
|
||||
<treeselect
|
||||
ref="deptTreeSelect"
|
||||
v-model="form.deptId"
|
||||
:options="depts"
|
||||
:load-options="loadDepts"
|
||||
:auto-load-root-options="false"
|
||||
:placeholder="$t('user.choose_org')"
|
||||
:no-children-text="$t('commons.treeselect.no_children_text')"
|
||||
:no-options-text="$t('commons.treeselect.no_options_text')"
|
||||
:no-results-text="$t('commons.treeselect.no_results_text')"
|
||||
@open="filterData"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="isPluginLoaded" :label="$t('commons.role')" prop="roleIds">
|
||||
<el-select
|
||||
ref="roleSelect"
|
||||
v-model="form.roleIds"
|
||||
style="width: 100%"
|
||||
:disabled="formType !== 'add' && form.isAdmin"
|
||||
multiple
|
||||
:placeholder="$t('commons.please_select')"
|
||||
@remove-tag="deleteTag"
|
||||
@change="changeRole"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in roles"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="save">{{ $t('commons.confirm') }}</el-button>
|
||||
<el-button @click="reset">{{ $t('commons.reset') }}</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="formType === 'add'">
|
||||
<!-- <el-link class="pwd-tips" type="danger" :underline="false">{{ $t('commons.default_pwd') + ':' + defaultPWD }}</el-link> -->
|
||||
<el-button class="pwd-tips" type="text">{{ $t('commons.default_pwd') + ':' + defaultPWD }}</el-button>
|
||||
<el-button
|
||||
v-clipboard:copy="defaultPWD"
|
||||
v-clipboard:success="onCopy"
|
||||
v-clipboard:error="onError"
|
||||
type="text"
|
||||
>
|
||||
{{ $t('commons.copy') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import { PHONE_REGEX } from '@/utils/validate'
|
||||
import { getDeptTree, treeByDeptId } from '@/api/system/dept'
|
||||
import { addUser, editUser, allRoles } from '@/api/system/user'
|
||||
import { pluginLoaded, defaultPwd } from '@/api/user'
|
||||
export default {
|
||||
|
||||
components: { LayoutContent },
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
roles: [{
|
||||
id: ''
|
||||
}]
|
||||
},
|
||||
rule: {
|
||||
username: [
|
||||
{ required: true, message: this.$t('user.input_id'), trigger: 'blur' },
|
||||
{ min: 1, max: 50, message: this.$t('commons.input_limit', [1, 50]), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: '^[^\u4e00-\u9fa5]+$',
|
||||
message: this.$t('user.special_characters_are_not_supported'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
nickName: [
|
||||
{ required: true, message: this.$t('user.input_name'), trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: this.$t('commons.input_limit', [2, 50]), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('user.special_characters_are_not_supported'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('user.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: this.$t('user.input_email'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
|
||||
message: this.$t('user.email_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: this.$t('user.input_password'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t('member.password_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, message: this.$t('user.input_password'), trigger: 'blur' },
|
||||
{ required: true, validator: this.repeatValidator, trigger: 'blur' }
|
||||
],
|
||||
newPassword: [
|
||||
{ required: true, message: this.$t('user.input_password'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t('member.password_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
roleIds: [{ required: true, message: this.$t('user.input_roles'), trigger: 'change' }],
|
||||
deptId: [],
|
||||
gender: [],
|
||||
enable: []
|
||||
|
||||
},
|
||||
defaultForm: { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 1, deptId: null, phone: null, roleIds: [2] },
|
||||
depts: null,
|
||||
roles: [],
|
||||
roleDatas: [],
|
||||
userRoles: [],
|
||||
formType: 'add',
|
||||
isPluginLoaded: false,
|
||||
defaultPWD: 'DataEase123..'
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.$router.currentRoute.params && this.$router.currentRoute.params.id) {
|
||||
const row = this.$router.currentRoute.params
|
||||
this.edit(row)
|
||||
} else {
|
||||
this.create()
|
||||
}
|
||||
this.initRoles()
|
||||
},
|
||||
mounted() {
|
||||
this.bindKey()
|
||||
},
|
||||
destroyed() {
|
||||
this.unBindKey()
|
||||
},
|
||||
beforeCreate() {
|
||||
pluginLoaded().then(res => {
|
||||
this.isPluginLoaded = res.success && res.data
|
||||
})
|
||||
defaultPwd().then(res => {
|
||||
if (res && res.data) {
|
||||
this.defaultPWD = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
entryKey(event) {
|
||||
const keyCode = event.keyCode
|
||||
if (keyCode === 13) {
|
||||
this.save()
|
||||
}
|
||||
},
|
||||
bindKey() {
|
||||
document.addEventListener('keypress', this.entryKey)
|
||||
},
|
||||
unBindKey() {
|
||||
document.removeEventListener('keypress', this.entryKey)
|
||||
},
|
||||
repeatValidator(rule, value, callback) {
|
||||
if (value !== this.form.password) {
|
||||
callback(new Error(this.$t('member.inconsistent_passwords')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
create() {
|
||||
this.depts = null
|
||||
this.formType = 'add'
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
},
|
||||
edit(row) {
|
||||
this.depts = null
|
||||
this.formType = 'modify'
|
||||
this.dialogVisible = true
|
||||
this.form = Object.assign({}, row)
|
||||
this.form.password = ''
|
||||
if (this.form.deptId === 0) {
|
||||
this.form.deptId = null
|
||||
}
|
||||
this.initDeptTree()
|
||||
},
|
||||
initRoles() {
|
||||
allRoles().then(res => {
|
||||
this.roles = res.data
|
||||
})
|
||||
},
|
||||
initDeptTree() {
|
||||
treeByDeptId(this.form.deptId || 0).then(res => {
|
||||
const results = res.data.map(node => {
|
||||
if (node.hasChildren && !node.children) {
|
||||
node.children = null
|
||||
// delete node.children
|
||||
}
|
||||
return node
|
||||
})
|
||||
this.depts = results
|
||||
})
|
||||
},
|
||||
// 获取弹窗内部门数据
|
||||
loadDepts({ action, parentNode, callback }) {
|
||||
if (action === 'LOAD_ROOT_OPTIONS' && !this.form.deptId) {
|
||||
const _self = this
|
||||
treeByDeptId(0).then(res => {
|
||||
const results = res.data.map(node => {
|
||||
if (node.hasChildren && !node.children) {
|
||||
node.children = null
|
||||
}
|
||||
return node
|
||||
})
|
||||
_self.depts = results
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
if (action === 'LOAD_CHILDREN_OPTIONS') {
|
||||
const _self = this
|
||||
getDeptTree(parentNode.id).then(res => {
|
||||
parentNode.children = res.data.map(function(obj) {
|
||||
return _self.normalizer(obj)
|
||||
})
|
||||
callback()
|
||||
})
|
||||
}
|
||||
},
|
||||
normalizer(node) {
|
||||
if (node.hasChildren) {
|
||||
node.children = null
|
||||
}
|
||||
return {
|
||||
id: node.deptId,
|
||||
label: node.name,
|
||||
children: node.children
|
||||
}
|
||||
},
|
||||
deleteTag(value) {
|
||||
this.userRoles.forEach(function(data, index) {
|
||||
if (data.id === value) {
|
||||
this.userRoles.splice(index, value)
|
||||
}
|
||||
}.bind(this))
|
||||
},
|
||||
changeRole(value) {
|
||||
this.userRoles = []
|
||||
value.forEach(function(data, index) {
|
||||
const role = { id: data }
|
||||
this.userRoles.push(role)
|
||||
}.bind(this))
|
||||
},
|
||||
reset() {
|
||||
this.$refs.createUserForm.resetFields()
|
||||
},
|
||||
save() {
|
||||
this.$refs.createUserForm.validate(valid => {
|
||||
if (valid) {
|
||||
// !this.form.deptId && (this.form.deptId = 0)
|
||||
const method = this.formType === 'add' ? addUser : editUser
|
||||
method(this.form).then(res => {
|
||||
this.$success(this.$t('commons.save_success'))
|
||||
this.backToList()
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
backToList() {
|
||||
this.$router.push({ name: 'system-user' })
|
||||
},
|
||||
filterData(instanceId) {
|
||||
this.$refs.roleSelect && this.$refs.roleSelect.blur && this.$refs.roleSelect.blur()
|
||||
if (!this.depts) {
|
||||
return
|
||||
}
|
||||
const results = this.depts.map(node => {
|
||||
if (node.hasChildren) {
|
||||
node.children = null
|
||||
}
|
||||
return node
|
||||
})
|
||||
this.depts = results
|
||||
},
|
||||
onCopy(e) {
|
||||
this.$success(this.$t('commons.copy_success'))
|
||||
},
|
||||
onError(e) {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
578
frontend/src/views/system/user/userEditer.vue
Normal file
578
frontend/src/views/system/user/userEditer.vue
Normal file
@ -0,0 +1,578 @@
|
||||
<template>
|
||||
<!-- <layout-content :header="formType=='add' ? $t('user.create') : $t('user.modify')" back-name="system-user">
|
||||
</layout-content> -->
|
||||
<el-dialog
|
||||
:title="formType == 'add' ? $t('user.create') : $t('user.modify')"
|
||||
:visible.sync="dialogVisible"
|
||||
class="user-editer-form"
|
||||
width="840px"
|
||||
:before-close="reset"
|
||||
>
|
||||
<div v-if="formType === 'add'" class="editer-form-title">
|
||||
<i class="el-icon-info"></i>
|
||||
<span class="pwd" type="text">{{
|
||||
$t("commons.default_pwd") + ":" + defaultPWD
|
||||
}}</span>
|
||||
<el-button
|
||||
v-clipboard:copy="defaultPWD"
|
||||
v-clipboard:success="onCopy"
|
||||
v-clipboard:error="onError"
|
||||
class="btn-text"
|
||||
type="text"
|
||||
>
|
||||
{{ $t("commons.copy") }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
ref="createUserForm"
|
||||
:model="form"
|
||||
:rules="rule"
|
||||
size="small"
|
||||
label-width="80px"
|
||||
label-position="right"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('commons.nick_name')" prop="nickName">
|
||||
<el-input
|
||||
:placeholder="$t('user.input_name')"
|
||||
v-model="form.nickName"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="ID" prop="username">
|
||||
<el-input
|
||||
:placeholder="$t('user.input_id')"
|
||||
v-model="form.username"
|
||||
:disabled="formType !== 'add'"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('commons.email')" prop="email">
|
||||
<el-input
|
||||
:placeholder="$t('user.input_email')"
|
||||
v-model="form.email"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('commons.mobile_phone_number')" prop="phone">
|
||||
<el-input
|
||||
:placeholder="$t('commons.mobile_phone')"
|
||||
v-model="form.phone"
|
||||
class="input-with-select"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.phonePrefix"
|
||||
slot="prepend"
|
||||
:placeholder="$t('fu.search_bar.please_select')"
|
||||
>
|
||||
<el-option label="+86" value="+86"></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('commons.gender')" prop="gender">
|
||||
<el-select
|
||||
class="form-gender-select"
|
||||
v-model="form.gender"
|
||||
:placeholder="$t('user.select_gender')"
|
||||
>
|
||||
<el-option :label="$t('commons.man')" value="男"> </el-option>
|
||||
<el-option :label="$t('commons.woman')" value="女"> </el-option>
|
||||
<el-option :label="$t('commons.keep_secret')" value="保密">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-show="isPluginLoaded"
|
||||
:label="$t('commons.organization')"
|
||||
prop="deptId"
|
||||
>
|
||||
<treeselect
|
||||
ref="deptTreeSelect"
|
||||
v-model="form.deptId"
|
||||
:options="depts"
|
||||
:load-options="loadDepts"
|
||||
:auto-load-root-options="false"
|
||||
:placeholder="$t('user.choose_org')"
|
||||
:no-children-text="$t('commons.treeselect.no_children_text')"
|
||||
:no-options-text="$t('commons.treeselect.no_options_text')"
|
||||
:no-results-text="$t('commons.treeselect.no_results_text')"
|
||||
@open="filterData"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- <el-form-item v-if="formType !== 'modify'" :label="$t('commons.password')" prop="password">
|
||||
<el-input v-model="form.password" autocomplete="off" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formType !== 'modify'" :label="$t('commons.confirmPassword')" prop="confirmPassword">
|
||||
<el-input v-model="form.confirmPassword" autocomplete="off" show-password />
|
||||
</el-form-item> -->
|
||||
<el-form-item
|
||||
v-show="isPluginLoaded"
|
||||
:label="$t('commons.role')"
|
||||
prop="roleIds"
|
||||
>
|
||||
<el-select
|
||||
ref="roleSelect"
|
||||
v-model="form.roleIds"
|
||||
style="width: 100%"
|
||||
:disabled="formType !== 'add' && form.isAdmin"
|
||||
multiple
|
||||
:placeholder="$t('user.input_roles')"
|
||||
@remove-tag="deleteTag"
|
||||
@change="changeRole"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in roles"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.status')" prop="enabled">
|
||||
<el-switch
|
||||
:disabled="formType !== 'add' && form.isAdmin"
|
||||
v-model="form.enabled"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button class="btn normal" @click="reset">{{
|
||||
$t("commons.cancel")
|
||||
}}</el-button>
|
||||
<el-button class="btn" type="primary" @click="save">{{
|
||||
$t("commons.confirm")
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { PHONE_REGEX } from "@/utils/validate";
|
||||
import { getDeptTree, treeByDeptId } from "@/api/system/dept";
|
||||
import { addUser, editUser, allRoles } from "@/api/system/user";
|
||||
import { pluginLoaded, defaultPwd } from "@/api/user";
|
||||
import {
|
||||
LOAD_CHILDREN_OPTIONS,
|
||||
LOAD_ROOT_OPTIONS,
|
||||
} from "@riophae/vue-treeselect";
|
||||
import Treeselect from "@riophae/vue-treeselect";
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
export default {
|
||||
components: { Treeselect },
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
roles: [
|
||||
{
|
||||
id: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
rule: {
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.id_mandatory"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
min: 1,
|
||||
max: 50,
|
||||
message: this.$t("commons.input_limit", [1, 50]),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
pattern: "^[^\u4e00-\u9fa5]+$",
|
||||
message: this.$t("user.special_characters_are_not_supported"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
nickName: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.name_mandatory"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
min: 2,
|
||||
max: 50,
|
||||
message: this.$t("commons.input_limit", [2, 50]),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.special_characters_are_not_supported"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t("user.phone_format"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.email_mandatory"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
pattern: /^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
|
||||
message: this.$t("user.email_format_is_incorrect"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.input_password"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t("member.password_format_is_incorrect"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
confirmPassword: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.input_password"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{ required: true, validator: this.repeatValidator, trigger: "blur" },
|
||||
],
|
||||
newPassword: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.input_password"),
|
||||
trigger: "blur",
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t("member.password_format_is_incorrect"),
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
roleIds: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("user.role_mandatory"),
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
deptId: [],
|
||||
gender: [],
|
||||
enabled: [{ required: true, trigger: "change" }],
|
||||
},
|
||||
defaultForm: {
|
||||
id: null,
|
||||
username: null,
|
||||
nickName: null,
|
||||
gender: "男",
|
||||
email: null,
|
||||
enabled: 1,
|
||||
deptId: null,
|
||||
phone: null,
|
||||
phonePrefix: "+86",
|
||||
roleIds: [2],
|
||||
},
|
||||
depts: null,
|
||||
roles: [],
|
||||
roleDatas: [],
|
||||
userRoles: [],
|
||||
formType: "add",
|
||||
isPluginLoaded: false,
|
||||
defaultPWD: "DataEase123..",
|
||||
dialogVisible: false,
|
||||
};
|
||||
},
|
||||
beforeCreate() {
|
||||
pluginLoaded().then((res) => {
|
||||
this.isPluginLoaded = res.success && res.data;
|
||||
});
|
||||
defaultPwd().then((res) => {
|
||||
if (res && res.data) {
|
||||
this.defaultPWD = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
repeatValidator(rule, value, callback) {
|
||||
if (value !== this.form.password) {
|
||||
callback(new Error(this.$t("member.inconsistent_passwords")));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
create() {
|
||||
this.depts = null;
|
||||
this.formType = "add";
|
||||
this.form = Object.assign({}, this.defaultForm);
|
||||
},
|
||||
init(row) {
|
||||
this.initRoles();
|
||||
this.dialogVisible = true;
|
||||
if (!row) {
|
||||
this.create();
|
||||
return;
|
||||
}
|
||||
this.depts = null;
|
||||
this.formType = "modify";
|
||||
this.dialogVisible = true;
|
||||
this.form = Object.assign({}, row);
|
||||
this.form.password = "";
|
||||
if (this.form.deptId === 0) {
|
||||
this.form.deptId = null;
|
||||
}
|
||||
|
||||
if (!this.form.phonePrefix) {
|
||||
this.form.phonePrefix = '+86';
|
||||
}
|
||||
this.initDeptTree();
|
||||
},
|
||||
initRoles() {
|
||||
allRoles().then((res) => {
|
||||
this.roles = res.data;
|
||||
});
|
||||
},
|
||||
initDeptTree() {
|
||||
treeByDeptId(this.form.deptId || 0).then((res) => {
|
||||
const results = res.data.map((node) => {
|
||||
if (node.hasChildren && !node.children) {
|
||||
node.children = null;
|
||||
// delete node.children
|
||||
}
|
||||
return node;
|
||||
});
|
||||
this.depts = results;
|
||||
});
|
||||
},
|
||||
// 获取弹窗内部门数据
|
||||
loadDepts({ action, parentNode, callback }) {
|
||||
if (action === "LOAD_ROOT_OPTIONS" && !this.form.deptId) {
|
||||
const _self = this;
|
||||
treeByDeptId(0).then((res) => {
|
||||
const results = res.data.map((node) => {
|
||||
if (node.hasChildren && !node.children) {
|
||||
node.children = null;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
_self.depts = results;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
if (action === "LOAD_CHILDREN_OPTIONS") {
|
||||
const _self = this;
|
||||
getDeptTree(parentNode.id).then((res) => {
|
||||
parentNode.children = res.data.map(function (obj) {
|
||||
return _self.normalizer(obj);
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}
|
||||
},
|
||||
normalizer(node) {
|
||||
if (node.hasChildren) {
|
||||
node.children = null;
|
||||
}
|
||||
return {
|
||||
id: node.deptId,
|
||||
label: node.name,
|
||||
children: node.children,
|
||||
};
|
||||
},
|
||||
deleteTag(value) {
|
||||
this.userRoles.forEach(
|
||||
function (data, index) {
|
||||
if (data.id === value) {
|
||||
this.userRoles.splice(index, value);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
changeRole(value) {
|
||||
this.userRoles = [];
|
||||
value.forEach(
|
||||
function (data, index) {
|
||||
const role = { id: data };
|
||||
this.userRoles.push(role);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
reset() {
|
||||
this.$refs.createUserForm.resetFields();
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
save() {
|
||||
this.$refs.createUserForm.validate((valid) => {
|
||||
if (valid) {
|
||||
// !this.form.deptId && (this.form.deptId = 0)
|
||||
const method = this.formType === "add" ? addUser : editUser;
|
||||
method(this.form).then((res) => {
|
||||
this.$success(this.$t("commons.save_success"));
|
||||
this.reset();
|
||||
this.$emit('saved')
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
filterData(instanceId) {
|
||||
this.$refs.roleSelect &&
|
||||
this.$refs.roleSelect.blur &&
|
||||
this.$refs.roleSelect.blur();
|
||||
if (!this.depts) {
|
||||
return;
|
||||
}
|
||||
const results = this.depts.map((node) => {
|
||||
if (node.hasChildren) {
|
||||
node.children = null;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
this.depts = results;
|
||||
},
|
||||
onCopy(e) {
|
||||
this.$success(this.$t("commons.copy_success"));
|
||||
},
|
||||
onError(e) {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-editer-form {
|
||||
::v-deep .el-dialog__body {
|
||||
padding: 0 24px 24px 24px;
|
||||
}
|
||||
|
||||
::v-deep .el-dialog__header {
|
||||
padding: 24px 24px 16px 24px;
|
||||
}
|
||||
|
||||
::v-deep .el-dialog__footer {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.editer-form-title {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
background: #e1eaff;
|
||||
padding: 9px 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
i {
|
||||
color: #3370ff;
|
||||
font-size: 14.666666030883789px;
|
||||
}
|
||||
|
||||
.pwd,
|
||||
.btn-text {
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__label {
|
||||
width: 100% !important;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
::v-deep
|
||||
.el-form-item.is-required:not(.is-no-asterisk)
|
||||
> .el-form-item__label:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep
|
||||
.el-form-item.is-required:not(.is-no-asterisk)
|
||||
> .el-form-item__label::after {
|
||||
content: "*";
|
||||
color: #f54a45;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.input-with-select {
|
||||
::v-deep .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
.el-select {
|
||||
::v-deep .el-input__inner {
|
||||
width: 72px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-radius: 4px;
|
||||
padding: 5px 26px 5px 26px;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.normal {
|
||||
color: #1f2329;
|
||||
border: 1px solid #bbbfc4;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.form-gender-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
}
|
||||
}
|
||||
</style>
|
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