Merge pull request #814 from dataease/dev

Dev
This commit is contained in:
fit2cloudrd 2021-09-15 09:46:31 +08:00 committed by GitHub
commit 9c157603c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 700 additions and 88 deletions

1
.gitignore vendored
View File

@ -40,6 +40,7 @@ yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.lh
.idea
.vscode
*.suo

View File

@ -252,11 +252,11 @@
<version>20171018</version>
</dependency>
<dependency>
<!--<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependency>-->
<!-- 反射工具包 -->
<dependency>
<groupId>net.oneandone.reflections8</groupId>

View File

@ -4,9 +4,7 @@ import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.auth.api.dto.LoginDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -46,4 +44,9 @@ public interface AuthApi {
@PostMapping("/isOpenLdap")
boolean isOpenLdap();
@ApiOperation("是否开启oidc")
@PostMapping("/isOpenOidc")
boolean isOpenOidc();
}

View File

@ -13,6 +13,8 @@ public class TokenInfo implements Serializable {
private Long userId;
/* private String idToken; */
public String format(){
return username + "," +userId;
}

View File

@ -4,7 +4,6 @@ import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

View File

@ -21,17 +21,19 @@ import io.dataease.plugins.util.PluginUtils;
import io.dataease.plugins.xpack.ldap.dto.request.LdapValidateRequest;
import io.dataease.plugins.xpack.ldap.dto.response.ValidateResult;
import io.dataease.plugins.xpack.ldap.service.LdapXpackService;
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@RestController
public class AuthServer implements AuthApi {
@ -113,6 +115,13 @@ public class AuthServer implements AuthApi {
@Override
public String logout() {
String token = ServletUtils.getToken();
if (isOpenOidc()) {
HttpServletRequest request = ServletUtils.request();
String idToken = request.getHeader("IdToken");
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
oidcXpackService.logout(idToken);
}
if (StringUtils.isEmpty(token) || StringUtils.equals("null", token) || StringUtils.equals("undefined", token)) {
return "success";
}
@ -144,6 +153,15 @@ public class AuthServer implements AuthApi {
return open;
}
@Override
public boolean isOpenOidc() {
Boolean licValid = PluginUtils.licValid();
if(!licValid) return false;
return authUserService.supportOidc();
}
/*@Override
public Boolean isLogin() {
return null;

View File

@ -23,6 +23,8 @@ public interface AuthUserService {
boolean supportLdap();
Boolean supportOidc();
}

View File

@ -10,6 +10,8 @@ import io.dataease.commons.constants.AuthConstants;
import io.dataease.commons.utils.LogUtil;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.ldap.service.LdapXpackService;
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
@ -19,6 +21,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@ -107,8 +110,21 @@ public class AuthUserServiceImpl implements AuthUserService {
@Override
public boolean supportLdap() {
Map<String, LdapXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((LdapXpackService.class));
if(beansOfType.keySet().size() == 0) return false;
LdapXpackService ldapXpackService = SpringContextUtil.getBean(LdapXpackService.class);
if(ObjectUtils.isEmpty(ldapXpackService)) return false;
return ldapXpackService.isOpen();
}
@Override
public Boolean supportOidc() {
Map<String, OidcXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((OidcXpackService.class));
if(beansOfType.keySet().size() == 0) return false;
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
if(ObjectUtils.isEmpty(oidcXpackService)) return false;
return oidcXpackService.isSuuportOIDC();
}
}

View File

@ -56,9 +56,15 @@ public class ShiroServiceImpl implements ShiroService {
// filterChainDefinitionMap.put("/axios.map", ANON);
filterChainDefinitionMap.put("/api/auth/login", ANON);
filterChainDefinitionMap.put("/api/auth/logout", ANON);
// filterChainDefinitionMap.put("/api/auth/logout", ANON);
filterChainDefinitionMap.put("/api/auth/validateName", ANON);
filterChainDefinitionMap.put("/api/auth/isOpenLdap", ANON);
filterChainDefinitionMap.put("/api/auth/isOpenOidc", ANON);
filterChainDefinitionMap.put("/api/pluginCommon/component/*", ANON);
filterChainDefinitionMap.put("/plugin/oidc/authInfo", ANON);
filterChainDefinitionMap.put("/sso/callBack*", ANON);
filterChainDefinitionMap.put("/unauth", ANON);
filterChainDefinitionMap.put("/display/**", ANON);
filterChainDefinitionMap.put("/tokenExpired", ANON);

View File

@ -2,16 +2,18 @@ package io.dataease.auth.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.JWTCreator.Builder;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.exception.DataEaseException;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import java.util.Date;
@ -34,10 +36,13 @@ public class JWTUtils {
*/
public static boolean verify(String token, TokenInfo tokenInfo, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
Verification verification = JWT.require(algorithm)
.withClaim("username", tokenInfo.getUsername())
.withClaim("userId", tokenInfo.getUserId())
.build();
.withClaim("userId", tokenInfo.getUserId());
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
verification.withClaim("idToken", tokenInfo.getIdToken());
} */
JWTVerifier verifier = verification.build();
verifier.verify(token);
return true;
}
@ -50,10 +55,15 @@ public class JWTUtils {
DecodedJWT jwt = JWT.decode(token);
String username = jwt.getClaim("username").asString();
Long userId = jwt.getClaim("userId").asLong();
// String idToken = jwt.getClaim("idToken").asString();
if (StringUtils.isEmpty(username) || ObjectUtils.isEmpty(userId) ){
DataEaseException.throwException("token格式错误");
}
TokenInfo tokenInfo = TokenInfo.builder().username(username).userId(userId).build();
TokenInfoBuilder tokenInfoBuilder = TokenInfo.builder().username(username).userId(userId);
/* if (StringUtils.isNotBlank(idToken)) {
tokenInfoBuilder.idToken(idToken);
} */
TokenInfo tokenInfo = tokenInfoBuilder.build();
return tokenInfo;
}
@ -107,12 +117,14 @@ public class JWTUtils {
try {
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
Builder builder = JWT.create()
.withClaim("username", tokenInfo.getUsername())
.withClaim("userId", tokenInfo.getUserId())
.withExpiresAt(date)
.sign(algorithm);
.withClaim("userId", tokenInfo.getUserId());
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
builder.withClaim("idToken", tokenInfo.getIdToken());
} */
return builder.withExpiresAt(date).sign(algorithm);
} catch (Exception e) {
return null;
}

View File

@ -45,9 +45,12 @@ public class DefaultLicenseService {
}
return f2CLicenseResponse;
}catch (Exception e){
e.printStackTrace();
return F2CLicenseResponse.invalid(e.getMessage());
LogUtil.error(e.getMessage());
// e.printStackTrace();
// return F2CLicenseResponse.invalid(e.getMessage());
return F2CLicenseResponse.noRecord();
}
}

View File

@ -2,6 +2,7 @@ package io.dataease.plugins.config;
import io.dataease.base.domain.MyPlugin;
import io.dataease.plugins.loader.ClassloaderResponsity;
import io.dataease.plugins.loader.ControllerLoader;
import io.dataease.plugins.loader.ModuleClassLoader;
import io.dataease.plugins.loader.MybatisLoader;
import org.springframework.beans.factory.annotation.Autowired;
@ -19,6 +20,9 @@ public class LoadjarUtil {
@Autowired
private MybatisLoader mybatisLoader;
@Autowired
private ControllerLoader controllerLoader;
public List<?> loadJar(String jarPath, MyPlugin myPlugin) throws Exception{
File jar = new File(jarPath);
URI uri = jar.toURI();
@ -34,6 +38,10 @@ public class LoadjarUtil {
Thread.currentThread().setContextClassLoader(classLoader);
classLoader.initBean();
mybatisLoader.loadMybatis(myPlugin);
List<String> controllers = classLoader.getRegisteredController();
controllerLoader.registerController(controllers);
ClassloaderResponsity.getInstance().addClassLoader(moduleName,classLoader);

View File

@ -0,0 +1,95 @@
package io.dataease.plugins.loader;
import io.dataease.commons.utils.LogUtil;
import io.dataease.plugins.config.SpringContextUtil;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
import java.util.List;
@Component
public class ControllerLoader {
/**
* 去掉Controller的Mapping
* @param controllerBeanName
*/
private void unregisterController(String controllerBeanName){
final RequestMappingHandlerMapping requestMappingHandlerMapping=(RequestMappingHandlerMapping)SpringContextUtil.getBean("requestMappingHandlerMapping");
if(requestMappingHandlerMapping!=null){
String handler=controllerBeanName;
Object controller= SpringContextUtil.getBean(handler);
if(controller==null){
return;
}
final Class<?> targetClass=controller.getClass();
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
try {
Method createMappingMethod = RequestMappingHandlerMapping.class.
getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
createMappingMethod.setAccessible(true);
RequestMappingInfo requestMappingInfo =(RequestMappingInfo)
createMappingMethod.invoke(requestMappingHandlerMapping,specificMethod,targetClass);
if(requestMappingInfo != null) {
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
}
}catch (Exception e){
e.printStackTrace();
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
}
/**
* 注册Controller
* @param controllerBeanName
* @throws Exception
*/
private void registerController(String controllerBeanName) throws Exception{
final RequestMappingHandlerMapping requestMappingHandlerMapping=(RequestMappingHandlerMapping) SpringContextUtil.getBean("requestMappingHandlerMapping");
if(requestMappingHandlerMapping!=null){
String handler=controllerBeanName;
Object controller= SpringContextUtil.getBean(handler);
if(controller==null){
return;
}
unregisterController(controllerBeanName);
//注册Controller
Method method=requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod("detectHandlerMethods",Object.class);
method.setAccessible(true);
method.invoke(requestMappingHandlerMapping,handler);
}
}
public void registerController(List<String> beanNames) {
beanNames.forEach(name -> {
try {
registerController(name);
} catch (Exception e) {
// e.printStackTrace();
LogUtil.error(e);
}
});
}
}

View File

@ -7,10 +7,14 @@ import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -35,6 +39,8 @@ public class ModuleClassLoader extends URLClassLoader {
//需要注册的spring bean的name集合
private List<String> registeredBean = new ArrayList<>();
private List<String> registeredController = new ArrayList<>();
//构造
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
@ -150,8 +156,12 @@ public class ModuleClassLoader extends URLClassLoader {
beanName = StringUtils.uncapitalize(beanName);
SpringContextUtil.getBeanFactory().registerBeanDefinition(beanName,beanDefinition);
if (isHandler(cla)) {
registeredController.add(beanName);
}
registeredBean.add(beanName);
// System.out.println("注册bean:"+beanName);
}
}
@ -164,6 +174,10 @@ public class ModuleClassLoader extends URLClassLoader {
return registeredBean;
}
public List<String> getRegisteredController() {
return registeredController;
}
/**
* 方法描述 判断class对象是否带有spring的注解
@ -184,6 +198,9 @@ public class ModuleClassLoader extends URLClassLoader {
if( Modifier.isAbstract(cla.getModifiers())){
return false;
}
if (isHandler(cla)) {
return true;
}
if(cla.getAnnotation(Component.class)!=null){
return true;
@ -194,8 +211,15 @@ public class ModuleClassLoader extends URLClassLoader {
if(cla.getAnnotation(Service.class)!=null){
return true;
}
if(cla.getAnnotation(Service.class)!=null){
return true;
}
return false;
}
protected boolean isHandler(Class<?> beanType) {
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
}
}

View File

@ -2,6 +2,7 @@ package io.dataease.plugins.server;
import io.dataease.commons.utils.ServletUtils;
import io.dataease.plugins.common.dto.PluginSysMenu;
import io.dataease.plugins.common.service.PluginComponentService;
import io.dataease.plugins.common.service.PluginMenuService;
import io.dataease.plugins.config.SpringContextUtil;
import org.springframework.web.bind.annotation.GetMapping;
@ -9,7 +10,6 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference;
public class PluginCommonServer {
@GetMapping("/async/{menuId}")
public void componentInfo(@PathVariable Long menuId) {
public void menuInfo(@PathVariable Long menuId) {
Map<String, PluginMenuService> pluginMenuServiceMap = SpringContextUtil.getApplicationContext().getBeansOfType(PluginMenuService.class);
pluginMenuServiceMap.values().stream().forEach(service -> {
AtomicReference<PluginSysMenu> atomicReference = new AtomicReference<>();
@ -65,4 +65,41 @@ public class PluginCommonServer {
return;
});
}
@GetMapping("/component/{componentName}")
public void componentInfo(@PathVariable String componentName) {
Map<String, PluginComponentService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType(PluginComponentService.class);
beansOfType.values().stream().forEach(service -> {
List<String> components = service.components();
if (components.contains(componentName)) {
HttpServletResponse response = ServletUtils.response();
BufferedInputStream bis = null;
InputStream inputStream = null;
OutputStream os = null; //输出流
try{
inputStream = service.vueResource(componentName);
byte[] buffer = new byte[1024];
os = response.getOutputStream();
bis = new BufferedInputStream(inputStream);
int i = bis.read(buffer);
while(i != -1){
os.write(buffer, 0, i);
i = bis.read(buffer);
}
os.flush();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
bis.close();
inputStream.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return;
}
});
}
}

View File

@ -0,0 +1,85 @@
package io.dataease.plugins.server;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import io.dataease.auth.entity.SysUserEntity;
import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.service.AuthUserService;
import io.dataease.auth.util.JWTUtils;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.utils.CodingUtil;
import io.dataease.commons.utils.ServletUtils;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
import io.dataease.plugins.xpack.oidc.dto.SSOToken;
import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo;
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
import io.dataease.service.sys.SysUserService;
@RequestMapping("/sso")
@Controller
public class SSOServer {
@Autowired
private AuthUserService authUserService;
@Autowired
private SysUserService sysUserService;
@GetMapping("/callBack")
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
Map<String, OidcXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((OidcXpackService.class));
if(beansOfType.keySet().size() == 0) {
DEException.throwException("缺少oidc插件");
}
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
Boolean suuportOIDC = oidcXpackService.isSuuportOIDC();
if (!suuportOIDC) {
DEException.throwException("未开启oidc");
}
Map<String, String> config = config(oidcXpackService);
SSOToken ssoToken = oidcXpackService.requestSsoToken(config, code, state);
SSOUserInfo ssoUserInfo = oidcXpackService.requestUserInfo(config, ssoToken.getAccessToken());
SysUserEntity sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName());
if(null == sysUserEntity){
sysUserService.saveOIDCUser(ssoUserInfo);
sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName());
}
TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build();
String realPwd = CodingUtil.md5(sysUserService.defaultPWD());
String token = JWTUtils.sign(tokenInfo, realPwd);
ServletUtils.setToken(token);
HttpServletResponse response = ServletUtils.response();
Cookie cookie_token = new Cookie("Authorization", token);cookie_token.setPath("/");
Cookie cookie_id_token = new Cookie("IdToken", ssoToken.getIdToken());cookie_id_token.setPath("/");
Cookie cookie_ac_token = new Cookie("AccessToken", ssoToken.getAccessToken());cookie_ac_token.setPath("/");
response.addCookie(cookie_token);
response.addCookie(cookie_id_token);
response.addCookie(cookie_ac_token);
ModelAndView modelAndView = new ModelAndView("redirect:/");
return modelAndView;
}
private Map<String, String> config(OidcXpackService oidcXpackService) {
List<SysSettingDto> sysSettingDtos = oidcXpackService.oidcSettings();
Map<String, String> config = sysSettingDtos.stream().collect(Collectors.toMap(SysSettingDto::getParamKey, SysSettingDto::getParamValue));
return config;
}
}

View File

@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/api/ldap")
@RequestMapping("/plugin/ldap")
@RestController
public class XLdapServer {

View File

@ -0,0 +1,59 @@
package io.dataease.plugins.server;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RequestMapping("/plugin/oidc")
@RestController
public class XOidcServer {
@PostMapping("/info")
public List<SysSettingDto> getOidcInfo() {
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
return oidcXpackService.oidcSettings();
}
@PostMapping("/save")
public void save(@RequestBody List<SysSettingDto> settings) {
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
oidcXpackService.save(settings);
}
@PostMapping(value="/authInfo")
public Map<String, Object> authInfo() {
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
Map<String, Object> result = new HashMap<String, Object>();
List<SysSettingDto> oidcSettings = oidcXpackService.oidcSettings();
Map<String, String> authParam = new HashMap<>();
authParam.put("response_type", "code");
authParam.put("state", "state");
// authParam.put("redirect_uri", "http://localhost:9528");
oidcSettings.forEach(param -> {
if(StringUtils.isNotBlank(param.getParamKey())) {
if (StringUtils.equals(param.getParamKey(), "oidc.authEndpoint")) {
result.put("authEndpoint", param.getParamValue());
}
if (StringUtils.equals(param.getParamKey(), "oidc.scope")) {
authParam.put("scope", param.getParamValue());
}
if (StringUtils.equals(param.getParamKey(), "oidc.clientId")) {
authParam.put("client_id", param.getParamValue());
}
}
});
result.put("authParam", authParam);
return result;
}
}

View File

@ -208,7 +208,9 @@ public class ChartViewService {
customFilter.addAll(collect);
}
if (StringUtils.equalsIgnoreCase("text", view.getType()) || StringUtils.equalsIgnoreCase("gauge", view.getType())) {
if (StringUtils.equalsIgnoreCase("text", view.getType())
|| StringUtils.equalsIgnoreCase("gauge", view.getType())
|| StringUtils.equalsIgnoreCase("liquid", view.getType())) {
xAxis = new ArrayList<>();
if (CollectionUtils.isEmpty(yAxis)) {
ChartViewDTO dto = new ChartViewDTO();
@ -458,6 +460,9 @@ public class ChartViewService {
map.putAll(mapChart);
map.putAll(mapTableNormal);
List<DatasetTableField> sourceFields = dataSetTableFieldsService.getFieldsByTableId(view.getTableId());
map.put("sourceFields",sourceFields);
ChartViewDTO dto = new ChartViewDTO();
BeanUtils.copyBean(dto, view);
dto.setData(map);

View File

@ -22,6 +22,8 @@ import io.dataease.controller.sys.response.SysUserGridResponse;
import io.dataease.controller.sys.response.SysUserRole;
import io.dataease.i18n.Translator;
import io.dataease.plugins.common.entity.XpackLdapUserEntity;
import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@ -31,6 +33,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -82,6 +86,7 @@ public class SysUserService {
@Transactional
public int save(SysUserCreateRequest request) {
checkUsername(request);
checkEmail(request);
SysUser user = BeanUtils.copyBean(new SysUser(), request);
long now = System.currentTimeMillis();
user.setCreateTime(now);
@ -102,6 +107,33 @@ public class SysUserService {
return insert;
}
@Transactional
public void saveOIDCUser(SSOUserInfo ssoUserInfo) {
long now = System.currentTimeMillis();
SysUser sysUser = new SysUser();
sysUser.setUsername(ssoUserInfo.getUserName());
sysUser.setNickName(ssoUserInfo.getNickName());
sysUser.setEmail(ssoUserInfo.getEmail());
sysUser.setPassword(CodingUtil.md5(DEFAULT_PWD));
sysUser.setCreateTime(now);
sysUser.setUpdateTime(now);
sysUser.setEnabled(1L);
sysUser.setLanguage("zh_CN");
sysUser.setFrom(2);
sysUserMapper.insert(sysUser);
SysUser dbUser = findOne(sysUser);
if (null != dbUser && null != dbUser.getUserId()) {
// oidc默认角色是普通员工
List<Long> roleIds = new ArrayList<Long>();
roleIds.add(2L);
saveUserRoles( dbUser.getUserId(), roleIds);
}
}
public String defaultPWD() {
return DEFAULT_PWD;
}
@Transactional
public void saveLdapUsers(LdapAddRequest request) {
long now = System.currentTimeMillis();
@ -115,6 +147,7 @@ public class SysUserService {
sysUser.setCreateTime(now);
sysUser.setUpdateTime(now);
sysUser.setEnabled(request.getEnabled());
sysUser.setLanguage("zh_CN");
sysUser.setFrom(1);
return sysUser;
}).collect(Collectors.toList());
@ -145,6 +178,7 @@ public class SysUserService {
@Transactional
public int update(SysUserCreateRequest request) {
checkUsername(request);
checkEmail(request);
if (StringUtils.isEmpty(request.getPassword())) {
request.setPassword(null);
}
@ -287,4 +321,19 @@ public class SysUserService {
throw new RuntimeException(Translator.get("i18n_username_exists"));
}
}
private void checkEmail(SysUserCreateRequest request) {
SysUserExample sysUserExample = new SysUserExample();
SysUserExample.Criteria criteria = sysUserExample.createCriteria();
if (request.getUserId() != null) {
criteria.andUserIdNotEqualTo(request.getUserId());
}
criteria.andEmailEqualTo(request.getEmail());
List<SysUser> sysUsers = sysUserMapper.selectByExample(sysUserExample);
if (CollectionUtils.isNotEmpty(sysUsers)) {
throw new RuntimeException(Translator.get("i18n_email_exists"));
}
}
}

View File

@ -243,6 +243,7 @@ i18n_union_field_exists=The same field can't in two dataset
i18n_cron_time_error=Start time can't greater then end time
i18n_auth_source_be_canceled=This Auth Resource Already Be Canceled,Please Connect Admin
i18n_username_exists=ID is already exists
i18n_email_exists=Email is already exists
i18n_ds_name_exists=Datasource name used
i18n_sync_job_exists=There is already a synchronization task running, please try again later
i18n_datasource_check_fail=Invalid,please check config

View File

@ -233,7 +233,7 @@ i18n_chart_count=记录数*
i18n_excel_have_merge_region=Excel 存在合并单元格
i18n_cron_expression_error=Cron 表达式校验错误
i18n_same_folder_can_not_repeat=同一目录下该名称已被使用
i18n_select_diff_folder= 请选择不的目录
i18n_select_diff_folder= 请选择不的目录
i18n_default_panel=默认仪表板
i18n_panel_list=仪表板
i18n_processing_data=正在处理数据,稍后刷新
@ -242,6 +242,7 @@ i18n_union_field_exists=两个数据集之间关联不能出现多次相同字
i18n_cron_time_error=开始时间不能大于结束时间
i18n_auth_source_be_canceled=本用户当前资源所有授权权限已经被取消,如需再次开通,请联系管理员
i18n_username_exists=用户 ID 已存在
i18n_email_exists=邮箱已存在
i18n_ds_name_exists=数据源名称已被使用
i18n_sync_job_exists=已经有同步任务在运行,稍后重试
i18n_datasource_check_fail=校验失败,请检查配置信息

View File

@ -236,7 +236,7 @@ i18n_chart_count=記錄數*
i18n_excel_have_merge_region=Excel存在合並單元格
i18n_cron_expression_error=Cron表達式校驗錯誤
i18n_same_folder_can_not_repeat=同一目錄下該名稱已被使用
i18n_select_diff_folder= 请选择不的目录
i18n_select_diff_folder= 请选择不的目录
i18n_default_panel=默認儀表板
i18n_panel_list=儀表板
i18n_processing_data=正在處理數據,稍後刷新
@ -245,6 +245,7 @@ i18n_union_field_exists=兩個數據集之間關聯不能出現多次相同字
i18n_cron_time_error=開始時間不能大於結束時間
i18n_auth_source_be_canceled=本用户当前资源所有授权权限已经被取消,如需再次开通,请联系管理员
i18n_username_exists=用戶ID已存在
i18n_email_exists=郵箱已存在
i18n_ds_name_exists=數據源名稱已被使用
i18n_sync_job_exists=已經有同步任務在運行,稍後重試
i18n_datasource_check_fail=校驗失敗,請檢查配置信息

View File

@ -100,7 +100,7 @@ export function roleGrid(pageIndex, pageSize, data) {
export function ldapUsers(data) {
return request({
url: '/api/ldap/users',
url: '/plugin/ldap/users',
method: 'post',
loading: true
})

View File

@ -57,3 +57,10 @@ export function ldapStatus() {
method: 'post'
})
}
export function oidcStatus() {
return request({
url: '/api/auth/isOpenOidc',
method: 'post'
})
}

View File

@ -232,7 +232,7 @@ export default {
right: 178px;
top: 8px;
background: red;
// color: #fff;
color: #fff;
border-radius: 17px;
padding: 4px 7px;
font-size: 16px;

View File

@ -1,6 +1,5 @@
<template>
<div
v-if="showDrag"
id="editor"
class="editor"
:class="[

View File

@ -49,6 +49,14 @@
<el-input v-model="innerOpacity" type="number" size="mini" min="0" max="100" step="10" @change="styleChange" />
</div>
<el-tooltip :content="$t('panel.borderRadius')">
<i style="float: left;margin-top: 3px;margin-left: 2px;" class="icon iconfont icon-fangxing-" />
</el-tooltip>
<div style="width: 70px;float: left;margin-top: 2px;margin-left: 2px;">
<el-input v-model="styleInfo.borderRadius" type="number" size="mini" min="0" max="100" step="1" @change="styleChange" />
</div>
<div style="width: 20px;float: left;margin-top: 2px;margin-left: 10px;">
<div style="width: 16px;height: 18px">
<el-tooltip :content="$t('panel.color')">
@ -173,7 +181,7 @@ export default {
ps = x + 60
}
// toolbar
const xGap = ps + 495 - this.canvasWidth
const xGap = ps + 565 - this.canvasWidth
// console.log('canvasWidth:' + this.canvasWidth + ';xGap:' + xGap)
if (xGap > 0) {
return ps - xGap
@ -205,7 +213,7 @@ export default {
.el-card-main {
height: 34px;
z-index: 10;
width: 550px;
width: 620px;
position: absolute;
}

View File

@ -121,7 +121,7 @@ export default {
trackMenu() {
const trackMenuInfo = []
let linkageCount = 0
this.chart.data && this.chart.data.fields && this.chart.data.fields.forEach(item => {
this.chart.data && this.chart.data.sourceFields && this.chart.data.sourceFields.forEach(item => {
const sourceInfo = this.chart.id + '#' + item.id
if (this.nowPanelTrackInfo[sourceInfo]) {
linkageCount++

View File

@ -57,8 +57,11 @@ const list = [
fontWeight: 400,
lineHeight: '',
letterSpacing: 0,
textAlign: 'left',
color: '#000000'
textAlign: 'center',
color: '#000000',
verticalAlign: 'middle',
backgroundColor: '#ffffff',
borderRadius: 0
}
},
{

View File

@ -130,6 +130,8 @@ export default {
re_login: 'Login again'
},
commons: {
search: 'Search',
folder: 'Folder',
no_target_permission: 'No permission',
success: 'Success',
switch_lang: 'Switch Language Success',

View File

@ -130,6 +130,8 @@ export default {
re_login: '重新登陸'
},
commons: {
search: '搜索',
folder: '目录',
no_target_permission: '沒有權限',
success: '成功',
switch_lang: '切換語言成功',

View File

@ -130,6 +130,8 @@ export default {
re_login: '重新登录'
},
commons: {
search: '搜索',
folder: '目录',
no_target_permission: '没有权限',
success: '成功',
switch_lang: '切换语言成功',
@ -530,6 +532,15 @@ export default {
mapping_cannot_be_empty: 'LDAP 用户属性映射不能为空',
password_cannot_be_empty: 'LDAP 密码不能为空'
},
oidc: {
auth_endpoint: '请输入AuthEndpoint',
token_endpoint: '请输入TokenEndpoint',
userinfo_endpoint: '请输入UserinfoEndpoint',
logout_endpoint: '请输入logoutEndpoint',
clientId: '请输入ClientId',
secret: '请输入Secret',
open: '启用OIDC认证'
},
role: {
menu_authorization: '菜单授权',
data_authorization: '数据授权',

View File

@ -5,15 +5,7 @@ import { DEFAULT_SIZE } from '@/views/chart/chart/chart'
export function baseLiquid(plot, container, chart) {
let value = 0
const colors = []
let max
let radius
let outlineBorder
let outlineDistance
let waveLength
let waveCount
let bgColor
let shape
let labelContent
let max, radius, outlineBorder, outlineDistance, waveLength, waveCount, bgColor, shape, labelContent, title
if (chart.data) {
if (chart.data.series.length > 0) {
value = chart.data.series[0].data[0].value
@ -36,7 +28,7 @@ export function baseLiquid(plot, container, chart) {
max = size.liquidMax ? size.liquidMax : DEFAULT_SIZE.liquidMax
radius = parseFloat((size.liquidSize ? size.liquidSize : DEFAULT_SIZE.liquidSize) / 100)
outlineBorder = parseInt(size.liquidOutlineBorder ? size.liquidOutlineBorder : DEFAULT_SIZE.liquidOutlineBorder)
outlineDistance = parseInt(size.liquidOutlineDistance ? size.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance)
outlineDistance = parseInt((size.liquidOutlineDistance || size.liquidOutlineDistance === 0) ? size.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance)
waveLength = parseInt(size.liquidWaveLength ? size.liquidWaveLength : DEFAULT_SIZE.liquidWaveLength)
waveCount = parseInt(size.liquidWaveCount ? size.liquidWaveCount : DEFAULT_SIZE.liquidWaveCount)
shape = size.liquidShape ? size.liquidShape : DEFAULT_SIZE.liquidShape
@ -62,6 +54,22 @@ export function baseLiquid(plot, container, chart) {
if (customStyle.background) {
bgColor = customStyle.background.color.concat(digToHex(parseInt(customStyle.background.alpha)))
}
if (customStyle.text) {
const t = JSON.parse(JSON.stringify(customStyle.text))
if (t.show) {
title = {
formatter: () => { return chart.title },
style: ({ percent }) => ({
fontSize: parseInt(t.fontSize),
color: t.color,
fontWeight: t.isBolder ? 'bold' : 'normal',
fontStyle: t.isItalic ? 'italic' : 'normal'
})
}
} else {
title = false
}
}
}
// 开始渲染
if (plot) {
@ -87,6 +95,7 @@ export function baseLiquid(plot, container, chart) {
count: waveCount
},
statistic: {
title: title,
content: labelContent
}
})

View File

@ -24,14 +24,14 @@
<el-form-item :label="$t('chart.text_color')" class="form-item">
<el-color-picker v-model="titleForm.color" class="color-picker-style" @change="changeTitleStyle" />
</el-form-item>
<el-form-item :label="$t('chart.text_h_position')" class="form-item">
<el-form-item v-show="chart.type && chart.type !== 'liquid'" :label="$t('chart.text_h_position')" class="form-item">
<el-radio-group v-model="titleForm.hPosition" size="mini" @change="changeTitleStyle">
<el-radio-button label="left">{{ $t('chart.text_pos_left') }}</el-radio-button>
<el-radio-button label="center">{{ $t('chart.text_pos_center') }}</el-radio-button>
<el-radio-button label="right">{{ $t('chart.text_pos_right') }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-show="chart.type && !chart.type.includes('table')" :label="$t('chart.text_v_position')" class="form-item">
<el-form-item v-show="chart.type && !chart.type.includes('table') && chart.type !== 'liquid'" :label="$t('chart.text_v_position')" class="form-item">
<el-radio-group v-model="titleForm.vPosition" size="mini" @change="changeTitleStyle">
<el-radio-button label="top">{{ $t('chart.text_pos_top') }}</el-radio-button>
<el-radio-button label="center">{{ $t('chart.text_pos_center') }}</el-radio-button>

View File

@ -165,6 +165,7 @@
</el-form>
<el-form v-show="chart.type && chart.type === 'chart-mix'" ref="sizeFormBar" :disabled="param && !hasDataPermission('manage',param.privileges)" :model="sizeForm" label-width="80px" size="mini">
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_bar') }}</el-divider>
<el-form-item :label="$t('chart.adapt')" class="form-item">
<el-checkbox v-model="sizeForm.barDefault" @change="changeBarSizeCase">{{ $t('chart.adapt') }}</el-checkbox>
</el-form-item>
@ -174,7 +175,7 @@
<el-form-item :label="$t('chart.bar_gap')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.barGap" :disabled="sizeForm.barDefault" show-input :show-input-controls="false" input-size="mini" :min="0" :max="5" :step="0.1" @change="changeBarSizeCase" />
</el-form-item>
<el-divider />
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_line') }}</el-divider>
<el-form-item :label="$t('chart.line_width')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.lineWidth" show-input :show-input-controls="false" input-size="mini" :min="0" :max="10" @change="changeBarSizeCase" />
</el-form-item>
@ -203,7 +204,7 @@
<el-form-item :label="$t('chart.line_area')" class="form-item">
<el-checkbox v-model="sizeForm.lineArea" @change="changeBarSizeCase">{{ $t('chart.show') }}</el-checkbox>
</el-form-item>
<el-divider />
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_scatter') }}</el-divider>
<el-form-item :label="$t('chart.bubble_symbol')" class="form-item">
<el-select v-model="sizeForm.scatterSymbol" :placeholder="$t('chart.line_symbol')" @change="changeBarSizeCase">
<el-option
@ -234,19 +235,19 @@
<el-input-number v-model="sizeForm.liquidMax" :min="1" size="mini" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.radar_size')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidSize" show-input :show-input-controls="false" input-size="mini" :min="0" :max="100" @change="changeBarSizeCase" />
<el-slider v-model="sizeForm.liquidSize" show-input :show-input-controls="false" input-size="mini" :min="1" :max="100" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_outline_border')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidOutlineBorder" show-input :show-input-controls="false" input-size="mini" :min="1" :max="20" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_outline_distance')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidOutlineDistance" show-input :show-input-controls="false" input-size="mini" :min="1" :max="20" @change="changeBarSizeCase" />
<el-slider v-model="sizeForm.liquidOutlineDistance" show-input :show-input-controls="false" input-size="mini" :min="0" :max="20" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_wave_length')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidWaveLength" show-input :show-input-controls="false" input-size="mini" :min="1" :max="500" @change="changeBarSizeCase" />
<el-slider v-model="sizeForm.liquidWaveLength" show-input :show-input-controls="false" input-size="mini" :min="10" :max="500" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_wave_count')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidWaveCount" show-input :show-input-controls="false" input-size="mini" :min="1" :max="10" @change="changeBarSizeCase" />
<el-slider v-model="sizeForm.liquidWaveCount" show-input :show-input-controls="false" input-size="mini" :min="2" :max="10" @change="changeBarSizeCase" />
</el-form-item>
</el-form>
</el-col>
@ -322,7 +323,7 @@ export default {
this.sizeForm.liquidMax = this.sizeForm.liquidMax ? this.sizeForm.liquidMax : DEFAULT_SIZE.liquidMax
this.sizeForm.liquidSize = this.sizeForm.liquidSize ? this.sizeForm.liquidSize : DEFAULT_SIZE.liquidSize
this.sizeForm.liquidOutlineBorder = this.sizeForm.liquidOutlineBorder ? this.sizeForm.liquidOutlineBorder : DEFAULT_SIZE.liquidOutlineBorder
this.sizeForm.liquidOutlineDistance = this.sizeForm.liquidOutlineDistance ? this.sizeForm.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance
this.sizeForm.liquidOutlineDistance = (this.sizeForm.liquidOutlineDistance || this.sizeForm.liquidOutlineDistance === 0) ? this.sizeForm.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance
this.sizeForm.liquidWaveLength = this.sizeForm.liquidWaveLength ? this.sizeForm.liquidWaveLength : DEFAULT_SIZE.liquidWaveLength
this.sizeForm.liquidWaveCount = this.sizeForm.liquidWaveCount ? this.sizeForm.liquidWaveCount : DEFAULT_SIZE.liquidWaveCount
}
@ -372,4 +373,10 @@ export default {
.el-divider--horizontal {
margin: 10px 0
}
.divider-style>>>.el-divider__text{
color: #606266;
font-size: 12px;
font-weight: 400;
padding: 0 10px;
}
</style>

View File

@ -503,7 +503,7 @@
<el-collapse-item v-show="view.type && view.type.includes('radar')" name="split" :title="$t('chart.split')">
<split-selector :param="param" class="attr-selector" :chart="chart" @onChangeSplitForm="onChangeSplitForm" />
</el-collapse-item>
<el-collapse-item v-show="view.type && view.type !== 'liquid'" name="title" :title="$t('chart.title')">
<el-collapse-item v-show="view.type" name="title" :title="$t('chart.title')">
<title-selector :param="param" class="attr-selector" :chart="chart" @onTextChange="onTextChange" />
</el-collapse-item>
<el-collapse-item v-show="view.type && view.type !== 'map' && !view.type.includes('table') && !view.type.includes('text') && chart.type !== 'treemap' && view.type !== 'liquid'" name="legend" :title="$t('chart.legend')">

View File

@ -15,11 +15,11 @@
{{ $t('login.welcome') + (uiInfo && uiInfo['ui.title'] && uiInfo['ui.title'].paramValue || ' DataEase') }}
</div>
<div class="login-form">
<el-form-item v-if="openLdap">
<el-radio-group v-if="openLdap" v-model="loginForm.loginType">
<el-radio v-if="openLdap" :label="0" size="mini">普通登录</el-radio>
<el-radio v-if="openLdap" :label="1" size="mini">LDAP</el-radio>
<el-form-item v-if="loginTypes.length > 1">
<el-radio-group v-if="loginTypes.length > 1" v-model="loginForm.loginType" @change="changeLoginType">
<el-radio :label="0" size="mini">普通登录</el-radio>
<el-radio v-if="loginTypes.includes(1)" :label="1" size="mini">LDAP</el-radio>
<el-radio v-if="loginTypes.includes(2)" :label="2" size="mini">OIDC</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="username">
@ -56,41 +56,20 @@
</el-col>
</el-row>
</div>
<plugin-com v-if="loginTypes.includes(2) && loginForm.loginType === 2" ref="SSOComponent" component-name="SSOComponent" />
</div>
</template>
<script>
import { encrypt } from '@/utils/rsaEncrypt'
import { ldapStatus } from '@/api/user'
import { ldapStatus, oidcStatus } from '@/api/user'
import { getSysUI } from '@/utils/auth'
import PluginCom from '@/views/system/plugin/PluginCom'
export default {
name: 'Login',
components: { PluginCom },
data() {
// const validateUsername = (rule, value, callback) => {
// const userName = value.trim()
// validateUserName({ userName: userName }).then(res => {
// if (res.data) {
// callback()
// } else {
// callback(this.$t('login.username_error'))
// }
// }).catch(() => {
// callback(this.$t('login.username_error'))
// })
// // if (!validUsername(value)) {
// // callback(new Error('Please enter the correct user name'))
// // } else {
// // callback()
// // }
// }
// const validatePassword = (rule, value, callback) => {
// if (value.length < 8) {
// callback(this.$t('login.password_error'))
// } else {
// callback()
// }
// }
return {
loginForm: {
loginType: 0,
@ -108,7 +87,7 @@ export default {
loginImageUrl: null,
loginLogoUrl: null,
axiosFinished: false,
openLdap: true
loginTypes: [0]
}
},
computed: {
@ -126,7 +105,15 @@ export default {
},
beforeCreate() {
ldapStatus().then(res => {
this.openLdap = res.success && res.data
if (res.success && res.data) {
this.loginTypes.push(1)
}
})
oidcStatus().then(res => {
if (res.success && res.data) {
this.loginTypes.push(2)
}
})
},
created() {
@ -169,6 +156,12 @@ export default {
return false
}
})
},
changeLoginType(val) {
if (val !== 2) return
this.$nextTick(() => {
})
}
}
}

View File

@ -1,6 +1,41 @@
<template xmlns:el-col="http://www.w3.org/1999/html">
<el-col style="padding: 0 5px 0 5px;">
<el-col>
<el-row style="margin-bottom: 10px">
<el-col :span="16">
<el-input
v-model="filterText"
size="mini"
:placeholder="$t('commons.search')"
prefix-icon="el-icon-search"
clearable
/>
</el-col>
<el-col :span="8">
<el-dropdown>
<el-button size="mini" type="primary">
{{ searchMap[searchType] }}<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="searchTypeClick('all')">全部</el-dropdown-item>
<el-dropdown-item @click.native="searchTypeClick('folder')">目录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- <el-select-->
<!-- v-model="searchType"-->
<!-- default-first-option-->
<!-- size="mini"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in searchTypeList"-->
<!-- :key="item.value"-->
<!-- :label="item.label"-->
<!-- :value="item.value"-->
<!-- />-->
<!-- </el-select>-->
</el-col>
</el-row>
<el-row>
<span class="header-title">{{ $t('panel.default_panel') }}</span>
<div class="block">
@ -11,6 +46,7 @@
node-key="id"
:highlight-current="activeTree==='system'"
:expand-on-click-node="true"
:filter-node-method="filterNode"
@node-click="nodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node father">
@ -59,6 +95,7 @@
node-key="id"
:highlight-current="activeTree==='self'"
:expand-on-click-node="true"
:filter-node-method="filterNode"
@node-click="nodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node-list father">
@ -294,7 +331,14 @@ export default {
moveDialogTitle: '',
moveInfo: {},
tGroup: {},
tGroupData: [] //
tGroupData: [], //
searchPids: [], // pid
filterText: '',
searchType: 'all',
searchMap: {
all: this.$t('commons.all'),
folder: this.$t('commons.folder')
}
}
},
computed: {
@ -311,6 +355,16 @@ export default {
if (newVal === 'PanelMain' && this.lastActiveNode && this.lastActiveNodeData) {
this.activeNodeAndClickOnly(this.lastActiveNodeData)
}
},
filterText(val) {
this.searchPids = []
this.$refs.default_panel_tree.filter(val)
this.$refs.panel_list_tree.filter(val)
},
searchType(val) {
this.searchPids = []
this.$refs.default_panel_tree.filter(this.filterText)
this.$refs.panel_list_tree.filter(this.filterText)
}
},
mounted() {
@ -710,6 +764,27 @@ export default {
targetGroup(val) {
this.tGroup = val
this.groupMoveConfirmDisabled = false
},
filterNode(value, data) {
if (!value) return true
if (this.searchType === 'folder') {
if (data.nodeType === 'folder' && data.label.indexOf(value) !== -1) {
this.searchPids.push(data.id)
return true
}
if (this.searchPids.indexOf(data.pid) !== -1) {
if (data.nodeType === 'folder') {
this.searchPids.push(data.id)
}
return true
}
} else {
return data.label.indexOf(value) !== -1
}
return false
},
searchTypeClick(searchTypeInfo) {
this.searchType = searchTypeInfo
}
}
}

View File

@ -0,0 +1,69 @@
<template>
<div>
<async-component v-if="showAsync" :url="url" @execute-axios="executeAxios" @on-add-languanges="addLanguages" @plugin-call-back="pluginCallBack" />
<div v-else>
<h1>未知组件无法展示</h1>
</div>
</div>
</template>
<script>
import AsyncComponent from '@/components/AsyncComponent'
import i18n from '@/lang'
import bus from '@/utils/bus'
import { execute } from '@/api/system/dynamic'
export default {
name: 'PluginCom',
components: {
AsyncComponent
},
props: {
componentName: {
type: String,
default: null
}
},
data() {
return {
showAsync: false,
baseUrl: '/api/pluginCommon/component/',
url: null
}
},
created() {
if (this.componentName) {
this.showAsync = true
this.url = this.baseUrl + this.componentName
} else {
this.showAsync = false
}
},
methods: {
// hasLicense
executeAxios(options) {
execute(options).then(res => {
if (options.callBack) {
options.callBack(res)
}
}).catch(e => {
if (options.callBack) {
options.callBack(e)
}
})
},
addLanguages(options) {
for (const key in i18n.messages) {
if (Object.hasOwnProperty.call(i18n.messages, key)) {
const element = options[key]
i18n.mergeLocaleMessage(key, element)
}
}
},
pluginCallBack(param) {
const { eventName, eventParam } = param
bus.$emit(eventName, eventParam)
}
}
}
</script>

View File

@ -22,7 +22,7 @@
<!-- <el-table-column prop="gender" :label="$t('commons.gender')" width="60" /> -->
<el-table-column prop="from" :label="$t('user.source')" width="80">
<template slot-scope="scope">
<div>{{ scope.row.from === 0 ? 'LOCAL' : 'LDAP' }}</div>
<div>{{ scope.row.from === 0 ? 'LOCAL' : scope.row.from === 1 ? 'LDAP' : 'OIDC' }}</div>
</template>
</el-table-column>