Merge branch 'dev' into pr@dev_memory_component
This commit is contained in:
commit
33803a6767
@ -8,5 +8,5 @@ referer = "referer"
|
||||
keynode = "keynode"
|
||||
|
||||
[files]
|
||||
extend-exclude = ["public/", "amap-wx/", "m-icon/", "uni-card/", "uni-col/", "uni-link/", "uni-list/", "uni-list-item/", "uni-row/", "migration/", "mapFiles/"]
|
||||
extend-exclude = ["public/", "amap-wx/", "m-icon/", "uni-card/", "uni-col/", "uni-link/", "uni-list/", "uni-list-item/", "uni-row/", "migration/", "mapFiles/", "frontend/src/views/chart/components/table/TableNormal.vue"]
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package io.dataease.auth.api;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.dataease.auth.api.dto.SeizeLoginDto;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -21,6 +22,13 @@ public interface AuthApi {
|
||||
@PostMapping("/login")
|
||||
Object login(LoginDto loginDto) throws Exception;
|
||||
|
||||
@ApiOperation("移动端登录")
|
||||
@PostMapping("/mobileLogin")
|
||||
Object mobileLogin(LoginDto loginDto) throws Exception;
|
||||
|
||||
@PostMapping("/seizeLogin")
|
||||
Object seizeLogin(SeizeLoginDto loginDto) throws Exception;
|
||||
|
||||
@ApiOperation("获取用户信息")
|
||||
@PostMapping("/userInfo")
|
||||
CurrentUserDto userInfo();
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
package io.dataease.auth.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class SeizeLoginDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3318473577764636483L;
|
||||
|
||||
private String token;
|
||||
}
|
||||
@ -4,6 +4,7 @@ import io.dataease.auth.api.AuthApi;
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.dataease.auth.api.dto.SeizeLoginDto;
|
||||
import io.dataease.auth.config.RsaProperties;
|
||||
import io.dataease.auth.entity.AccountLockStatus;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
@ -28,6 +29,8 @@ import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
|
||||
import io.dataease.service.sys.SysUserService;
|
||||
|
||||
import io.dataease.service.system.SystemParameterService;
|
||||
import io.dataease.websocket.entity.WsMessage;
|
||||
import io.dataease.websocket.service.WsService;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
@ -61,6 +64,49 @@ public class AuthServer implements AuthApi {
|
||||
@Resource
|
||||
private SystemParameterService systemParameterService;
|
||||
|
||||
@Autowired
|
||||
private WsService wsService;
|
||||
|
||||
@Override
|
||||
public Object mobileLogin(@RequestBody LoginDto loginDto) throws Exception {
|
||||
String username = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, loginDto.getUsername());
|
||||
String pwd = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, loginDto.getPassword());
|
||||
AccountLockStatus accountLockStatus = authUserService.lockStatus(username, 0);
|
||||
if (accountLockStatus.getLocked()) {
|
||||
String msg = Translator.get("I18N_ACCOUNT_LOCKED");
|
||||
msg = String.format(msg, username, accountLockStatus.getRelieveTimes().toString());
|
||||
DataEaseException.throwException(msg);
|
||||
}
|
||||
|
||||
SysUserEntity user = authUserService.getUserByName(username);
|
||||
|
||||
if (ObjectUtils.isEmpty(user)) {
|
||||
AccountLockStatus lockStatus = authUserService.recordLoginFail(username, 0);
|
||||
DataEaseException.throwException(appendLoginErrorMsg(Translator.get("i18n_id_or_pwd_error"), lockStatus));
|
||||
}
|
||||
if (user.getEnabled() == 0) {
|
||||
AccountLockStatus lockStatus = authUserService.recordLoginFail(username, 0);
|
||||
DataEaseException.throwException(appendLoginErrorMsg(Translator.get("i18n_user_is_disable"), lockStatus));
|
||||
}
|
||||
String realPwd = user.getPassword();
|
||||
pwd = CodingUtil.md5(pwd);
|
||||
|
||||
if (!StringUtils.equals(pwd, realPwd)) {
|
||||
AccountLockStatus lockStatus = authUserService.recordLoginFail(username, 0);
|
||||
DataEaseException.throwException(appendLoginErrorMsg(Translator.get("i18n_id_or_pwd_error"), lockStatus));
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(username).build();
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd, false);
|
||||
// 记录token操作时间
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("token", token);
|
||||
ServletUtils.setToken(token);
|
||||
DeLogUtils.save(SysLogConstants.OPERATE_TYPE.LOGIN, SysLogConstants.SOURCE_TYPE.USER, user.getUserId(), null, null, null);
|
||||
authUserService.unlockAccount(username, 0);
|
||||
authUserService.clearCache(user.getUserId());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object login(@RequestBody LoginDto loginDto) throws Exception {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
@ -164,6 +210,23 @@ public class AuthServer implements AuthApi {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object seizeLogin(@RequestBody SeizeLoginDto loginDto) throws Exception {
|
||||
String token = loginDto.getToken();
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("token", token);
|
||||
ServletUtils.setToken(token);
|
||||
TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token);
|
||||
Long userId = tokenInfo.getUserId();
|
||||
JWTUtils.seizeSign(userId, token);
|
||||
DeLogUtils.save(SysLogConstants.OPERATE_TYPE.LOGIN, SysLogConstants.SOURCE_TYPE.USER, userId, null, null, null);
|
||||
WsMessage message = new WsMessage(userId, "/web-seize-topic", IPUtils.get());
|
||||
wsService.releaseMessage(message);
|
||||
authUserService.clearCache(userId);
|
||||
Thread.sleep(3000L);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String appendLoginErrorMsg(String msg, AccountLockStatus lockStatus) {
|
||||
if (ObjectUtils.isEmpty(lockStatus)) return msg;
|
||||
if (ObjectUtils.isNotEmpty(lockStatus.getRemainderTimes())) {
|
||||
|
||||
@ -81,7 +81,9 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
|
||||
|
||||
filterChainDefinitionMap.put("/api/auth/login", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/seizeLogin", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/logout", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/mobileLogin", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/isPluginLoaded", ANON);
|
||||
filterChainDefinitionMap.put("/system/requestTimeOut", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/validateName", ANON);
|
||||
|
||||
@ -6,15 +6,21 @@ import com.auth0.jwt.JWTCreator.Builder;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.auth0.jwt.interfaces.Verification;
|
||||
import com.google.gson.Gson;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.commons.model.OnlineUserModel;
|
||||
import io.dataease.commons.utils.*;
|
||||
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;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JWTUtils {
|
||||
|
||||
@ -68,23 +74,93 @@ public class JWTUtils {
|
||||
* @return 加密的token
|
||||
*/
|
||||
public static String sign(TokenInfo tokenInfo, String secret) {
|
||||
return sign(tokenInfo, secret, true);
|
||||
}
|
||||
|
||||
private static boolean tokenValid(OnlineUserModel model) {
|
||||
String token = model.getToken();
|
||||
// 如果已经加入黑名单 则直接返回无效
|
||||
boolean invalid = TokenCacheUtils.invalid(token);
|
||||
if (invalid) return false;
|
||||
|
||||
Long loginTime = model.getLoginTime();
|
||||
if (ObjectUtils.isEmpty(expireTime)) {
|
||||
expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L);
|
||||
}
|
||||
long expireTimeMillis = expireTime * 60000L;
|
||||
// 如果当前时间减去登录时间小于超时时间则说明token未过期 返回有效状态
|
||||
return System.currentTimeMillis() - loginTime < expireTimeMillis;
|
||||
|
||||
}
|
||||
|
||||
private static String models2Json(OnlineUserModel model, boolean withCurToken, String token) {
|
||||
Set<OnlineUserModel> models = new LinkedHashSet<>();
|
||||
models.add(model);
|
||||
Gson gson = new Gson();
|
||||
List<OnlineUserModel> userModels = models.stream().map(item -> {
|
||||
item.setToken(null);
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
if (withCurToken) {
|
||||
userModels.get(0).setToken(token);
|
||||
}
|
||||
String json = gson.toJson(userModels);
|
||||
try {
|
||||
if (ObjectUtils.isEmpty(expireTime)) {
|
||||
expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L);
|
||||
}
|
||||
long expireTimeMillis = expireTime * 60000L;
|
||||
Date date = new Date(System.currentTimeMillis() + expireTimeMillis);
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
Builder builder = JWT.create()
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId());
|
||||
String sign = builder.withExpiresAt(date).sign(algorithm);
|
||||
return sign;
|
||||
return URLEncoder.encode(json, "utf-8");
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String seizeSign(Long userId, String token) {
|
||||
Optional.ofNullable(TokenCacheUtils.onlineUserToken(userId)).ifPresent(model -> TokenCacheUtils.add(model.getToken(), userId));
|
||||
TokenCacheUtils.add2OnlinePools(token, userId);
|
||||
return IPUtils.get();
|
||||
}
|
||||
|
||||
public static String sign(TokenInfo tokenInfo, String secret, boolean writeOnline) {
|
||||
|
||||
Long userId = tokenInfo.getUserId();
|
||||
String multiLoginType = null;
|
||||
if (writeOnline && StringUtils.equals("1", (multiLoginType = TokenCacheUtils.multiLoginType()))) {
|
||||
OnlineUserModel userModel = TokenCacheUtils.onlineUserToken(userId);
|
||||
if (ObjectUtils.isNotEmpty(userModel) && tokenValid(userModel)) {
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
Cookie cookie_token = new Cookie("MultiLoginError1", models2Json(userModel, false, null));
|
||||
cookie_token.setPath("/");
|
||||
cookie_token.setPath("/");
|
||||
response.addCookie(cookie_token);
|
||||
DataEaseException.throwException("MultiLoginError1");
|
||||
}
|
||||
}
|
||||
if (ObjectUtils.isEmpty(expireTime)) {
|
||||
expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L);
|
||||
}
|
||||
long expireTimeMillis = expireTime * 60000L;
|
||||
Date date = new Date(System.currentTimeMillis() + expireTimeMillis);
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
Builder builder = JWT.create()
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", userId);
|
||||
String sign = builder.withExpiresAt(date).sign(algorithm);
|
||||
|
||||
if (StringUtils.equals("2", multiLoginType)) {
|
||||
OnlineUserModel userModel = TokenCacheUtils.onlineUserToken(userId);
|
||||
if (ObjectUtils.isNotEmpty(userModel) && tokenValid(userModel)) {
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
Cookie cookie_token = new Cookie("MultiLoginError2", models2Json(userModel, true, sign));
|
||||
cookie_token.setPath("/");
|
||||
response.addCookie(cookie_token);
|
||||
DataEaseException.throwException("MultiLoginError");
|
||||
}
|
||||
}
|
||||
if (writeOnline && !StringUtils.equals("0", multiLoginType)) {
|
||||
TokenCacheUtils.add2OnlinePools(sign, userId);
|
||||
}
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
||||
public static String signLink(String resourceId, Long userId, String secret) {
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
if (userId == null) {
|
||||
|
||||
@ -127,6 +127,8 @@ public interface ParamConstants {
|
||||
LOGIN_LIMIT_OPEN("loginlimit.open"),
|
||||
|
||||
SCAN_CREATE_USER("loginlimit.scanCreateUser"),
|
||||
|
||||
MULTI_LOGIN("loginlimit.multiLogin"),
|
||||
TEMPLATE_ACCESS_KEY("basic.templateAccessKey");
|
||||
|
||||
private String value;
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package io.dataease.commons.model;
|
||||
|
||||
import lombok.Data;
|
||||
import net.minidev.json.annotate.JsonIgnore;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class OnlineUserModel implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 190044376129186283L;
|
||||
|
||||
@JsonIgnore
|
||||
private String token;
|
||||
|
||||
private String ip;
|
||||
|
||||
private Long loginTime;
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package io.dataease.commons.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.dataease.commons.model.OnlineUserModel;
|
||||
import io.dataease.listener.util.CacheUtils;
|
||||
import io.dataease.service.system.SystemParameterService;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -17,10 +20,14 @@ public class TokenCacheUtils {
|
||||
|
||||
private static final String KEY = "sys_token_store";
|
||||
|
||||
private static final String ONLINE_TOKEN_POOL_KEY = "online_token_store";
|
||||
|
||||
private static String cacheType;
|
||||
|
||||
private static Long expTime;
|
||||
|
||||
private static Gson gson = new Gson();
|
||||
|
||||
@Value("${spring.cache.type:ehcache}")
|
||||
public void setCacheType(String cacheType) {
|
||||
TokenCacheUtils.cacheType = cacheType;
|
||||
@ -55,17 +62,6 @@ public class TokenCacheUtils {
|
||||
CacheUtils.flush(KEY);
|
||||
}
|
||||
|
||||
public static void remove(String token) {
|
||||
if (useRedis()) {
|
||||
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
|
||||
String key = KEY + token;
|
||||
if (redisTemplate.hasKey(key)) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
CacheUtils.remove(KEY, token);
|
||||
}
|
||||
|
||||
public static boolean invalid(String token) {
|
||||
if (useRedis()) {
|
||||
@ -76,4 +72,46 @@ public class TokenCacheUtils {
|
||||
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString());
|
||||
}
|
||||
|
||||
public static void add2OnlinePools(String token, Long userId) {
|
||||
OnlineUserModel model = buildModel(token);
|
||||
if (useRedis()) {
|
||||
ValueOperations valueOperations = cacheHandler();
|
||||
valueOperations.set(ONLINE_TOKEN_POOL_KEY + userId, model, expTime, TimeUnit.MINUTES);
|
||||
return;
|
||||
}
|
||||
|
||||
Long time = expTime * 60;
|
||||
Double v = time * 0.6;
|
||||
CacheUtils.put(ONLINE_TOKEN_POOL_KEY, userId, model, time.intValue(), v.intValue());
|
||||
CacheUtils.flush(ONLINE_TOKEN_POOL_KEY);
|
||||
}
|
||||
|
||||
public static String multiLoginType() {
|
||||
SystemParameterService service = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
return service.multiLoginType();
|
||||
}
|
||||
|
||||
public static OnlineUserModel onlineUserToken(Long userId) {
|
||||
if (useRedis()) {
|
||||
ValueOperations valueOperations = cacheHandler();
|
||||
Object obj = valueOperations.get(ONLINE_TOKEN_POOL_KEY + userId);
|
||||
if (ObjectUtils.isNotEmpty(obj)) return (OnlineUserModel) obj;
|
||||
return null;
|
||||
}
|
||||
Object o = CacheUtils.get(ONLINE_TOKEN_POOL_KEY, userId);
|
||||
if (ObjectUtils.isNotEmpty(o)) {
|
||||
OnlineUserModel userModel = gson.fromJson(gson.toJson(o), OnlineUserModel.class);
|
||||
return userModel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static OnlineUserModel buildModel(String token) {
|
||||
OnlineUserModel model = new OnlineUserModel();
|
||||
model.setToken(token);
|
||||
model.setIp(IPUtils.get());
|
||||
model.setLoginTime(System.currentTimeMillis());
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,13 +6,10 @@ import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.service.impl.AuthUserServiceImpl;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.*;
|
||||
import io.dataease.dto.PermissionProxy;
|
||||
import io.dataease.dto.chart.ViewOption;
|
||||
import io.dataease.ext.ExtTaskMapper;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.commons.utils.CronUtils;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import io.dataease.job.sechedule.ScheduleManager;
|
||||
import io.dataease.job.sechedule.strategy.TaskHandler;
|
||||
import io.dataease.plugins.common.base.domain.SysUserAssist;
|
||||
@ -164,6 +161,7 @@ public class EmailTaskHandler extends TaskHandler implements Job {
|
||||
AuthUserServiceImpl userService = SpringContextUtil.getBean(AuthUserServiceImpl.class);
|
||||
SysUserService sysUserService = SpringContextUtil.getBean(SysUserService.class);
|
||||
List<File> files = null;
|
||||
String token = null;
|
||||
try {
|
||||
XpackEmailTemplateDTO emailTemplateDTO = emailXpackService.emailTemplate(taskInstance.getTaskId());
|
||||
XpackEmailTaskRequest taskForm = emailXpackService.taskForm(taskInstance.getTaskId());
|
||||
@ -173,7 +171,7 @@ public class EmailTaskHandler extends TaskHandler implements Job {
|
||||
}
|
||||
String panelId = emailTemplateDTO.getPanelId();
|
||||
String url = panelUrl(panelId);
|
||||
String token = tokenByUser(user);
|
||||
token = tokenByUser(user);
|
||||
XpackPixelEntity xpackPixelEntity = buildPixel(emailTemplateDTO);
|
||||
LogUtil.info("url is " + url);
|
||||
LogUtil.info("token is " + token);
|
||||
@ -349,6 +347,9 @@ public class EmailTaskHandler extends TaskHandler implements Job {
|
||||
error(taskInstance, e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (StringUtils.isNotBlank(token)) {
|
||||
TokenCacheUtils.add(token, user.getUserId());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(files)) {
|
||||
files.forEach(file -> {
|
||||
if (file.exists()) {
|
||||
@ -381,7 +382,7 @@ public class EmailTaskHandler extends TaskHandler implements Job {
|
||||
|
||||
private String tokenByUser(SysUserEntity user) {
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(user.getUsername()).build();
|
||||
String token = JWTUtils.sign(tokenInfo, user.getPassword());
|
||||
String token = JWTUtils.sign(tokenInfo, user.getPassword(), false);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ public class XDingtalkServer {
|
||||
return dingtalkXpackService.getQrParam();
|
||||
}
|
||||
|
||||
private ModelAndView privateCallBack(String code, Boolean withoutLogin) {
|
||||
private ModelAndView privateCallBack(String code, Boolean withoutLogin, Boolean isMobile) {
|
||||
ModelAndView modelAndView = new ModelAndView("redirect:/");
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
DingtalkXpackService dingtalkXpackService = null;
|
||||
@ -109,7 +109,7 @@ public class XDingtalkServer {
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build();
|
||||
String realPwd = sysUserEntity.getPassword();
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd);
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd, !isMobile);
|
||||
ServletUtils.setToken(token);
|
||||
|
||||
DeLogUtils.save(SysLogConstants.OPERATE_TYPE.LOGIN, SysLogConstants.SOURCE_TYPE.USER, sysUserEntity.getUserId(), null, null, null);
|
||||
@ -144,13 +144,14 @@ public class XDingtalkServer {
|
||||
}
|
||||
|
||||
@GetMapping("/callBackWithoutLogin")
|
||||
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code) {
|
||||
return privateCallBack(code, true);
|
||||
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code, @RequestParam("mobile") String mobile) {
|
||||
boolean isMobile = StringUtils.equals("1", mobile);
|
||||
return privateCallBack(code, true, isMobile);
|
||||
}
|
||||
|
||||
@GetMapping("/callBack")
|
||||
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
|
||||
return privateCallBack(code, false);
|
||||
return privateCallBack(code, false, false);
|
||||
}
|
||||
|
||||
private void bindError(HttpServletResponse response, String url, String errorMsg) {
|
||||
|
||||
@ -92,11 +92,12 @@ public class XLarkServer {
|
||||
}
|
||||
|
||||
@GetMapping("/callBackWithoutLogin")
|
||||
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code) {
|
||||
return privateCallBack(code, null, true);
|
||||
public ModelAndView callBackWithoutLogin(@RequestParam("code") String code, @RequestParam("mobile") String mobile) {
|
||||
boolean isMobile = StringUtils.equals("1", mobile);
|
||||
return privateCallBack(code, null, true, isMobile);
|
||||
}
|
||||
|
||||
private ModelAndView privateCallBack(String code, String state, Boolean withoutLogin) {
|
||||
private ModelAndView privateCallBack(String code, String state, Boolean withoutLogin, Boolean isMobile) {
|
||||
ModelAndView modelAndView = new ModelAndView("redirect:/");
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
LarkXpackService larkXpackService = null;
|
||||
@ -132,7 +133,7 @@ public class XLarkServer {
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build();
|
||||
String realPwd = sysUserEntity.getPassword();
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd);
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd, !isMobile);
|
||||
ServletUtils.setToken(token);
|
||||
|
||||
DeLogUtils.save(SysLogConstants.OPERATE_TYPE.LOGIN, SysLogConstants.SOURCE_TYPE.USER, sysUserEntity.getUserId(), null, null, null);
|
||||
@ -168,7 +169,7 @@ public class XLarkServer {
|
||||
|
||||
@GetMapping("/callBack")
|
||||
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
|
||||
return privateCallBack(code, state, false);
|
||||
return privateCallBack(code, state, false, false);
|
||||
}
|
||||
|
||||
private void bindError(HttpServletResponse response, String url, String errorMsg) {
|
||||
|
||||
@ -777,6 +777,7 @@ public class JdbcProvider extends DefaultJdbcProvider {
|
||||
case StarRocks:
|
||||
MysqlConfiguration mysqlConfiguration = new Gson().fromJson(datasource.getConfiguration(), MysqlConfiguration.class);
|
||||
mysqlConfiguration.getJdbc();
|
||||
break;
|
||||
case redshift:
|
||||
RedshiftConfiguration redshiftConfiguration = new Gson().fromJson(datasource.getConfiguration(), RedshiftConfiguration.class);
|
||||
if(redshiftConfiguration.getDataBase().length() > 64 || redshiftConfiguration.getDataBase().length() < 1){
|
||||
@ -785,6 +786,7 @@ public class JdbcProvider extends DefaultJdbcProvider {
|
||||
if(!redshiftConfiguration.getDataBase().matches("\"^[a-z][a-z0-9_+.@-]*$\"")){
|
||||
throw new Exception("Invalid database name");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -269,7 +269,8 @@ public class MysqlQueryProvider extends QueryProvider {
|
||||
ChartViewFieldDTO x = xAxis.get(i);
|
||||
String originField;
|
||||
if (ObjectUtils.isNotEmpty(x.getExtField()) && x.getExtField() == 2) {
|
||||
// 解析origin name中有关联的字段生成sql表达式
|
||||
// 计算字段和视图字段,规则为 函数([原始字段id]),这边把[原始字段id] 换成 表名.原始字段id
|
||||
// 解析origin name中有关联的字段生成sql表达式
|
||||
originField = calcFieldRegex(x.getOriginName(), tableObj);
|
||||
} else if (ObjectUtils.isNotEmpty(x.getExtField()) && x.getExtField() == 1) {
|
||||
originField = String.format(MysqlConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getDataeaseName());
|
||||
@ -1058,12 +1059,13 @@ public class MysqlQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5 || field.getDeExtractType() == 1) {
|
||||
whereName = String.format(MysqlConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : MysqlConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(MysqlConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(MysqlConstants.CAST, originName, MysqlConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
whereName = String.format(MysqlConstants.FROM_UNIXTIME, cast, MysqlConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(MysqlConstants.FROM_UNIXTIME, cast, format);
|
||||
}
|
||||
} else if (field.getDeType() == 0 && field.getDeExtractType() == 0) {
|
||||
whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.CHAR);
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package io.dataease.provider.query;
|
||||
|
||||
/**
|
||||
* @Author Junjun
|
||||
*/
|
||||
public class SQLUtils {
|
||||
public static String transKeyword(String value) {
|
||||
return value.replaceAll("'", "\\\\'");
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,7 @@ import org.stringtemplate.v4.STGroup;
|
||||
import org.stringtemplate.v4.STGroupFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@ -1141,15 +1142,16 @@ public class CKQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == DeTypeConstants.DE_TIME) {
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(CKConstants.toDateTime, originName);
|
||||
whereName = String.format(CKConstants.formatDateTime, String.format(CKConstants.toDateTime, originName), format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_FLOAT || field.getDeExtractType() == DeTypeConstants.DE_FLOAT || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(CKConstants.toFloat64, originName);
|
||||
whereName = String.format(CKConstants.toDateTime, cast);
|
||||
whereName = String.format(CKConstants.formatDateTime, String.format(CKConstants.toDateTime, cast), format);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = String.format(CKConstants.formatDateTime, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
@ -1168,7 +1170,7 @@ public class CKQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
String whereName = "";
|
||||
if (request.getIsTree()) {
|
||||
if (request.getIsTree() && whereNameList.size() > 1) {
|
||||
whereName = "CONCAT(" + StringUtils.join(whereNameList, ",',',") + ")";
|
||||
} else {
|
||||
whereName = whereNameList.get(0);
|
||||
|
||||
@ -1115,23 +1115,24 @@ public class Db2QueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == DeTypeConstants.DE_TIME) {
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) {
|
||||
if (StringUtils.isNotEmpty(field.getDateFormat())) {
|
||||
originName = String.format(Db2Constants.TO_DATE, originName, field.getDateFormat());
|
||||
} else {
|
||||
originName = String.format(Db2Constants.STR_TO_DATE, originName);
|
||||
}
|
||||
whereName = String.format(Db2Constants.DATE_FORMAT, originName, Db2Constants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(Db2Constants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(Db2Constants.CAST, originName, Db2Constants.DEFAULT_INT_FORMAT);
|
||||
whereName = String.format(Db2Constants.FROM_UNIXTIME, cast, Db2Constants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(Db2Constants.FROM_UNIXTIME, cast, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_TIME) {
|
||||
if (field.getType().equalsIgnoreCase("TIME")) {
|
||||
whereName = String.format(Db2Constants.FORMAT_TIME, originName, Db2Constants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(Db2Constants.FORMAT_TIME, originName, format);
|
||||
} else if (field.getType().equalsIgnoreCase("DATE")) {
|
||||
whereName = String.format(Db2Constants.FORMAT_DATE, originName, Db2Constants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(Db2Constants.FORMAT_DATE, originName, format);
|
||||
} else {
|
||||
whereName = originName;
|
||||
}
|
||||
|
||||
@ -1080,15 +1080,16 @@ public class EsQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(EsSqlLConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : EsSqlLConstants.DEFAULT_DATE_FORMAT, EsSqlLConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(EsSqlLConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : EsSqlLConstants.DEFAULT_DATE_FORMAT, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(EsSqlLConstants.CAST, originName, "timestamp");
|
||||
whereName = String.format(EsSqlLConstants.DATETIME_FORMAT, cast, EsSqlLConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(EsSqlLConstants.DATETIME_FORMAT, cast, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = String.format(EsSqlLConstants.DATETIME_FORMAT, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1035,17 +1035,17 @@ public class HiveQueryProvider extends QueryProvider {
|
||||
} else {
|
||||
originName = String.format(HiveConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
|
||||
}
|
||||
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeType() == DeTypeConstants.DE_TIME) {
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(HiveConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : HiveConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(HiveConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(HiveConstants.CAST, originName, HiveConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
whereName = String.format(HiveConstants.FROM_UNIXTIME, cast, HiveConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(HiveConstants.FROM_UNIXTIME, cast, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_TIME) {
|
||||
whereName = originName;
|
||||
whereName = String.format(HiveConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1032,16 +1032,17 @@ public class ImpalaQueryProvider extends QueryProvider {
|
||||
originName = String.format(ImpalaConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
|
||||
}
|
||||
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeType() == DeTypeConstants.DE_TIME) {
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(ImpalaConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : ImpalaConstants.DEFAULT_DATE_FORMAT ,ImpalaConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(ImpalaConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : ImpalaConstants.DEFAULT_DATE_FORMAT, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(ImpalaConstants.CAST, originName, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
whereName = String.format(ImpalaConstants.FROM_UNIXTIME, cast, ImpalaConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(ImpalaConstants.FROM_UNIXTIME, cast, format);
|
||||
}
|
||||
if (field.getDeExtractType() == DeTypeConstants.DE_TIME) {
|
||||
whereName = originName;
|
||||
whereName = String.format(ImpalaConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
@ -1069,7 +1070,12 @@ public class ImpalaQueryProvider extends QueryProvider {
|
||||
String whereValue = "";
|
||||
|
||||
if (StringUtils.containsIgnoreCase(request.getOperator(), "in")) {
|
||||
whereValue = "('" + StringUtils.join(value, "','") + "')";
|
||||
DatasetTableField field = fieldList.get(0);
|
||||
if (!request.getIsTree() && (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == DeTypeConstants.DE_FLOAT || field.getDeExtractType() == DeTypeConstants.DE_BOOL)) {
|
||||
whereValue = "(" + StringUtils.join(value, ",") + ")";
|
||||
} else {
|
||||
whereValue = "('" + StringUtils.join(value, "','") + "')";
|
||||
}
|
||||
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) {
|
||||
whereValue = "'%" + value.get(0) + "%'";
|
||||
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) {
|
||||
@ -1154,6 +1160,7 @@ public class ImpalaQueryProvider extends QueryProvider {
|
||||
String format = transDateFormat(x.getDateStyle(), x.getDatePattern());
|
||||
if (x.getDeExtractType() == DeTypeConstants.DE_STRING) {
|
||||
fieldName = String.format(ImpalaConstants.STR_TO_DATE, originField, StringUtils.isNotEmpty(x.getDateFormat()) ? x.getDateFormat() : ImpalaConstants.DEFAULT_DATE_FORMAT ,ImpalaConstants.DEFAULT_DATE_FORMAT);
|
||||
fieldName = String.format(ImpalaConstants.DATE_FORMAT, fieldName, format);
|
||||
} else {
|
||||
String cast = String.format(ImpalaConstants.CAST, originField, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
String from_unixtime = String.format(ImpalaConstants.FROM_UNIXTIME, cast, ImpalaConstants.DEFAULT_DATE_FORMAT);
|
||||
|
||||
@ -1062,15 +1062,25 @@ public class MysqlQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(MySQLConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : MysqlConstants.DEFAULT_DATE_FORMAT);
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5 || field.getDeExtractType() == 1) {
|
||||
if (StringUtils.equalsIgnoreCase(request.getDateStyle(),"y_Q")){
|
||||
whereName = String.format(format,
|
||||
String.format(MysqlConstants.DATE_FORMAT, originName, "%Y"),
|
||||
String.format(MysqlConstants.QUARTER, String.format(MysqlConstants.DATE_FORMAT, originName, MysqlConstants.DEFAULT_DATE_FORMAT)));
|
||||
} else {
|
||||
whereName = String.format(MySQLConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(MySQLConstants.CAST, originName, MySQLConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
whereName = String.format(MySQLConstants.FROM_UNIXTIME, cast, MySQLConstants.DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
if (StringUtils.equalsIgnoreCase(request.getDateStyle(),"y_Q")){
|
||||
whereName = String.format(format,
|
||||
String.format(MysqlConstants.DATE_FORMAT, cast, "%Y"),
|
||||
String.format(MysqlConstants.QUARTER, String.format(MysqlConstants.DATE_FORMAT, field, MysqlConstants.DEFAULT_DATE_FORMAT)));
|
||||
} else {
|
||||
whereName = String.format(MySQLConstants.DATE_FORMAT, cast, format);
|
||||
}
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1205,17 +1205,17 @@ public class OracleQueryProvider extends QueryProvider {
|
||||
} else {
|
||||
originName = String.format(OracleConstants.KEYWORD_FIX, tableObj.getTableAlias(), field.getOriginName());
|
||||
}
|
||||
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeType() == 1) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(OracleConstants.TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : OracleConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(OracleConstants.TO_DATE, originName, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(OracleConstants.CAST, originName, OracleConstants.DEFAULT_INT_FORMAT) + "/1000";
|
||||
whereName = String.format(OracleConstants.FROM_UNIXTIME, cast, OracleConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(OracleConstants.FROM_UNIXTIME, cast, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = String.format(OracleConstants.TO_CHAR, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1072,15 +1072,18 @@ public class PgQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(PgConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : PgConstants.DEFAULT_DATE_FORMAT);
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5 || field.getDeExtractType() == 1) {
|
||||
String timestamp = String.format(PgConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : PgConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, timestamp, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(PgConstants.CAST, originName, "bigint");
|
||||
whereName = String.format(PgConstants.FROM_UNIXTIME, cast);
|
||||
String timestamp = String.format(PgConstants.FROM_UNIXTIME, cast);
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, timestamp, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1067,15 +1067,18 @@ public class RedshiftQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
String format = transDateFormat(request.getDateStyle(), request.getDatePattern());
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(PgConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : PgConstants.DEFAULT_DATE_FORMAT);
|
||||
String timestamp = String.format(PgConstants.STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : PgConstants.DEFAULT_DATE_FORMAT);
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, timestamp, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(PgConstants.CAST, originName, "bigint");
|
||||
whereName = String.format(PgConstants.FROM_UNIXTIME, cast);
|
||||
String timestamp = String.format(PgConstants.FROM_UNIXTIME, cast);
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, timestamp, format);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = String.format(PgConstants.DATE_FORMAT, originName, format);
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
|
||||
@ -1080,15 +1080,12 @@ public class SqlserverQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
if (field.getDeType() == 1) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
whereName = String.format(SqlServerSQLConstants.STRING_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : SqlServerSQLConstants.DEFAULT_DATE_FORMAT);
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5 || field.getDeExtractType() == 1) {
|
||||
whereName = transDateFormat(request.getDateStyle(), request.getDatePattern(), originName);
|
||||
}
|
||||
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
|
||||
String cast = String.format(SqlServerSQLConstants.LONG_TO_DATE, originName + "/1000");
|
||||
whereName = String.format(SqlServerSQLConstants.FROM_UNIXTIME, cast);
|
||||
}
|
||||
if (field.getDeExtractType() == 1) {
|
||||
whereName = originName;
|
||||
whereName = transDateFormat(request.getDateStyle(), request.getDatePattern(), cast);;
|
||||
}
|
||||
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
|
||||
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
|
||||
@ -1107,7 +1104,7 @@ public class SqlserverQueryProvider extends QueryProvider {
|
||||
}
|
||||
|
||||
String whereName = "";
|
||||
if (request.getIsTree()) {
|
||||
if (request.getIsTree() && whereNameList.size() > 1) {
|
||||
whereName = "CONCAT(" + StringUtils.join(whereNameList, ",',',") + ")";
|
||||
} else {
|
||||
whereName = whereNameList.get(0);
|
||||
|
||||
@ -34,6 +34,7 @@ import io.dataease.plugins.common.base.mapper.DatasetTableFieldMapper;
|
||||
import io.dataease.plugins.common.base.mapper.PanelViewMapper;
|
||||
import io.dataease.plugins.common.constants.DatasetType;
|
||||
import io.dataease.plugins.common.constants.datasource.SQLConstants;
|
||||
import io.dataease.plugins.common.dto.chart.ChartCustomFilterItemDTO;
|
||||
import io.dataease.plugins.common.dto.chart.ChartFieldCompareDTO;
|
||||
import io.dataease.plugins.common.dto.chart.ChartFieldCustomFilterDTO;
|
||||
import io.dataease.plugins.common.dto.chart.ChartViewFieldDTO;
|
||||
@ -49,6 +50,7 @@ import io.dataease.plugins.view.entity.*;
|
||||
import io.dataease.plugins.view.service.ViewPluginService;
|
||||
import io.dataease.plugins.xpack.auth.dto.request.ColumnPermissionItem;
|
||||
import io.dataease.provider.ProviderFactory;
|
||||
import io.dataease.provider.query.SQLUtils;
|
||||
import io.dataease.service.chart.util.ChartDataBuild;
|
||||
import io.dataease.service.dataset.*;
|
||||
import io.dataease.service.datasource.DatasourceService;
|
||||
@ -71,9 +73,8 @@ import java.math.RoundingMode;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @Author gin
|
||||
@ -848,21 +849,40 @@ public class ChartViewService {
|
||||
boolean isDrill = false;
|
||||
List<ChartDrillRequest> drillRequestList = chartExtRequest.getDrill();
|
||||
if (CollectionUtils.isNotEmpty(drillRequestList) && (drill.size() > drillRequestList.size())) {
|
||||
// 如果是从子维度开始下钻,那么先把主维度的条件先加上去
|
||||
if (CollectionUtils.isNotEmpty(xAxisExt) && StringUtils.equalsIgnoreCase(drill.get(0).getId(), xAxisExt.get(0).getId())) {
|
||||
ChartDrillRequest head = drillRequestList.get(0);
|
||||
for (int i = 0; i < xAxisBase.size(); i++) {
|
||||
ChartDimensionDTO dimensionDTO = head.getDimensionList().get(i);
|
||||
DatasetTableField datasetTableField = dataSetTableFieldsService.get(dimensionDTO.getId());
|
||||
ChartExtFilterRequest tmp = new ChartExtFilterRequest();
|
||||
tmp.setFieldId(tmp.getFieldId());
|
||||
tmp.setValue(Collections.singletonList(dimensionDTO.getValue()));
|
||||
tmp.setOperator("in");
|
||||
tmp.setDatasetTableField(datasetTableField);
|
||||
extFilterList.add(tmp);
|
||||
drillFilters.add(tmp);
|
||||
ArrayList<ChartViewFieldDTO> fieldsToFilter = new ArrayList<>();
|
||||
// 如果是从子维度开始下钻,那么其他维度的条件要先加上去
|
||||
// 分组和堆叠
|
||||
if (StringUtils.containsIgnoreCase(view.getType(), "group")) {
|
||||
// 分组堆叠
|
||||
if (StringUtils.containsIgnoreCase(view.getType(), "stack")) {
|
||||
// 分组和堆叠字段都有才有效
|
||||
if (CollectionUtils.isNotEmpty(xAxisExt) && CollectionUtils.isNotEmpty(extStack)) {
|
||||
// 从分组字段下钻,就加上堆叠字段的条件
|
||||
if (StringUtils.equalsIgnoreCase(drill.get(0).getId(), xAxisExt.get(0).getId())) {
|
||||
fieldsToFilter.addAll(xAxisBase);
|
||||
fieldsToFilter.addAll(extStack);
|
||||
}
|
||||
// 从堆叠字段下钻,就加上分组字段的条件
|
||||
if (StringUtils.equalsIgnoreCase(drill.get(0).getId(), extStack.get(0).getId())) {
|
||||
fieldsToFilter.addAll(xAxisBase);
|
||||
fieldsToFilter.addAll(xAxisExt);
|
||||
}
|
||||
}
|
||||
} else if (CollectionUtils.isNotEmpty(xAxisExt) &&
|
||||
StringUtils.equalsIgnoreCase(drill.get(0).getId(), xAxisExt.get(0).getId())) {
|
||||
fieldsToFilter.addAll(xAxisBase);
|
||||
}
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "stack") &&
|
||||
CollectionUtils.isNotEmpty(extStack) &&
|
||||
StringUtils.equalsIgnoreCase(drill.get(0).getId(), extStack.get(0).getId())) {
|
||||
// 堆叠
|
||||
fieldsToFilter.addAll(xAxisBase);
|
||||
}
|
||||
ChartDrillRequest head = drillRequestList.get(0);
|
||||
Map<String, String> dimValMap = head.getDimensionList().stream().collect(Collectors.toMap(ChartDimensionDTO::getId, ChartDimensionDTO::getValue));
|
||||
Map<String, ChartViewFieldDTO> fieldMap = Stream.of(xAxisBase, xAxisExt, extStack).
|
||||
flatMap(Collection::stream).
|
||||
collect(Collectors.toMap(ChartViewFieldDTO::getId, o -> o));
|
||||
for (int i = 0; i < drillRequestList.size(); i++) {
|
||||
ChartDrillRequest request = drillRequestList.get(i);
|
||||
ChartViewFieldDTO chartViewFieldDTO = drill.get(i);
|
||||
@ -870,26 +890,14 @@ public class ChartViewService {
|
||||
// 将钻取值作为条件传递,将所有钻取字段作为xAxis并加上下一个钻取字段
|
||||
if (StringUtils.equalsIgnoreCase(requestDimension.getId(), chartViewFieldDTO.getId())) {
|
||||
isDrill = true;
|
||||
DatasetTableField datasetTableField = dataSetTableFieldsService.get(requestDimension.getId());
|
||||
ChartViewFieldDTO d = new ChartViewFieldDTO();
|
||||
BeanUtils.copyBean(d, datasetTableField);
|
||||
|
||||
ChartExtFilterRequest drillFilter = new ChartExtFilterRequest();
|
||||
drillFilter.setFieldId(requestDimension.getId());
|
||||
drillFilter.setValue(Collections.singletonList(requestDimension.getValue()));
|
||||
drillFilter.setOperator("in");
|
||||
drillFilter.setDatasetTableField(datasetTableField);
|
||||
extFilterList.add(drillFilter);
|
||||
|
||||
drillFilters.add(drillFilter);
|
||||
|
||||
if (!checkDrillExist(xAxis, extStack, d, view)) {
|
||||
xAxis.add(d);
|
||||
fieldsToFilter.add(chartViewFieldDTO);
|
||||
dimValMap.put(requestDimension.getId(), requestDimension.getValue());
|
||||
if (!checkDrillExist(xAxis, extStack, requestDimension.getId(), view)) {
|
||||
xAxis.add(chartViewFieldDTO);
|
||||
}
|
||||
//
|
||||
if (i == drillRequestList.size() - 1) {
|
||||
ChartViewFieldDTO nextDrillField = drill.get(i + 1);
|
||||
if (!checkDrillExist(xAxis, extStack, nextDrillField, view)) {
|
||||
if (!checkDrillExist(xAxis, extStack, nextDrillField.getId(), view)) {
|
||||
// get drill list first element's sort,then assign to nextDrillField
|
||||
nextDrillField.setSort(getDrillSort(xAxis, drill.get(0)));
|
||||
xAxis.add(nextDrillField);
|
||||
@ -898,6 +906,19 @@ public class ChartViewService {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < fieldsToFilter.size(); i++) {
|
||||
ChartViewFieldDTO tmpField = fieldsToFilter.get(i);
|
||||
ChartExtFilterRequest tmpFilter = new ChartExtFilterRequest();
|
||||
DatasetTableField datasetTableField = dataSetTableFieldsService.get(tmpField.getId());
|
||||
tmpFilter.setDatasetTableField(datasetTableField);
|
||||
tmpFilter.setOperator("in");
|
||||
tmpFilter.setDateStyle(fieldMap.get(tmpField.getId()).getDateStyle());
|
||||
tmpFilter.setDatePattern(fieldMap.get(tmpField.getId()).getDatePattern());
|
||||
tmpFilter.setFieldId(tmpField.getId());
|
||||
tmpFilter.setValue(Collections.singletonList(dimValMap.get(tmpField.getId())));
|
||||
extFilterList.add(tmpFilter);
|
||||
drillFilters.add(tmpFilter);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断连接方式,直连或者定时抽取 table.mode
|
||||
@ -922,6 +943,25 @@ public class ChartViewService {
|
||||
assistFields = getAssistFields(dynamicAssistFields, yAxis);
|
||||
}
|
||||
|
||||
// 处理过滤条件中的单引号
|
||||
fieldCustomFilter = fieldCustomFilter.stream().peek(ele -> {
|
||||
if (CollectionUtils.isNotEmpty(ele.getEnumCheckField())) {
|
||||
List<String> collect = ele.getEnumCheckField().stream().map(SQLUtils::transKeyword).collect(Collectors.toList());
|
||||
ele.setEnumCheckField(collect);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(ele.getFilter())) {
|
||||
List<ChartCustomFilterItemDTO> collect = ele.getFilter().stream().peek(f -> f.setValue(SQLUtils.transKeyword(f.getValue()))).collect(Collectors.toList());
|
||||
ele.setFilter(collect);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
extFilterList = extFilterList.stream().peek(ele -> {
|
||||
if (CollectionUtils.isNotEmpty(ele.getValue())) {
|
||||
List<String> collect = ele.getValue().stream().map(SQLUtils::transKeyword).collect(Collectors.toList());
|
||||
ele.setValue(collect);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 如果是插件视图 走插件内部的逻辑
|
||||
if (ObjectUtils.isNotEmpty(view.getIsPlugin()) && view.getIsPlugin()) {
|
||||
Map<String, List<ChartViewFieldDTO>> fieldMap = ObjectUtils.isEmpty(extFieldsMap) ? new LinkedHashMap<>() : extFieldsMap;
|
||||
@ -1540,17 +1580,17 @@ public class ChartViewService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkDrillExist(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> extStack, ChartViewFieldDTO dto, ChartViewWithBLOBs view) {
|
||||
private boolean checkDrillExist(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> extStack, String fieldId, ChartViewWithBLOBs view) {
|
||||
if (CollectionUtils.isNotEmpty(xAxis)) {
|
||||
for (ChartViewFieldDTO x : xAxis) {
|
||||
if (StringUtils.equalsIgnoreCase(x.getId(), dto.getId())) {
|
||||
if (StringUtils.equalsIgnoreCase(x.getId(), fieldId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(view.getType(), "stack") && CollectionUtils.isNotEmpty(extStack)) {
|
||||
for (ChartViewFieldDTO x : extStack) {
|
||||
if (StringUtils.equalsIgnoreCase(x.getId(), dto.getId())) {
|
||||
if (StringUtils.equalsIgnoreCase(x.getId(), fieldId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1797,7 +1837,8 @@ public class ChartViewService {
|
||||
}
|
||||
|
||||
private String handleVariable(String sql, ChartExtRequest requestList, QueryProvider qp, DataSetTableDTO table, Datasource ds) throws Exception {
|
||||
List<SqlVariableDetails> sqlVariables = new Gson().fromJson(table.getSqlVariableDetails(), new TypeToken<List<SqlVariableDetails>>() {}.getType());
|
||||
List<SqlVariableDetails> sqlVariables = new Gson().fromJson(table.getSqlVariableDetails(), new TypeToken<List<SqlVariableDetails>>() {
|
||||
}.getType());
|
||||
if (requestList != null && CollectionUtils.isNotEmpty(requestList.getFilter())) {
|
||||
for (ChartExtFilterRequest chartExtFilterRequest : requestList.getFilter()) {
|
||||
if (CollectionUtils.isEmpty(chartExtFilterRequest.getValue())) {
|
||||
|
||||
@ -21,6 +21,7 @@ import io.dataease.service.datasource.DatasourceService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -34,6 +35,7 @@ import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import io.dataease.ext.*;
|
||||
import springfox.documentation.annotations.Cacheable;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -125,6 +127,13 @@ public class SystemParameterService {
|
||||
boolean open = StringUtils.equals("true", param.getParamValue());
|
||||
result.setScanCreateUser(open ? "true" : "false");
|
||||
}
|
||||
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASIC.MULTI_LOGIN.getValue())) {
|
||||
String paramValue = param.getParamValue();
|
||||
result.setMultiLogin("0");
|
||||
if (StringUtils.isNotBlank(paramValue)) {
|
||||
result.setMultiLogin(paramValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -150,6 +159,7 @@ public class SystemParameterService {
|
||||
public CasSaveResult editBasic(List<SystemParameter> parameters) {
|
||||
CasSaveResult casSaveResult = afterSwitchDefaultLogin(parameters);
|
||||
BasicInfo basicInfo = basicInfo();
|
||||
String oldMultiLogin = this.getValue("loginlimit.multiLogin");
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
SystemParameter parameter = parameters.get(i);
|
||||
SystemParameterExample example = new SystemParameterExample();
|
||||
@ -163,6 +173,10 @@ public class SystemParameterService {
|
||||
example.clear();
|
||||
}
|
||||
datasourceService.updateDatasourceStatusJob(basicInfo, parameters);
|
||||
String newMultiLogin = this.getValue("loginlimit.multiLogin");
|
||||
if (!StringUtils.equals(oldMultiLogin, newMultiLogin)) {
|
||||
clearMultiLoginCache();
|
||||
}
|
||||
return casSaveResult;
|
||||
}
|
||||
|
||||
@ -364,4 +378,17 @@ public class SystemParameterService {
|
||||
return basicInfo;
|
||||
}
|
||||
|
||||
@Cacheable(value = "multiLogin")
|
||||
public String multiLoginType() {
|
||||
String value = getValue("loginlimit.multiLogin");
|
||||
if (StringUtils.isBlank(value)) {
|
||||
value = "0";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@CacheEvict("multiLogin")
|
||||
public void clearMultiLoginCache() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import java.util.*;
|
||||
*/
|
||||
@Service
|
||||
public class ReptileService {
|
||||
String blogUrl = "https://blog.fit2cloud.com/?cat=321";
|
||||
String blogUrl = "https://blog.fit2cloud.com/categories/dataease";
|
||||
//获取最新的前几条数据
|
||||
private static int infoCount=5;
|
||||
|
||||
@ -28,23 +28,20 @@ public class ReptileService {
|
||||
config.setSocketTimeout(5000);
|
||||
//爬取最新数据
|
||||
Document doc = Jsoup.parse(HttpClientUtil.get(blogUrl, config));
|
||||
Elements elementsContent = doc.getElementsByAttributeValue("rel", "bookmark");
|
||||
Elements elementsTime = doc.getElementsByTag("time");
|
||||
Elements elementsContent = doc.getElementsByClass("aspect-w-16");
|
||||
for(int i = 0;i<infoCount;i++){
|
||||
Element info = elementsContent.get(i*3);
|
||||
Element info = elementsContent.get(i).children().get(0);
|
||||
Map<String, String> infoMap = new HashMap();
|
||||
infoMap.put("title",info.attr("title"));
|
||||
infoMap.put("href",info.attr("href"));
|
||||
infoMap.put("time",elementsTime.get(i).childNode(0).outerHtml());
|
||||
result.add(infoMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
//ignore
|
||||
Map<String, String> infoMap = new HashMap();
|
||||
infoMap.put("title","支持移动端展示,数据源新增对DB2的支持,DataEase开源数据可视化分析平台v1.6.0发布");
|
||||
infoMap.put("href","https://blog.fit2cloud.com/?p=3200");
|
||||
infoMap.put("time","2022年1月10日");
|
||||
infoMap.put("title","模板学堂丨妙用Tab组件制作多屏仪表板并实现自动轮播");
|
||||
infoMap.put("href","https://blog.fit2cloud.com/?p=7c524ae9-69f1-4687-a5a2-f27971047308");
|
||||
result.add(infoMap);
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -52,4 +52,6 @@ END if;
|
||||
|
||||
END
|
||||
;;
|
||||
delimiter ;
|
||||
delimiter ;
|
||||
|
||||
INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('loginlimit.multiLogin', '0', 'text', '3');
|
||||
@ -283,7 +283,30 @@
|
||||
<BootstrapCacheLoaderFactory class="net.sf.ehcache.store.DiskStoreBootstrapCacheLoaderFactory" properties="bootstrapAsynchronously=true" />
|
||||
</cache>
|
||||
|
||||
<cache
|
||||
name="online_token_store"
|
||||
eternal="false"
|
||||
maxElementsInMemory="5000"
|
||||
maxElementsOnDisk="50000"
|
||||
overflowToDisk="true"
|
||||
timeToIdleSeconds="28800"
|
||||
timeToLiveSeconds="28800"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
diskPersistent="true">
|
||||
<BootstrapCacheLoaderFactory class="net.sf.ehcache.store.DiskStoreBootstrapCacheLoaderFactory" properties="bootstrapAsynchronously=true" />
|
||||
</cache>
|
||||
|
||||
<cache
|
||||
name="multiLogin"
|
||||
eternal="false"
|
||||
maxElementsInMemory="100"
|
||||
maxElementsOnDisk="1000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="true"
|
||||
timeToIdleSeconds="1800"
|
||||
timeToLiveSeconds="3600"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
</ehcache>
|
||||
@ -8,6 +8,15 @@ export function login(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function seizeLogin(data) {
|
||||
return request({
|
||||
url: '/api/auth/seizeLogin',
|
||||
method: 'post',
|
||||
data,
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfo(token) {
|
||||
return request({
|
||||
url: '/api/auth/userInfo',
|
||||
|
||||
@ -786,7 +786,6 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
min-width: 200px;
|
||||
min-height: 300px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
|
||||
@ -136,13 +136,9 @@ export default {
|
||||
const jumpRequestParam = {
|
||||
sourcePanelId: jumpParam.sourcePanelId,
|
||||
sourceViewId: jumpParam.sourceViewId,
|
||||
sourceFieldId: jumpParam.sourceFieldId,
|
||||
sourceFieldId: null,
|
||||
targetPanelId: this.panelId
|
||||
}
|
||||
//透视表中的其他维度数据数据都进行匹配
|
||||
if (jumpParam.sourceType && jumpParam.sourceType === 'table-pivot') {
|
||||
jumpRequestParam.sourceFieldId = null
|
||||
}
|
||||
try {
|
||||
// 刷新跳转目标仪表板联动信息
|
||||
queryTargetPanelJumpInfo(jumpRequestParam).then(rsp => {
|
||||
|
||||
@ -238,7 +238,7 @@ export default {
|
||||
.VisualSelects {
|
||||
.el-scrollbar {
|
||||
position: relative;
|
||||
height: 251px;
|
||||
height: 245px;
|
||||
overflow: inherit;
|
||||
overflow-x: hidden;
|
||||
content-visibility: auto;
|
||||
@ -270,4 +270,7 @@ export default {
|
||||
.select-all {
|
||||
padding: 10px 20px 0 20px;
|
||||
}
|
||||
.coustom-de-select {
|
||||
z-index: 999 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -198,7 +198,7 @@ export default {
|
||||
validateCom(rule, value, callback) {
|
||||
if (!value) return callback()
|
||||
const one = Number(value)
|
||||
if (Number.isInteger(one)) {
|
||||
if (!Number.isNaN(one)) {
|
||||
if (one < MIN_NUMBER) {
|
||||
return callback(new Error(this.$t('denumberrange.out_of_min')))
|
||||
} else if (one > MAX_NUMBER) {
|
||||
|
||||
@ -382,6 +382,7 @@ export default {
|
||||
thumbnail: 'thumbnail',
|
||||
confirm_delete: 'Confirm delete',
|
||||
delete_this_dashboard: 'Are you sure to delete this dashboard?',
|
||||
delete_this_folder: 'Are you sure to delete this folder?',
|
||||
confirm_stop: 'Confirm stop',
|
||||
stop_success: 'Stop success',
|
||||
treeselect: {
|
||||
@ -1516,7 +1517,11 @@ export default {
|
||||
p_right: 'Right',
|
||||
p_top: 'Top',
|
||||
p_bottom: 'Bottom',
|
||||
p_center: 'Center'
|
||||
p_center: 'Center',
|
||||
table_auto_break_line: 'Auto Line Feed',
|
||||
table_break_line_tip: 'If open this option,the table item height will disabled.',
|
||||
step: 'Step(px)',
|
||||
no_function: 'Function not enter,please input.'
|
||||
},
|
||||
dataset: {
|
||||
scope_edit: 'Effective only when editing',
|
||||
@ -2545,7 +2550,7 @@ export default {
|
||||
please_key_max: 'Please key max value',
|
||||
out_of_min: 'The min value cannot be less than the min integer -2³²',
|
||||
out_of_max: 'The max value cannot be more than the max integer 2³²-1',
|
||||
must_int: 'Please key integer',
|
||||
must_int: 'Please key number',
|
||||
min_out_max: 'The min value must be less than the max value',
|
||||
max_out_min: 'The max value must be more than the min value'
|
||||
},
|
||||
@ -2867,5 +2872,14 @@ export default {
|
||||
reset: 'Reset',
|
||||
preview: 'Preview',
|
||||
save: 'Save'
|
||||
},
|
||||
multi_login_lang: {
|
||||
title: 'The current account is online!',
|
||||
ip: 'IP',
|
||||
time: 'Login time',
|
||||
label: 'Prohibit multi-terminal login!',
|
||||
confirm_title: 'Forced login will cause other clients to go offline',
|
||||
confirm: 'Whether to force login?',
|
||||
forced_offline: '`The current account is logged in on the client [${ip}],and you have been pushed off the line!`'
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,6 +382,7 @@ export default {
|
||||
thumbnail: '縮略圖',
|
||||
confirm_delete: '確認刪除',
|
||||
delete_this_dashboard: '確認删除該儀錶板嗎?',
|
||||
delete_this_folder: '確認删除該目錄嗎?',
|
||||
confirm_stop: '確認停止',
|
||||
stop_success: '停止成功',
|
||||
treeselect: {
|
||||
@ -1510,7 +1511,11 @@ export default {
|
||||
p_right: '右對齊',
|
||||
p_top: '上對齊',
|
||||
p_bottom: '下對齊',
|
||||
p_center: '居中'
|
||||
p_center: '居中',
|
||||
table_auto_break_line: '自動換行',
|
||||
table_break_line_tip: '開啟自動換行,表格行高設置將失效',
|
||||
step: '步長(px)',
|
||||
no_function: '函數尚未支持直接引用,請在字段表達式中手動輸入。'
|
||||
},
|
||||
dataset: {
|
||||
scope_edit: '僅編輯時生效',
|
||||
@ -2539,7 +2544,7 @@ export default {
|
||||
please_key_max: '請輸入最大值',
|
||||
out_of_min: '最小值不能小於最小整數-2³²',
|
||||
out_of_max: '最大值不能大於最大整數2³²-1',
|
||||
must_int: '請輸入整數',
|
||||
must_int: '請輸入數字',
|
||||
min_out_max: '最小值必須小於最大值',
|
||||
max_out_min: '最大值必須大於最小值'
|
||||
},
|
||||
@ -2860,5 +2865,14 @@ export default {
|
||||
reset: '重置',
|
||||
preview: '預覽',
|
||||
save: '保存'
|
||||
},
|
||||
multi_login_lang: {
|
||||
title: '當前賬號已在線!',
|
||||
ip: 'IP',
|
||||
time: '登錄時間',
|
||||
label: '禁止多端登錄!',
|
||||
confirm_title: '強行登錄會導致其他客戶端掉線',
|
||||
confirm: '是否強行登錄?',
|
||||
forced_offline: '`當前賬號在客戶端【${ip}】登錄,您已被擠下線!`'
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { $confirm } from '@/utils/message'
|
||||
|
||||
export default {
|
||||
fu: {
|
||||
search_bar: {
|
||||
@ -381,6 +383,7 @@ export default {
|
||||
thumbnail: '缩略图',
|
||||
confirm_delete: '确认删除',
|
||||
delete_this_dashboard: '确认删除该仪表板吗?',
|
||||
delete_this_folder: '确认删除该目录吗?',
|
||||
confirm_stop: '确认停止',
|
||||
stop_success: '停止成功',
|
||||
treeselect: {
|
||||
@ -1509,7 +1512,11 @@ export default {
|
||||
p_right: '右对齐',
|
||||
p_top: '上对齐',
|
||||
p_bottom: '下对齐',
|
||||
p_center: '居中'
|
||||
p_center: '居中',
|
||||
table_auto_break_line: '自动换行',
|
||||
table_break_line_tip: '开启自动换行,表格行高设置将失效',
|
||||
step: '步长(px)',
|
||||
no_function: '函数尚未支持直接引用,请在字段表达式中手动输入。'
|
||||
},
|
||||
dataset: {
|
||||
scope_edit: '仅编辑时生效',
|
||||
@ -2539,7 +2546,7 @@ export default {
|
||||
please_key_max: '请输入最大值',
|
||||
out_of_min: '最小值不能小于最小整数-2³²',
|
||||
out_of_max: '最大值不能大于最大整数2³²-1',
|
||||
must_int: '请输入整数',
|
||||
must_int: '请输入数字',
|
||||
min_out_max: '最小值必须小于最大值',
|
||||
max_out_min: '最大值必须大于最小值'
|
||||
},
|
||||
@ -2860,5 +2867,14 @@ export default {
|
||||
reset: '重置',
|
||||
preview: '预览',
|
||||
save: '保存'
|
||||
},
|
||||
multi_login_lang: {
|
||||
title: '当前账号已在线!',
|
||||
ip: 'IP',
|
||||
time: '登录时间',
|
||||
label: '禁止多端登录!',
|
||||
confirm_title: '强行登录会导致其他客户端掉线',
|
||||
confirm: '是否强行登录?',
|
||||
forced_offline: '`当前账号在客户端【${ip}】登录,您已被挤下线!`'
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,6 +239,9 @@ export default {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('beforeunload', (e) => this.beforeunloadHandler(e))
|
||||
window.addEventListener('unload', (e) => this.unloadHandler(e))
|
||||
|
||||
this.initCurrentRoutes()
|
||||
bus.$on('set-top-menu-info', this.setTopMenuInfo)
|
||||
bus.$on('set-top-menu-active-info', this.setTopMenuActiveInfo)
|
||||
@ -251,6 +254,9 @@ export default {
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('beforeunload', (e) => this.beforeunloadHandler(e))
|
||||
window.removeEventListener('unload', (e) => this.unloadHandler(e))
|
||||
|
||||
bus.$off('set-top-menu-info', this.setTopMenuInfo)
|
||||
bus.$off('set-top-menu-active-info', this.setTopMenuActiveInfo)
|
||||
bus.$off('set-top-text-info', this.setTopTextInfo)
|
||||
@ -269,6 +275,16 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
beforeunloadHandler() {
|
||||
this.beforeUnload_time = new Date().getTime()
|
||||
},
|
||||
unloadHandler(e) {
|
||||
this.gap_time = new Date().getTime() - this.beforeUnload_time
|
||||
if (this.gap_time <= 5) {
|
||||
this.logout().then(res => {})
|
||||
}
|
||||
},
|
||||
|
||||
// 通过当前路径找到二级菜单对应项,存到store,用来渲染左侧菜单
|
||||
initCurrentRoutes() {
|
||||
const {
|
||||
|
||||
@ -61,6 +61,7 @@ import DeMainContainer from '@/components/dataease/DeMainContainer'
|
||||
import DeContainer from '@/components/dataease/DeContainer'
|
||||
import DeAsideContainer from '@/components/dataease/DeAsideContainer'
|
||||
import bus from '@/utils/bus'
|
||||
import { showMultiLoginMsg } from '@/utils/index'
|
||||
|
||||
import { needModifyPwd, removePwdTips } from '@/api/user'
|
||||
|
||||
@ -131,11 +132,22 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('PanelSwitchComponent', this.panelSwitchComponent)
|
||||
bus.$on('web-seize-topic-call', this.webMsgTopicCall)
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('PanelSwitchComponent', this.panelSwitchComponent)
|
||||
bus.$off('web-seize-topic-call', this.webMsgTopicCall)
|
||||
},
|
||||
created() {
|
||||
showMultiLoginMsg()
|
||||
},
|
||||
methods: {
|
||||
webMsgTopicCall(param) {
|
||||
const ip = param
|
||||
const msg = this.$t('multi_login_lang.forced_offline')
|
||||
this.$error(eval(msg))
|
||||
bus.$emit('sys-logout')
|
||||
},
|
||||
panelSwitchComponent(c) {
|
||||
this.componentName = c.name
|
||||
},
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import Cookies from 'js-cookie'
|
||||
import i18n from '@/lang'
|
||||
import { $error, $confirm } from '@/utils/message'
|
||||
import { seizeLogin } from '@/api/user'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import { Loading } from 'element-ui'
|
||||
export function timeSection(date, type, labelFormat = 'yyyy-MM-dd') {
|
||||
if (!date) {
|
||||
return null
|
||||
@ -352,3 +358,45 @@ export const inOtherPlatform = () => {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const showMultiLoginMsg = () => {
|
||||
const multiLoginError1 = Cookies.get('MultiLoginError1')
|
||||
if (multiLoginError1) {
|
||||
Cookies.remove('MultiLoginError1')
|
||||
const infos = JSON.parse(multiLoginError1)
|
||||
const content = infos.map(info => buildMultiLoginErrorItem(info)).join('</br>')
|
||||
let msgContent = '<strong>' + i18n.t('multi_login_lang.title') + '</strong>'
|
||||
msgContent += content + '<p>' + i18n.t('multi_login_lang.label') + '</p>'
|
||||
$error(msgContent, 10000, true)
|
||||
}
|
||||
const multiLoginError2 = Cookies.get('MultiLoginError2')
|
||||
if (multiLoginError2) {
|
||||
const infos = JSON.parse(multiLoginError2)
|
||||
Cookies.remove('MultiLoginError2')
|
||||
const content = infos.map(info => buildMultiLoginErrorItem(info)).join('</br>')
|
||||
let msgContent = '<strong>' + i18n.t('multi_login_lang.confirm_title') + '</strong>'
|
||||
msgContent += content + '<p>' + i18n.t('multi_login_lang.confirm') + '</p>'
|
||||
$confirm(msgContent, () => seize(infos[0]), {
|
||||
dangerouslyUseHTMLString: true
|
||||
})
|
||||
}
|
||||
}
|
||||
const seize = model => {
|
||||
const loadingInstance = Loading.service({})
|
||||
const token = model.token
|
||||
const param = {
|
||||
token
|
||||
}
|
||||
seizeLogin(param).then(res => {
|
||||
const resultToken = res.data.token
|
||||
store.dispatch('user/refreshToken', resultToken)
|
||||
router.push('/')
|
||||
loadingInstance.close()
|
||||
})
|
||||
}
|
||||
const buildMultiLoginErrorItem = (info) => {
|
||||
if (!info) return null
|
||||
const ip = i18n.t('multi_login_lang.ip')
|
||||
const time = i18n.t('multi_login_lang.time')
|
||||
return '<p>' + ip + ': ' + info.ip + ', ' + time + ': ' + new Date(info.loginTime).format('yyyy-MM-dd hh:mm:ss') + '</p>'
|
||||
}
|
||||
|
||||
@ -47,12 +47,13 @@ export const $warning = (message, duration) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const $error = (message, duration) => {
|
||||
export const $error = (message, duration, useHtml) => {
|
||||
Message.error({
|
||||
message: message,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
duration: duration || 10000
|
||||
duration: duration || 10000,
|
||||
dangerouslyUseHTMLString: useHtml
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ service.interceptors.response.use(response => {
|
||||
if (msg.length > 600) {
|
||||
msg = msg.slice(0, 600)
|
||||
}
|
||||
!config.hideMsg && (!headers['authentication-status']) && $error(msg)
|
||||
!config.hideMsg && (!headers['authentication-status']) && !msg?.startsWith("MultiLoginError") && $error(msg)
|
||||
return Promise.reject(config.url === '/dataset/table/sqlPreview' ? msg : error)
|
||||
})
|
||||
const checkDownError = response => {
|
||||
|
||||
@ -77,6 +77,7 @@ export const DEFAULT_SIZE = {
|
||||
tableColumnWidth: 100,
|
||||
tableHeaderAlign: 'left',
|
||||
tableItemAlign: 'right',
|
||||
tableAutoBreakLine: false,
|
||||
gaugeMinType: 'fix', // fix or dynamic
|
||||
gaugeMinField: {
|
||||
id: '',
|
||||
@ -462,7 +463,8 @@ export const DEFAULT_THRESHOLD = {
|
||||
export const DEFAULT_SCROLL = {
|
||||
open: false,
|
||||
row: 1,
|
||||
interval: 2000
|
||||
interval: 2000,
|
||||
step: 50
|
||||
}
|
||||
// chart config
|
||||
export const BASE_BAR = {
|
||||
|
||||
@ -200,13 +200,31 @@ export function getLabel(chart) {
|
||||
f.formatterCfg.thousandSeparator = false
|
||||
}
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else if (equalsAny(chart.type, 'bar-group', 'bar-group-stack')) {
|
||||
} else if (equalsAny(chart.type, 'bar-group')) {
|
||||
const f = yAxis[0]
|
||||
if (f.formatterCfg) {
|
||||
res = valueFormatter(param.value, f.formatterCfg)
|
||||
} else {
|
||||
res = valueFormatter(param.value, formatterItem)
|
||||
}
|
||||
} else if (equalsAny(chart.type, 'bar-group-stack')) {
|
||||
const f = yAxis[0]
|
||||
let formatterCfg = formatterItem
|
||||
if (f.formatterCfg) {
|
||||
formatterCfg = f.formatterCfg
|
||||
}
|
||||
const labelContent = l.labelContent ?? ['quota']
|
||||
const contentItems = []
|
||||
if (labelContent.includes('group')) {
|
||||
contentItems.push(param.group)
|
||||
}
|
||||
if (labelContent.includes('stack')) {
|
||||
contentItems.push(param.category)
|
||||
}
|
||||
if (labelContent.includes('quota')) {
|
||||
contentItems.push(valueFormatter(param.value, formatterCfg))
|
||||
}
|
||||
res = contentItems.join('\n')
|
||||
} else {
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
@ -363,7 +381,14 @@ export function getTooltip(chart) {
|
||||
if (chart.type === 'bar-group') {
|
||||
obj = { name: param.category, value: param.value }
|
||||
} else {
|
||||
obj = { name: param.group, value: param.value }
|
||||
let name = ''
|
||||
if (param.group) {
|
||||
name = param.name + '-'
|
||||
}
|
||||
if (param.category) {
|
||||
name += param.category
|
||||
}
|
||||
obj = { name: name, value: param.value }
|
||||
}
|
||||
for (let i = 0; i < yAxis.length; i++) {
|
||||
const f = yAxis[i]
|
||||
|
||||
@ -886,7 +886,8 @@ export const TYPE_CONFIGS = [
|
||||
'show',
|
||||
'fontSize',
|
||||
'color',
|
||||
'position-v'
|
||||
'position-v',
|
||||
'labelContent'
|
||||
],
|
||||
'tooltip-selector-ant-v': [
|
||||
'show',
|
||||
@ -1847,6 +1848,7 @@ export const TYPE_CONFIGS = [
|
||||
'tableItemBgColor',
|
||||
'tableHeaderFontColor',
|
||||
'tableFontColor',
|
||||
'tableBorderColor',
|
||||
'tableScrollBarColor',
|
||||
'alpha'
|
||||
],
|
||||
@ -1857,7 +1859,8 @@ export const TYPE_CONFIGS = [
|
||||
'tableItemHeight',
|
||||
'tableColumnWidth',
|
||||
'showIndex',
|
||||
'indexLabel'
|
||||
'indexLabel',
|
||||
'tableAutoBreakLine'
|
||||
],
|
||||
'title-selector': [
|
||||
'show',
|
||||
@ -1887,6 +1890,7 @@ export const TYPE_CONFIGS = [
|
||||
'tableItemBgColor',
|
||||
'tableHeaderFontColor',
|
||||
'tableFontColor',
|
||||
'tableBorderColor',
|
||||
'tableScrollBarColor',
|
||||
'alpha'
|
||||
],
|
||||
@ -1899,7 +1903,8 @@ export const TYPE_CONFIGS = [
|
||||
'tableItemHeight',
|
||||
'tableColumnWidth',
|
||||
'showIndex',
|
||||
'indexLabel'
|
||||
'indexLabel',
|
||||
'tableAutoBreakLine'
|
||||
],
|
||||
'title-selector': [
|
||||
'show',
|
||||
@ -3549,3 +3554,13 @@ export function resetRgbOpacity(sourceColor, times) {
|
||||
}
|
||||
return sourceColor
|
||||
}
|
||||
|
||||
export function getDefaultLabelContent(chart) {
|
||||
if (chart?.type?.includes('pie')) {
|
||||
return ['dimension', 'proportion']
|
||||
}
|
||||
if (chart?.type?.includes('bar')) {
|
||||
return ['quota']
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
</el-form-item>
|
||||
<span v-show="scrollForm.open">
|
||||
<el-form-item
|
||||
v-show="!isAutoBreakLine"
|
||||
:label="$t('chart.row')"
|
||||
class="form-item"
|
||||
>
|
||||
@ -43,6 +44,20 @@
|
||||
@change="changeScrollCfg"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="isAutoBreakLine"
|
||||
:label="$t('chart.step')"
|
||||
class="form-item"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="scrollForm.step"
|
||||
:min="1"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
size="mini"
|
||||
@change="changeScrollCfg"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('chart.interval') + '(ms)'"
|
||||
class="form-item"
|
||||
@ -63,7 +78,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DEFAULT_SCROLL } from '@/views/chart/chart/chart'
|
||||
import { DEFAULT_SCROLL, DEFAULT_SIZE } from '@/views/chart/chart/chart'
|
||||
|
||||
export default {
|
||||
name: 'ScrollCfg',
|
||||
@ -75,7 +90,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollForm: JSON.parse(JSON.stringify(DEFAULT_SCROLL))
|
||||
scrollForm: JSON.parse(JSON.stringify(DEFAULT_SCROLL)),
|
||||
isAutoBreakLine: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -100,10 +116,26 @@ export default {
|
||||
}
|
||||
if (senior.scrollCfg) {
|
||||
this.scrollForm = senior.scrollCfg
|
||||
this.scrollForm.step = senior.scrollCfg.step ? senior.scrollCfg.step : DEFAULT_SCROLL.step
|
||||
} else {
|
||||
this.scrollForm = JSON.parse(JSON.stringify(DEFAULT_SCROLL))
|
||||
}
|
||||
}
|
||||
if (chart.customAttr) {
|
||||
let customAttr = null
|
||||
if (Object.prototype.toString.call(chart.customAttr) === '[object Object]') {
|
||||
customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
||||
} else {
|
||||
customAttr = JSON.parse(chart.customAttr)
|
||||
}
|
||||
if (customAttr.size) {
|
||||
if (this.chart.render === 'antv') {
|
||||
this.isAutoBreakLine = false
|
||||
} else {
|
||||
this.isAutoBreakLine = customAttr.size.tableAutoBreakLine ? customAttr.size.tableAutoBreakLine : DEFAULT_SIZE.tableAutoBreakLine
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
changeScrollCfg() {
|
||||
this.$emit('onScrollCfgChange', this.scrollForm)
|
||||
|
||||
@ -314,11 +314,6 @@ export default {
|
||||
{ name: this.$t('chart.reserve_zero'), value: 0 },
|
||||
{ name: this.$t('chart.reserve_one'), value: 1 },
|
||||
{ name: this.$t('chart.reserve_two'), value: 2 }
|
||||
],
|
||||
labelContentOptions: [
|
||||
{ name: this.$t('chart.dimension'), value: 'dimension' },
|
||||
{ name: this.$t('chart.quota'), value: 'quota' },
|
||||
{ name: this.$t('chart.proportion'), value: 'proportion' }
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -403,6 +398,25 @@ export default {
|
||||
showProperty(property) {
|
||||
return this.propertyInner.includes(property)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labelContentOptions() {
|
||||
if (this.chart.type.includes('pie')) {
|
||||
return [
|
||||
{ name: this.$t('chart.dimension'), value: 'dimension' },
|
||||
{ name: this.$t('chart.quota'), value: 'quota' },
|
||||
{ name: this.$t('chart.proportion'), value: 'proportion' }
|
||||
]
|
||||
}
|
||||
if (this.chart.type.includes('bar')) {
|
||||
return [
|
||||
{ name: this.$t('chart.chart_group'), value: 'group' },
|
||||
{ name: this.$t('chart.stack_item'), value: 'stack' },
|
||||
{ name: this.$t('chart.quota'), value: 'quota' }
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -283,6 +283,30 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="showProperty('tableAutoBreakLine')"
|
||||
label-width="100px"
|
||||
:label="$t('chart.table_auto_break_line')"
|
||||
class="form-item"
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="sizeForm.tableAutoBreakLine"
|
||||
@change="changeBarSizeCase('tableAutoBreakLine')"
|
||||
>{{ $t('chart.open') }}</el-checkbox>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
placement="bottom"
|
||||
>
|
||||
<div slot="content">
|
||||
{{ $t('chart.table_break_line_tip') }}
|
||||
</div>
|
||||
<i
|
||||
class="el-icon-info"
|
||||
style="cursor: pointer;color: gray;font-size: 12px;"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-show="showProperty('tableTitleFontSize')"
|
||||
label-width="100px"
|
||||
@ -345,6 +369,7 @@
|
||||
>
|
||||
<el-slider
|
||||
v-model="sizeForm.tableItemHeight"
|
||||
:disabled="sizeForm.tableAutoBreakLine"
|
||||
:min="36"
|
||||
:max="100"
|
||||
show-input
|
||||
@ -1127,6 +1152,8 @@ export default {
|
||||
|
||||
this.sizeForm.hPosition = this.sizeForm.hPosition ? this.sizeForm.hPosition : DEFAULT_SIZE.hPosition
|
||||
this.sizeForm.vPosition = this.sizeForm.vPosition ? this.sizeForm.vPosition : DEFAULT_SIZE.vPosition
|
||||
|
||||
this.sizeForm.tableAutoBreakLine = this.sizeForm.tableAutoBreakLine ? this.sizeForm.tableAutoBreakLine : DEFAULT_SIZE.tableAutoBreakLine
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -4,7 +4,10 @@
|
||||
:style="bg_class"
|
||||
style="padding: 8px;width: 100%;height: 100%;overflow: hidden;"
|
||||
>
|
||||
<el-row style="height: 100%;">
|
||||
<el-row
|
||||
style="height: 100%;"
|
||||
:style="cssVars"
|
||||
>
|
||||
<p
|
||||
v-show="title_show"
|
||||
ref="title"
|
||||
@ -93,7 +96,7 @@
|
||||
<script>
|
||||
import { hexColorToRGBA } from '../../chart/util'
|
||||
import eventBus from '@/components/canvas/utils/eventBus'
|
||||
import { DEFAULT_COLOR_CASE, DEFAULT_SIZE, NOT_SUPPORT_PAGE_DATASET } from '@/views/chart/chart/chart'
|
||||
import { DEFAULT_COLOR_CASE, DEFAULT_SCROLL, DEFAULT_SIZE, NOT_SUPPORT_PAGE_DATASET } from '@/views/chart/chart/chart'
|
||||
import { mapState } from 'vuex'
|
||||
import DePagination from '@/components/deCustomCm/pagination.js'
|
||||
|
||||
@ -178,7 +181,13 @@ export default {
|
||||
color: '#606266'
|
||||
},
|
||||
not_support_page_dataset: NOT_SUPPORT_PAGE_DATASET,
|
||||
mergeCells: []
|
||||
mergeCells: [],
|
||||
cssStyleParams: {
|
||||
borderColor: DEFAULT_COLOR_CASE.tableBorderColor,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -208,7 +217,16 @@ export default {
|
||||
},
|
||||
...mapState([
|
||||
'previewCanvasScale'
|
||||
])
|
||||
]),
|
||||
cssVars() {
|
||||
return {
|
||||
'--color': this.cssStyleParams.borderColor,
|
||||
'--overflow': this.cssStyleParams.overflow,
|
||||
'--text-overflow': this.cssStyleParams.textOverflow,
|
||||
'--white-space': this.cssStyleParams.whiteSpace
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
chart: function() {
|
||||
@ -329,6 +347,7 @@ export default {
|
||||
calcHeightRightNow() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.tableContainer) {
|
||||
const attr = JSON.parse(this.chart.customAttr)
|
||||
let pageHeight = 0
|
||||
if (this.showPage) {
|
||||
pageHeight = 36
|
||||
@ -338,23 +357,32 @@ export default {
|
||||
let tableHeight
|
||||
if (this.chart.data) {
|
||||
if (this.chart.type === 'table-info') {
|
||||
tableHeight = (this.currentPage.pageSize + 2) * 36 - pageHeight
|
||||
if (this.showPage) {
|
||||
tableHeight = this.currentPage.pageSize * attr.size.tableItemHeight + attr.size.tableTitleHeight
|
||||
} else {
|
||||
tableHeight = this.chart.data.tableRow.length * attr.size.tableItemHeight + attr.size.tableTitleHeight
|
||||
}
|
||||
} else if (this.chart.data.detailFields?.length) {
|
||||
let rowLength = 0
|
||||
this.chart.data.tableRow.forEach(row => {
|
||||
rowLength += (row?.details?.length || 1)
|
||||
})
|
||||
tableHeight = (rowLength + 2) * 36 - pageHeight
|
||||
tableHeight = rowLength * attr.size.tableItemHeight + 2 * attr.size.tableTitleHeight
|
||||
} else {
|
||||
tableHeight = (this.chart.data.tableRow.length + 2) * 36 - pageHeight
|
||||
tableHeight = this.chart.data.tableRow.length * attr.size.tableItemHeight + 2 * attr.size.tableTitleHeight
|
||||
}
|
||||
} else {
|
||||
tableHeight = 0
|
||||
}
|
||||
if (tableHeight > tableMaxHeight) {
|
||||
const breakLine = attr.size.tableAutoBreakLine ? attr.size.tableAutoBreakLine : DEFAULT_SIZE.tableAutoBreakLine
|
||||
if (breakLine) {
|
||||
this.height = tableMaxHeight + 'px'
|
||||
} else {
|
||||
this.height = 'auto'
|
||||
if (tableHeight > tableMaxHeight) {
|
||||
this.height = tableMaxHeight + 'px'
|
||||
} else {
|
||||
this.height = 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
if (this.enableScroll) {
|
||||
@ -379,6 +407,7 @@ export default {
|
||||
this.table_item_class.color = customAttr.color.tableFontColor
|
||||
this.table_item_class.background = hexColorToRGBA(customAttr.color.tableItemBgColor, customAttr.color.alpha)
|
||||
this.scrollBarColor = customAttr.color.tableScrollBarColor ? customAttr.color.tableScrollBarColor : DEFAULT_COLOR_CASE.tableScrollBarColor
|
||||
this.cssStyleParams.borderColor = customAttr.color.tableBorderColor ? customAttr.color.tableBorderColor : DEFAULT_COLOR_CASE.tableBorderColor
|
||||
}
|
||||
if (customAttr.size) {
|
||||
this.table_header_class.fontSize = customAttr.size.tableTitleFontSize + 'px'
|
||||
@ -400,6 +429,17 @@ export default {
|
||||
} else {
|
||||
this.indexLabel = customAttr.size.indexLabel
|
||||
}
|
||||
|
||||
const autoBreakLine = customAttr.size.tableAutoBreakLine ? customAttr.size.tableAutoBreakLine : DEFAULT_SIZE.tableAutoBreakLine
|
||||
if (autoBreakLine) {
|
||||
this.cssStyleParams.overflow = 'hidden'
|
||||
this.cssStyleParams.textOverflow = 'auto'
|
||||
this.cssStyleParams.whiteSpace = 'normal'
|
||||
} else {
|
||||
this.cssStyleParams.overflow = 'hidden'
|
||||
this.cssStyleParams.textOverflow = 'ellipsis'
|
||||
this.cssStyleParams.whiteSpace = 'nowrap'
|
||||
}
|
||||
}
|
||||
this.table_item_class_stripe = JSON.parse(JSON.stringify(this.table_item_class))
|
||||
// 暂不支持斑马纹
|
||||
@ -552,8 +592,18 @@ export default {
|
||||
if (rowHeight < 36) {
|
||||
rowHeight = 36
|
||||
}
|
||||
|
||||
const attr = JSON.parse(this.chart.customAttr)
|
||||
const breakLine = attr.size.tableAutoBreakLine ? attr.size.tableAutoBreakLine : DEFAULT_SIZE.tableAutoBreakLine
|
||||
|
||||
this.scrollTimer = setInterval(() => {
|
||||
const top = rowHeight * senior.scrollCfg.row
|
||||
let top = 0
|
||||
if (breakLine) {
|
||||
top = senior.scrollCfg.step ? senior.scrollCfg.step : DEFAULT_SCROLL.step
|
||||
} else {
|
||||
top = rowHeight * senior.scrollCfg.row
|
||||
}
|
||||
|
||||
if (scrollContainer.clientHeight + scrollContainer.scrollTop < scrollContainer.scrollHeight) {
|
||||
this.scrollTop += top
|
||||
} else {
|
||||
@ -628,4 +678,32 @@ export default {
|
||||
.table-class{
|
||||
scrollbar-color: var(--scroll-bar-color) transparent;
|
||||
}
|
||||
|
||||
.table-class {
|
||||
::v-deep .elx-table.border--full .elx-body--column,
|
||||
::v-deep .elx-table.border--full .elx-footer--column,
|
||||
::v-deep .elx-table.border--full .elx-header--column {
|
||||
background-image: linear-gradient(var(--color, #e8eaec), var(--color, #e8eaec)), linear-gradient(var(--color, #e8eaec), var(--color, #e8eaec)) !important;
|
||||
}
|
||||
::v-deep .elx-table--border-line {
|
||||
border: 1px solid var(--color, #e8eaec) !important;
|
||||
}
|
||||
::v-deep .elx-table .elx-table--header-wrapper .elx-table--header-border-line {
|
||||
border-bottom: 1px solid var(--color, #e8eaec) !important;
|
||||
}
|
||||
::v-deep .elx-table .elx-table--footer-wrapper {
|
||||
border-top: 1px solid var(--color, #e8eaec) !important;
|
||||
}
|
||||
::v-deep .elx-checkbox .elx-checkbox--label,
|
||||
::v-deep .elx-radio .elx-radio--label,
|
||||
::v-deep .elx-radio-button .elx-radio--label,
|
||||
::v-deep .elx-table .elx-body--column.col--ellipsis:not(.col--actived) > .elx-cell,
|
||||
::v-deep .elx-table .elx-footer--column.col--ellipsis:not(.col--actived) > .elx-cell,
|
||||
::v-deep .elx-table .elx-header--column.col--ellipsis:not(.col--actived) > .elx-cell{
|
||||
overflow: var(--overflow, 'hidden');
|
||||
text-overflow: var(--text-overflow, 'ellipsis');
|
||||
white-space: var(--white-space, 'nowrap');
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -513,6 +513,7 @@ import {
|
||||
} from '../chart/chart'
|
||||
import { checkViewTitle } from '@/components/canvas/utils/utils'
|
||||
import { adaptCurTheme } from '@/components/canvas/utils/style'
|
||||
import { getDefaultLabelContent } from '@/views/chart/chart/util'
|
||||
|
||||
export default {
|
||||
name: 'Group',
|
||||
@ -1060,6 +1061,7 @@ export default {
|
||||
if (type === 'pie-donut-rose') {
|
||||
attr.size.pieInnerRadius = Math.round(attr.size.pieOuterRadius * 0.5)
|
||||
}
|
||||
attr.label.labelContent = getDefaultLabelContent(view)
|
||||
} else if (type.includes('line')) {
|
||||
attr.label.position = 'top'
|
||||
} else if (type.includes('treemap')) {
|
||||
|
||||
@ -260,26 +260,32 @@
|
||||
clearable
|
||||
/>
|
||||
<el-row class="function-height">
|
||||
<el-popover
|
||||
v-for="(item,index) in functionData"
|
||||
:key="index"
|
||||
class="function-pop"
|
||||
placement="right"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
:open-delay="500"
|
||||
>
|
||||
<p class="pop-title">{{ item.name }}</p>
|
||||
<p class="pop-info">{{ item.func }}</p>
|
||||
<p class="pop-info">{{ item.desc }}</p>
|
||||
<span
|
||||
slot="reference"
|
||||
class="function-style"
|
||||
@click="insertParamToCodeMirror(item.func)"
|
||||
>{{
|
||||
item.func
|
||||
}}</span>
|
||||
</el-popover>
|
||||
<div v-if="functionData && functionData.length > 0">
|
||||
<el-popover
|
||||
v-for="(item,index) in functionData"
|
||||
:key="index"
|
||||
class="function-pop"
|
||||
placement="right"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
:open-delay="500"
|
||||
>
|
||||
<p class="pop-title">{{ item.name }}</p>
|
||||
<p class="pop-info">{{ item.func }}</p>
|
||||
<p class="pop-info">{{ item.desc }}</p>
|
||||
<span
|
||||
slot="reference"
|
||||
class="function-style"
|
||||
@click="insertParamToCodeMirror(item.func)"
|
||||
>{{
|
||||
item.func
|
||||
}}</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="class-na"
|
||||
>{{ $t('chart.no_function') }}</div>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -28,7 +28,12 @@
|
||||
:data="view"
|
||||
:tab-status="tabStatus"
|
||||
/>
|
||||
<svg-icon slot="reference" class="icon-class" style="position:absolute; margin-left: 30px; top:14px;cursor: pointer;" icon-class="icon_info_filled" />
|
||||
<svg-icon
|
||||
slot="reference"
|
||||
class="icon-class"
|
||||
style="position:absolute; margin-left: 30px; top:14px;cursor: pointer;"
|
||||
icon-class="icon_info_filled"
|
||||
/>
|
||||
</el-popover>
|
||||
<span
|
||||
class="title-text view-title-name"
|
||||
@ -188,7 +193,7 @@
|
||||
@command="chartFieldEdit"
|
||||
>
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-s-tools"/>
|
||||
<i class="el-icon-s-tools" />
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
@ -263,7 +268,7 @@
|
||||
@command="chartFieldEdit"
|
||||
>
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-s-tools"/>
|
||||
<i class="el-icon-s-tools" />
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
@ -358,7 +363,7 @@
|
||||
style="padding: 6px;"
|
||||
>
|
||||
{{ $t('chart.change_chart_type') }}
|
||||
<i class="el-icon-caret-bottom"/>
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</el-button>
|
||||
</el-popover>
|
||||
</span>
|
||||
@ -549,8 +554,8 @@
|
||||
>
|
||||
<span class="data-area-label">
|
||||
<span v-if="view.type && view.type.includes('table')">{{
|
||||
$t('chart.drag_block_table_data_column')
|
||||
}}</span>
|
||||
$t('chart.drag_block_table_data_column')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="view.type && (view.type.includes('bar') || view.type.includes('line') || view.type.includes('scatter') || view.type === 'chart-mix' || view.type === 'waterfall' || view.type === 'area')"
|
||||
>{{ $t('chart.drag_block_type_axis') }}</span>
|
||||
@ -558,18 +563,18 @@
|
||||
v-else-if="view.type && view.type.includes('pie')"
|
||||
>{{ $t('chart.drag_block_pie_label') }}</span>
|
||||
<span v-else-if="view.type && view.type.includes('funnel')">{{
|
||||
$t('chart.drag_block_funnel_split')
|
||||
}}</span>
|
||||
$t('chart.drag_block_funnel_split')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type.includes('radar')">{{
|
||||
$t('chart.drag_block_radar_label')
|
||||
}}</span>
|
||||
$t('chart.drag_block_radar_label')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type === 'map'">{{ $t('chart.area') }}</span>
|
||||
<span v-else-if="view.type && view.type.includes('treemap')">{{
|
||||
$t('chart.drag_block_treemap_label')
|
||||
}}</span>
|
||||
$t('chart.drag_block_treemap_label')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type === 'word-cloud'">{{
|
||||
$t('chart.drag_block_word_cloud_label')
|
||||
}}</span>
|
||||
$t('chart.drag_block_word_cloud_label')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type === 'label'">{{ $t('chart.drag_block_label') }}</span>
|
||||
<span v-show="view.type !== 'richTextView'"> / </span>
|
||||
<span v-if="view.type && view.type !== 'table-info'">{{ $t('chart.dimension') }}</span>
|
||||
@ -693,8 +698,8 @@
|
||||
>
|
||||
<span class="data-area-label">
|
||||
<span v-if="view.type && view.type.includes('table')">{{
|
||||
$t('chart.drag_block_table_data_column')
|
||||
}}</span>
|
||||
$t('chart.drag_block_table_data_column')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="view.type && (view.type.includes('bar') || view.type.includes('line') || view.type.includes('scatter') || view.type === 'waterfall' || view.type === 'area')"
|
||||
>{{ $t('chart.drag_block_value_axis') }}</span>
|
||||
@ -702,30 +707,30 @@
|
||||
v-else-if="view.type && view.type.includes('pie')"
|
||||
>{{ $t('chart.drag_block_pie_angel') }}</span>
|
||||
<span v-else-if="view.type && view.type.includes('funnel')">{{
|
||||
$t('chart.drag_block_funnel_width')
|
||||
}}</span>
|
||||
$t('chart.drag_block_funnel_width')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type.includes('radar')">{{
|
||||
$t('chart.drag_block_radar_length')
|
||||
}}</span>
|
||||
$t('chart.drag_block_radar_length')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type.includes('gauge')">{{
|
||||
$t('chart.drag_block_gauge_angel')
|
||||
}}</span>
|
||||
$t('chart.drag_block_gauge_angel')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="view.type && view.type.includes('text')"
|
||||
>{{ $t('chart.drag_block_label_value') }}</span>
|
||||
<span v-else-if="view.type && view.type === 'map'">{{ $t('chart.chart_data') }}</span>
|
||||
<span v-else-if="view.type && view.type.includes('tree')">{{
|
||||
$t('chart.drag_block_treemap_size')
|
||||
}}</span>
|
||||
$t('chart.drag_block_treemap_size')
|
||||
}}</span>
|
||||
<span v-else-if="view.type && view.type === 'chart-mix'">{{
|
||||
$t('chart.drag_block_value_axis_main')
|
||||
}}</span>
|
||||
$t('chart.drag_block_value_axis_main')
|
||||
}}</span>
|
||||
<span
|
||||
v-else-if="view.type && view.type === 'liquid'"
|
||||
>{{ $t('chart.drag_block_progress') }}</span>
|
||||
<span v-else-if="view.type && view.type === 'word-cloud'">{{
|
||||
$t('chart.drag_block_word_cloud_size')
|
||||
}}</span>
|
||||
$t('chart.drag_block_word_cloud_size')
|
||||
}}</span>
|
||||
<span v-show="view.type !== 'richTextView'"> / </span>
|
||||
<span>{{ $t('chart.quota') }}</span>
|
||||
<i
|
||||
@ -1197,7 +1202,7 @@
|
||||
:title="$t('panel.position_adjust_component')"
|
||||
:name="'positionAdjust'"
|
||||
>
|
||||
<position-adjust/>
|
||||
<position-adjust />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
@ -1353,7 +1358,7 @@
|
||||
width="800px"
|
||||
class="dialog-css"
|
||||
>
|
||||
<quota-filter-editor :item="quotaItem"/>
|
||||
<quota-filter-editor :item="quotaItem" />
|
||||
<div
|
||||
slot="footer"
|
||||
class="dialog-footer"
|
||||
@ -1380,7 +1385,7 @@
|
||||
width="800px"
|
||||
class="dialog-css"
|
||||
>
|
||||
<dimension-filter-editor :item="dimensionItem"/>
|
||||
<dimension-filter-editor :item="dimensionItem" />
|
||||
<div
|
||||
slot="footer"
|
||||
class="dialog-footer"
|
||||
@ -1743,6 +1748,7 @@ import CalcChartFieldEdit from '@/views/chart/view/CalcChartFieldEdit'
|
||||
import { equalsAny } from '@/utils/StringUtils'
|
||||
import PositionAdjust from '@/views/chart/view/PositionAdjust'
|
||||
import MarkMapDataEditor from '@/views/chart/components/map/MarkMapDataEditor'
|
||||
import { getDefaultLabelContent } from '@/views/chart/chart/util'
|
||||
|
||||
export default {
|
||||
name: 'ChartEdit',
|
||||
@ -2002,6 +2008,7 @@ export default {
|
||||
bus.$off('show-quota-edit-filter', this.showQuotaEditFilter)
|
||||
bus.$off('show-quota-edit-compare', this.showQuotaEditCompare)
|
||||
bus.$off('show-edit-filter', this.showEditFilter)
|
||||
bus.$off('show-edit-formatter', this.valueFormatter)
|
||||
bus.$off('calc-data', this.calcData)
|
||||
bus.$off('plugins-calc-style', this.calcStyle)
|
||||
bus.$off('plugin-chart-click', this.chartClick)
|
||||
@ -2072,6 +2079,7 @@ export default {
|
||||
bus.$on('show-quota-edit-filter', this.showQuotaEditFilter)
|
||||
bus.$on('show-quota-edit-compare', this.showQuotaEditCompare)
|
||||
bus.$on('show-edit-filter', this.showEditFilter)
|
||||
bus.$on('show-edit-formatter', this.valueFormatter)
|
||||
bus.$on('calc-data', this.calcData)
|
||||
bus.$on('plugins-calc-style', this.calcStyle)
|
||||
bus.$on('plugin-chart-click', this.chartClick)
|
||||
@ -2892,19 +2900,22 @@ export default {
|
||||
|
||||
// 更换数据集
|
||||
changeChart() {
|
||||
this.view.dataFrom = 'dataset'
|
||||
const optType = this.view.tableId === this.changeTable.id ? 'same' : 'change'
|
||||
// this.save(true, 'chart', false)
|
||||
this.view.tableId = this.changeTable.id
|
||||
// 更换数据集后清空视图字段
|
||||
post('/chart/field/deleteByChartId/' + this.param.id + '/' + this.panelInfo.id, null).then(response => {
|
||||
// reset gauge
|
||||
this.view.customAttr.size.gaugeMinType = 'fix'
|
||||
this.view.customAttr.size.gaugeMaxType = 'fix'
|
||||
this.calcData(true, 'chart', false)
|
||||
this.initTableData(this.view.tableId, optType)
|
||||
// 更换数据集后清空视图字段,并重新请求数据;否则没有操作
|
||||
if (optType === 'change') {
|
||||
this.view.dataFrom = 'dataset'
|
||||
this.view.tableId = this.changeTable.id
|
||||
post('/chart/field/deleteByChartId/' + this.param.id + '/' + this.panelInfo.id, null).then(response => {
|
||||
// reset gauge
|
||||
this.view.customAttr.size.gaugeMinType = 'fix'
|
||||
this.view.customAttr.size.gaugeMaxType = 'fix'
|
||||
this.calcData(true, 'chart', false)
|
||||
this.initTableData(this.view.tableId, optType)
|
||||
this.closeChangeChart()
|
||||
})
|
||||
} else {
|
||||
this.closeChangeChart()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
fieldFilter(val) {
|
||||
@ -3303,6 +3314,7 @@ export default {
|
||||
this.view.customAttr.label.position = 'middle'
|
||||
}
|
||||
}
|
||||
customAttr.label.labelContent = getDefaultLabelContent(this.view)
|
||||
// reset custom colors
|
||||
this.view.customAttr.color.seriesColors = []
|
||||
},
|
||||
|
||||
@ -236,24 +236,30 @@
|
||||
clearable
|
||||
/>
|
||||
<el-row class="function-height">
|
||||
<el-popover
|
||||
v-for="(item, index) in functionData"
|
||||
:key="index"
|
||||
class="function-pop"
|
||||
placement="right"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
:open-delay="500"
|
||||
>
|
||||
<p class="pop-title">{{ item.name }}</p>
|
||||
<p class="pop-info">{{ item.func }}</p>
|
||||
<p class="pop-info">{{ item.desc }}</p>
|
||||
<span
|
||||
slot="reference"
|
||||
class="function-style"
|
||||
@click="insertParamToCodeMirror(item.func)"
|
||||
>{{ item.func }}</span>
|
||||
</el-popover>
|
||||
<div v-if="functionData && functionData.length > 0">
|
||||
<el-popover
|
||||
v-for="(item, index) in functionData"
|
||||
:key="index"
|
||||
class="function-pop"
|
||||
placement="right"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
:open-delay="500"
|
||||
>
|
||||
<p class="pop-title">{{ item.name }}</p>
|
||||
<p class="pop-info">{{ item.func }}</p>
|
||||
<p class="pop-info">{{ item.desc }}</p>
|
||||
<span
|
||||
slot="reference"
|
||||
class="function-style"
|
||||
@click="insertParamToCodeMirror(item.func)"
|
||||
>{{ item.func }}</span>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="class-na"
|
||||
>{{ $t('chart.no_function') }}</div>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -212,7 +212,7 @@
|
||||
import { encrypt } from '@/utils/rsaEncrypt'
|
||||
import { ldapStatus, oidcStatus, getPublicKey, pluginLoaded, defaultLoginType, wecomStatus, dingtalkStatus, larkStatus, larksuiteStatus, casStatus, casLoginPage } from '@/api/user'
|
||||
import { getSysUI } from '@/utils/auth'
|
||||
import { changeFavicon } from '@/utils/index'
|
||||
import { changeFavicon, showMultiLoginMsg } from '@/utils/index'
|
||||
import { initTheme } from '@/utils/ThemeUtil'
|
||||
import PluginCom from '@/views/system/plugin/PluginCom'
|
||||
import Cookies from 'js-cookie'
|
||||
@ -395,6 +395,7 @@ export default {
|
||||
this.$error(Cookies.get('LarksuiteError'))
|
||||
}
|
||||
this.clearLarksuiteMsg()
|
||||
showMultiLoginMsg()
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -476,14 +477,18 @@ export default {
|
||||
this.$store.dispatch('user/login', user).then(() => {
|
||||
this.$router.push({ path: this.redirect || '/' })
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
}).catch((e) => {
|
||||
this.loading = false
|
||||
e?.response?.data?.message?.startsWith('MultiLoginError') && this.showMessage()
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
showMessage() {
|
||||
showMultiLoginMsg()
|
||||
},
|
||||
changeLoginType(val) {
|
||||
if (val !== 2 && val !== 7) return
|
||||
this.clearOidcMsg()
|
||||
|
||||
@ -92,7 +92,7 @@ export default {
|
||||
.filter-field {
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
|
||||
overflow-x: overlay;
|
||||
.field-content {
|
||||
position: relative;
|
||||
display: table;
|
||||
|
||||
@ -850,7 +850,7 @@ export default {
|
||||
|
||||
delete(data) {
|
||||
const params = {
|
||||
title: 'commons.delete_this_dashboard',
|
||||
title: data.nodeType === 'folder'?'commons.delete_this_folder':'commons.delete_this_dashboard',
|
||||
type: 'danger',
|
||||
cb: () => {
|
||||
delGroup(data.id).then((response) => {
|
||||
@ -899,7 +899,7 @@ export default {
|
||||
groupTree(this.groupForm, !userCache).then((res) => {
|
||||
localStorage.setItem('panel-main-tree', JSON.stringify(res.data || []))
|
||||
if (!userCache) {
|
||||
this.tData = res.data
|
||||
this.tData = res.data || []
|
||||
}
|
||||
if (this.responseSource === 'appApply') {
|
||||
this.fromAppActive()
|
||||
|
||||
@ -159,6 +159,13 @@
|
||||
component-name="LoginLimitSetting"
|
||||
/>
|
||||
|
||||
<plugin-com
|
||||
v-if="isPluginLoaded"
|
||||
ref="MultiLoginLimit"
|
||||
:form="formInline"
|
||||
component-name="MultiLoginLimit"
|
||||
/>
|
||||
|
||||
<plugin-com
|
||||
v-if="isPluginLoaded && scanOpen"
|
||||
ref="ScanLimitSetting"
|
||||
@ -429,6 +436,12 @@ export default {
|
||||
paramValue: this.formInline.scanCreateUser,
|
||||
type: 'text',
|
||||
sort: 3
|
||||
},
|
||||
{
|
||||
paramKey: 'loginlimit.multiLogin',
|
||||
paramValue: this.formInline.multiLogin,
|
||||
type: 'text',
|
||||
sort: 3
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
<span class="content_middle_title">{{ $t('wizard.latest_developments') }}</span>
|
||||
<div class="content_middle_more"><a
|
||||
target="_blank"
|
||||
href="https://blog.fit2cloud.com/?cat=321"
|
||||
href="https://blog.fit2cloud.com/categories/dataease"
|
||||
>{{ $t('wizard.more') }}<i class="el-icon-arrow-right"/></a></div>
|
||||
</el-row>
|
||||
<el-row>
|
||||
|
||||
@ -2,7 +2,6 @@ import bus from '@/utils/bus'
|
||||
import SockJS from 'sockjs-client'
|
||||
import Stomp from 'stompjs'
|
||||
import store from '@/store'
|
||||
|
||||
class DeWebsocket {
|
||||
constructor() {
|
||||
this.ws_url = '/websocket'
|
||||
@ -11,6 +10,10 @@ class DeWebsocket {
|
||||
{
|
||||
topic: '/web-msg-topic',
|
||||
event: 'web-msg-topic-call'
|
||||
},
|
||||
{
|
||||
topic: '/web-seize-topic',
|
||||
event: 'web-seize-topic-call'
|
||||
}
|
||||
]
|
||||
this.timer = null
|
||||
|
||||
@ -30,8 +30,7 @@ module.exports = {
|
||||
overlay: {
|
||||
warnings: false,
|
||||
errors: true
|
||||
},
|
||||
before: require('./mock/mock-server.js')
|
||||
}
|
||||
},
|
||||
|
||||
pages: {
|
||||
|
||||
@ -2,7 +2,7 @@ import request from '@/common/js/request'
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/api/auth/login',
|
||||
url: '/api/auth/mobileLogin',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
||||
@ -60,10 +60,13 @@ checkAuth(error.response)
|
||||
} else {
|
||||
msg = error.message
|
||||
}
|
||||
if (msg?.startsWith('MultiLoginError')) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
uni.showToast({
|
||||
icon: 'error',
|
||||
title: msg
|
||||
});
|
||||
})
|
||||
return Promise.reject(error)
|
||||
})
|
||||
const logout = () => {
|
||||
|
||||
@ -31,7 +31,8 @@
|
||||
"loginbtn": "Login",
|
||||
"pwdFmtError": "Password Must More Than 6 Characters",
|
||||
"uOrpwdError": "Invalid Account Or Password",
|
||||
"accFmtError": "Account Must More Than 1 Characters"
|
||||
"accFmtError": "Account Must More Than 1 Characters",
|
||||
"multiLogin": "The current account is online,Prohibit multi-terminal login"
|
||||
},
|
||||
"home": {
|
||||
"tab1": "My Favorites",
|
||||
|
||||
@ -31,7 +31,8 @@
|
||||
"loginbtn": "登录",
|
||||
"pwdFmtError": "密码最短为1个字符",
|
||||
"accFmtError": "账号最短为1个字符",
|
||||
"uOrpwdError": "无效账号或密码"
|
||||
"uOrpwdError": "无效账号或密码",
|
||||
"multiLogin": "当前账号已在线,禁止多端登录"
|
||||
},
|
||||
"home": {
|
||||
"tab1": "我的收藏",
|
||||
|
||||
@ -32,7 +32,8 @@
|
||||
"loginbtn": "登錄",
|
||||
"pwdFmtError": "密碼最短為6個字符",
|
||||
"uOrpwdError": "無效賬號或密碼",
|
||||
"accFmtError": "帳號最短為1個字符"
|
||||
"accFmtError": "帳號最短為1個字符",
|
||||
"multiLogin": "當前賬號已在線,禁止多端登錄"
|
||||
},
|
||||
"home": {
|
||||
"tab1": "我的收藏",
|
||||
|
||||
@ -106,9 +106,13 @@
|
||||
|
||||
}).catch(error => {
|
||||
this.loginBtnLoading = false
|
||||
let msg = error.response.data.message
|
||||
if (msg?.startsWith('MultiLoginError')) {
|
||||
msg = this.$t('login.multiLogin')
|
||||
}
|
||||
uni.showToast({
|
||||
icon: 'error',
|
||||
title: error.response.data.message,
|
||||
title: msg,
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
@ -36,7 +36,8 @@
|
||||
</template>
|
||||
<script>
|
||||
import { setToken, getLanguage } from '@/common/utils'
|
||||
import {getUserInfo, setUserInfo} from '@/common/utils'
|
||||
import { getUserInfo, setUserInfo } from '@/common/utils'
|
||||
import { logout } from '@/api/auth'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@ -85,11 +86,15 @@ export default {
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
setToken(null)
|
||||
setUserInfo(null)
|
||||
uni.reLaunch({
|
||||
url: '/'
|
||||
});
|
||||
const callBack = () => {
|
||||
setToken(null)
|
||||
setUserInfo(null)
|
||||
uni.reLaunch({
|
||||
url: '/'
|
||||
});
|
||||
}
|
||||
logout().then(res => {callBack()}).catch(e => {callBack()})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@ module.exports = {
|
||||
LinkTokenKey: 'LINK-PWD-TOKEN',
|
||||
title: 'DataEase',
|
||||
WHITE_LIST: [
|
||||
'/api/auth/login',
|
||||
'/api/auth/getPublicKey',
|
||||
'/system/ui/info',
|
||||
'/system/ui/image/'
|
||||
'/api/auth/login',
|
||||
'/api/auth/getPublicKey',
|
||||
'/system/ui/info',
|
||||
'/system/ui/image/'
|
||||
|
||||
],
|
||||
RECENT_KEY: 'recently',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user