Merge remote-tracking branch 'origin/main' into main
# Conflicts: # backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
7
.gitignore
vendored
@ -27,7 +27,7 @@ target/
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
node/
|
||||
|
||||
# local env files
|
||||
.env.demo
|
||||
@ -47,5 +47,10 @@ pnpm-debug.log*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.lock
|
||||
*.classpath
|
||||
*.project
|
||||
.settings/
|
||||
|
||||
|
||||
package-lock.json
|
||||
|
||||
17
Dockerfile
Normal file
@ -0,0 +1,17 @@
|
||||
FROM registry.fit2cloud.com/fit2cloud3/fabric8-java-alpine-openjdk8-jre
|
||||
|
||||
ARG IMAGE_TAG
|
||||
|
||||
RUN mkdir -p /opt/apps
|
||||
|
||||
ADD backend/target/backend-1.0.jar /opt/apps
|
||||
|
||||
ENV JAVA_APP_JAR=/opt/apps/backend-1.0.jar
|
||||
|
||||
ENV AB_OFF=true
|
||||
|
||||
ENV JAVA_OPTIONS=-Dfile.encoding=utf-8
|
||||
|
||||
HEALTHCHECK --interval=15s --timeout=5s --retries=20 --start-period=30s CMD curl -f 127.0.0.1:8081
|
||||
|
||||
CMD ["/deployments/run-java.sh"]
|
||||
@ -303,17 +303,6 @@
|
||||
<artifactId>reflections8</artifactId>
|
||||
<version>0.11.7</version>
|
||||
</dependency>
|
||||
<!-- k8s client -->
|
||||
<!--<dependency>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>kubernetes-client</artifactId>
|
||||
<version>4.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.fge</groupId>
|
||||
<artifactId>json-schema-validator</artifactId>
|
||||
<version>2.2.6</version>
|
||||
</dependency>-->
|
||||
<!--开启 cache 缓存 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -325,6 +314,25 @@
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
<!-- hbase -->
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-client</artifactId>
|
||||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hbase</groupId>
|
||||
<artifactId>hbase-common</artifactId>
|
||||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>6.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -430,6 +438,34 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
<!-- <plugin>-->
|
||||
<!-- <groupId>org.apache.maven.plugins</groupId>-->
|
||||
<!-- <artifactId>maven-antrun-plugin</artifactId>-->
|
||||
<!-- <executions>-->
|
||||
<!-- <execution>-->
|
||||
<!-- <id>main-class-placement</id>-->
|
||||
<!-- <phase>generate-resources</phase>-->
|
||||
<!-- <configuration>-->
|
||||
<!-- <target>-->
|
||||
<!-- <move todir="src/main/resources/static">-->
|
||||
<!-- <fileset dir="../frontend/dist">-->
|
||||
<!-- <exclude name="*.html"/>-->
|
||||
<!-- </fileset>-->
|
||||
<!-- </move>-->
|
||||
<!-- <move todir="src/main/resources/templates">-->
|
||||
<!-- <fileset dir="../frontend/dist">-->
|
||||
<!-- <include name="*.html"/>-->
|
||||
<!-- </fileset>-->
|
||||
<!-- </move>-->
|
||||
<!-- </target>-->
|
||||
<!-- </configuration>-->
|
||||
<!-- <goals>-->
|
||||
<!-- <goal>run</goal>-->
|
||||
<!-- </goals>-->
|
||||
<!-- </execution>-->
|
||||
<!-- </executions>-->
|
||||
<!-- </plugin>-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@ -13,8 +13,9 @@ import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -23,7 +24,8 @@ import java.util.stream.Collectors;
|
||||
@Component
|
||||
public class F2CRealm extends AuthorizingRealm {
|
||||
|
||||
@Resource
|
||||
@Autowired
|
||||
@Lazy //shiro组件加载过早 让authUserService等一等再注入 否则 注入的可能不是代理对象
|
||||
private AuthUserService authUserService;
|
||||
|
||||
|
||||
@ -36,7 +38,6 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
@Override
|
||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||
Long userId = JWTUtils.tokenInfoByToken(principals.toString()).getUserId();
|
||||
//SysUserEntity user = authUserService.getUserById(userId);
|
||||
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
|
||||
Set<String> role = authUserService.roles(userId).stream().collect(Collectors.toSet());
|
||||
simpleAuthorizationInfo.addRoles(role);
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package io.dataease.auth.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "dataease")
|
||||
@Data
|
||||
public class WhitelistConfig {
|
||||
|
||||
private List<String> whitelist;
|
||||
|
||||
|
||||
}
|
||||
@ -6,6 +6,9 @@ import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
@ -23,6 +26,8 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
|
||||
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public final static String expireMessage = "login token is expire";
|
||||
|
||||
/*@Autowired
|
||||
private AuthUserService authUserService;*/
|
||||
|
||||
@ -45,7 +50,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
String authorization = httpServletRequest.getHeader("Authorization");
|
||||
|
||||
// 当没有出现登录超时 且需要刷新token 则执行刷新token
|
||||
if (JWTUtils.loginExpire(authorization)){
|
||||
throw new AuthenticationException(expireMessage);
|
||||
}
|
||||
if (JWTUtils.needRefresh(authorization)){
|
||||
authorization = refreshToken(request, response);
|
||||
}
|
||||
@ -67,7 +75,12 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
boolean loginSuccess = executeLogin(request, response);
|
||||
return loginSuccess;
|
||||
} catch (Exception e) {
|
||||
response401(request, response);
|
||||
if (e instanceof AuthenticationException && StringUtils.equals(e.getMessage(), expireMessage)){
|
||||
responseExpire(request, response);
|
||||
}else {
|
||||
response401(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -81,7 +94,13 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class);
|
||||
SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId());
|
||||
String password = user.getPassword();
|
||||
|
||||
// 删除老token操作时间
|
||||
JWTUtils.removeTokenExpire(token);
|
||||
String newToken = JWTUtils.sign(tokenInfo, password);
|
||||
// 记录新token操作时间
|
||||
JWTUtils.addTokenExpire(newToken);
|
||||
|
||||
JWTToken jwtToken = new JWTToken(newToken);
|
||||
this.getSubject(request, response).login(jwtToken);
|
||||
// 设置响应的Header头新Token
|
||||
@ -123,4 +142,16 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void responseExpire(ServletRequest req, ServletResponse resp) {
|
||||
try {
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
|
||||
httpServletResponse.addHeader("Access-Control-Expose-Headers", "authentication-status");
|
||||
httpServletResponse.setHeader("authentication-status", "login_expire");
|
||||
httpServletResponse.setStatus(401);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -49,6 +49,8 @@ public class AuthServer implements AuthApi {
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(username).lastLoginTime(System.currentTimeMillis()).build();
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd);
|
||||
// 记录token操作时间
|
||||
JWTUtils.addTokenExpire(token);
|
||||
result.put("token", token);
|
||||
ServletUtils.setToken(token);
|
||||
return result;
|
||||
@ -79,6 +81,9 @@ public class AuthServer implements AuthApi {
|
||||
|
||||
@Override
|
||||
public String test() {
|
||||
SysUserEntity userById = authUserService.getUserById(4L);
|
||||
String nickName = userById.getNickName();
|
||||
System.out.println(nickName);
|
||||
return "apple";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,22 @@
|
||||
package io.dataease.auth.service.impl;
|
||||
|
||||
import io.dataease.auth.config.WhitelistConfig;
|
||||
import io.dataease.auth.service.ShiroService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@Service
|
||||
public class ShiroServiceImpl implements ShiroService {
|
||||
|
||||
private final static String ANON = "anon";
|
||||
|
||||
@Autowired
|
||||
private WhitelistConfig whitelistConfig;
|
||||
|
||||
@Override
|
||||
public Map<String, String> loadFilterChainDefinitionMap() {
|
||||
@ -20,47 +25,38 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
// 配置过滤:不会被拦截的链接 -> 放行 start ----------------------------------------------------------
|
||||
// 放行Swagger2页面,需要放行这些
|
||||
|
||||
filterChainDefinitionMap.put("/swagger-ui.html","anon");
|
||||
filterChainDefinitionMap.put("/swagger-ui/**","anon");
|
||||
|
||||
filterChainDefinitionMap.put("/swagger/**","anon");
|
||||
filterChainDefinitionMap.put("/webjars/**", "anon");
|
||||
filterChainDefinitionMap.put("/swagger-resources/**","anon");
|
||||
filterChainDefinitionMap.put("/v2/**","anon");
|
||||
filterChainDefinitionMap.put("/v3/**","anon");
|
||||
filterChainDefinitionMap.put("/static/**", "anon");
|
||||
filterChainDefinitionMap.put("/common-files/**", "anon");
|
||||
|
||||
|
||||
// filterChainDefinitionMap.put("/401", "anon");
|
||||
// filterChainDefinitionMap.put("/404", "anon");
|
||||
// 登陆
|
||||
// filterChainDefinitionMap.put("/api/auth/logout", "anon");
|
||||
filterChainDefinitionMap.put("/api/auth/login", "anon");
|
||||
// 退出
|
||||
|
||||
// 放行未授权接口,重定向使用
|
||||
filterChainDefinitionMap.put("/unauth", "anon");
|
||||
filterChainDefinitionMap.put("/display/**", "anon");
|
||||
|
||||
// token过期接口
|
||||
filterChainDefinitionMap.put("/tokenExpired", "anon");
|
||||
// 被挤下线
|
||||
filterChainDefinitionMap.put("/downline", "anon");
|
||||
// 放行 end ----------------------------------------------------------
|
||||
|
||||
/*List<ExtPermissionBean> extPermissionBeans = extUserMapper.getPermissions();
|
||||
|
||||
extPermissionBeans.forEach(item -> {
|
||||
StringJoiner f2cPerms = new StringJoiner(",", "f2cPerms[", "]");
|
||||
f2cPerms.add(item.getPermission());
|
||||
filterChainDefinitionMap.put(item.getPath(), "jwt," + f2cPerms);
|
||||
filterChainDefinitionMap.put("/swagger-ui.html",ANON);
|
||||
filterChainDefinitionMap.put("/swagger-ui/**",ANON);
|
||||
filterChainDefinitionMap.put("/swagger/**",ANON);
|
||||
filterChainDefinitionMap.put("/webjars/**", ANON);
|
||||
filterChainDefinitionMap.put("/swagger-resources/**",ANON);
|
||||
filterChainDefinitionMap.put("/v2/**",ANON);
|
||||
filterChainDefinitionMap.put("/v3/**",ANON);
|
||||
filterChainDefinitionMap.put("/static/**", ANON);
|
||||
filterChainDefinitionMap.put("/css/**", ANON);
|
||||
filterChainDefinitionMap.put("/js/**", ANON);
|
||||
filterChainDefinitionMap.put("/img/**", ANON);
|
||||
filterChainDefinitionMap.put("/fonts/**", ANON);
|
||||
filterChainDefinitionMap.put("/favicon.ico", ANON);
|
||||
filterChainDefinitionMap.put("/", ANON);
|
||||
filterChainDefinitionMap.put("/index.html", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/login", ANON);
|
||||
filterChainDefinitionMap.put("/unauth", ANON);
|
||||
filterChainDefinitionMap.put("/display/**", ANON);
|
||||
filterChainDefinitionMap.put("/tokenExpired", ANON);
|
||||
filterChainDefinitionMap.put("/downline", ANON);
|
||||
List<String> whitelist = whitelistConfig.getWhitelist();
|
||||
if (CollectionUtils.isNotEmpty(whitelist))
|
||||
whitelist.forEach(path -> {
|
||||
filterChainDefinitionMap.put(path, ANON);
|
||||
});
|
||||
*/
|
||||
|
||||
filterChainDefinitionMap.put("/api/auth/logout", "logout");
|
||||
filterChainDefinitionMap.put("/**", "jwt");
|
||||
return filterChainDefinitionMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession) {
|
||||
|
||||
@ -6,20 +6,23 @@ import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import io.dataease.auth.filter.JWTFilter;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class JWTUtils {
|
||||
|
||||
|
||||
// token过期时间5min (过期会自动刷新续命 目的是避免一直都是同一个token )
|
||||
private static final long EXPIRE_TIME = 1*60*1000;
|
||||
// token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token )
|
||||
private static final long EXPIRE_TIME = 1*60*1000/2;
|
||||
// 登录间隔时间10min 超过这个时间强制重新登录
|
||||
private static final long Login_Interval = 10*60*1000;
|
||||
private static final long Login_Interval = 20*60*1000;
|
||||
|
||||
|
||||
/**
|
||||
@ -35,16 +38,12 @@ public class JWTUtils {
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId())
|
||||
.build();
|
||||
DecodedJWT jwt = verifier.verify(token);
|
||||
Long lastLoginTime = jwt.getClaim("lastLoginTime").asLong();
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastLoginTime > Login_Interval){
|
||||
verifier.verify(token);
|
||||
if (loginExpire(token)){
|
||||
// 登录超时
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
response.addHeader("Access-Control-Expose-Headers", "authentication-status");
|
||||
response.setHeader("authentication-status", "login_expire");
|
||||
throw new AuthenticationException(JWTFilter.expireMessage);
|
||||
// 前端拦截 登录超时状态 直接logout
|
||||
return false;
|
||||
//return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -74,6 +73,17 @@ public class JWTUtils {
|
||||
return new Date().getTime() >= exp.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前token是否登录超时
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static boolean loginExpire(String token){
|
||||
Long now = System.currentTimeMillis();
|
||||
Long lastOperateTime = tokenLastOperateTime(token);
|
||||
return now - lastOperateTime > Login_Interval;
|
||||
}
|
||||
|
||||
public static Date getExp(String token) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
@ -106,4 +116,29 @@ public class JWTUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前token上次操作时间
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static Long tokenLastOperateTime(String token){
|
||||
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
|
||||
Cache tokens_expire = cacheManager.getCache("tokens_expire");
|
||||
Long expTime = tokens_expire.get(token, Long.class);
|
||||
return expTime;
|
||||
}
|
||||
|
||||
public static void removeTokenExpire(String token){
|
||||
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
|
||||
Cache tokens_expire = cacheManager.getCache("tokens_expire");
|
||||
tokens_expire.evict(token);
|
||||
}
|
||||
|
||||
public static void addTokenExpire(String token){
|
||||
CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
|
||||
Cache tokens_expire = cacheManager.getCache("tokens_expire");
|
||||
long now = System.currentTimeMillis();
|
||||
tokens_expire.put(token, now);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package io.dataease.base.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class DatasetTableField implements Serializable {
|
||||
private String id;
|
||||
|
||||
@ -24,4 +27,4 @@ public class DatasetTableField implements Serializable {
|
||||
private Integer deType;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package io.dataease.base.mapper.ext;
|
||||
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import io.dataease.controller.sys.request.SimpleTreeNode;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -22,4 +21,9 @@ public interface ExtDeptMapper {
|
||||
" <foreach collection='ids' item='id' open='(' separator=',' close=')'>#{id}</foreach> " +
|
||||
"</script>")
|
||||
int batchDelete(@Param("ids") List<Long> ids);
|
||||
|
||||
|
||||
List<SimpleTreeNode> allNodes();
|
||||
|
||||
List<SimpleTreeNode> nodesByExample(GridExample example);
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.dataease.base.mapper.ext.ExtDeptMapper">
|
||||
|
||||
<resultMap id="simpleNode" type="io.dataease.controller.sys.request.SimpleTreeNode">
|
||||
<id property="id" column="id" javaType="java.lang.Long" />
|
||||
<result property="pid" column="pid" javaType="java.lang.Long"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="allNodes" resultMap="simpleNode">
|
||||
select dept_id as id, pid from sys_dept
|
||||
</select>
|
||||
|
||||
|
||||
<select id="nodesByExample" resultType="io.dataease.base.mapper.ext.query.GridExample" resultMap="simpleNode">
|
||||
select dept_id as id, pid from sys_dept
|
||||
<include refid="io.dataease.base.mapper.ext.query.GridSql.gridCondition" />
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@ -1,6 +1,7 @@
|
||||
package io.dataease.base.mapper.ext;
|
||||
|
||||
import io.dataease.base.domain.SysRole;
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import io.dataease.controller.sys.request.RoleGridRequest;
|
||||
import io.dataease.controller.sys.response.RoleUserItem;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -12,7 +13,7 @@ import java.util.Map;
|
||||
public interface ExtSysRoleMapper {
|
||||
|
||||
|
||||
List<SysRole> query(@Param("request")RoleGridRequest request);
|
||||
List<SysRole> query(GridExample example);
|
||||
|
||||
int deleteRoleMenu(@Param("roleId") Long roleId);
|
||||
|
||||
|
||||
@ -9,15 +9,19 @@
|
||||
<result property="name" column="name"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="query" resultMap="io.dataease.base.mapper.SysRoleMapper.BaseResultMap">
|
||||
<select id="query" parameterType="io.dataease.base.mapper.ext.query.GridExample" resultMap="io.dataease.base.mapper.SysRoleMapper.BaseResultMap">
|
||||
select r.*
|
||||
from sys_role r
|
||||
<where>
|
||||
<if test="request.name != null">
|
||||
AND r.name like CONCAT('%', #{request.name},'%')
|
||||
</if>
|
||||
</where>
|
||||
order by r.update_time desc
|
||||
<if test="_parameter != null">
|
||||
<include refid="io.dataease.base.mapper.ext.query.GridSql.gridCondition" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
<if test="orderByClause == null">
|
||||
order by r.update_time desc
|
||||
</if>
|
||||
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package io.dataease.base.mapper.ext;
|
||||
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.UserGridRequest;
|
||||
import io.dataease.controller.sys.response.SysUserGridResponse;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -8,5 +10,5 @@ import java.util.List;
|
||||
|
||||
public interface ExtSysUserMapper {
|
||||
|
||||
List<SysUserGridResponse> query(@Param("request")UserGridRequest request);
|
||||
List<SysUserGridResponse> query(GridExample example);
|
||||
}
|
||||
|
||||
@ -27,17 +27,24 @@
|
||||
</collection>
|
||||
</resultMap>
|
||||
|
||||
<select id="query" resultMap="BaseResultMap">
|
||||
|
||||
|
||||
<select id="query" parameterType="io.dataease.base.mapper.ext.query.GridExample" resultMap="BaseResultMap">
|
||||
select u.*,u.user_id as id, r.role_id,r.name as role_name , d.pid, d.name as dept_name
|
||||
from sys_user u left join sys_users_roles ur on u.user_id = ur.user_id
|
||||
left join sys_role r on r.role_id = ur.role_id
|
||||
left join sys_dept d on d.dept_id = u.dept_id
|
||||
<where>
|
||||
<if test="request.name != null">
|
||||
AND u.name like CONCAT('%', #{request.name},'%')
|
||||
</if>
|
||||
</where>
|
||||
order by u.update_time desc
|
||||
|
||||
<if test="_parameter != null">
|
||||
<include refid="io.dataease.base.mapper.ext.query.GridSql.gridCondition" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
<if test="orderByClause == null">
|
||||
order by u.update_time desc
|
||||
</if>
|
||||
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,259 @@
|
||||
package io.dataease.base.mapper.ext.query;
|
||||
|
||||
import io.dataease.controller.sys.base.ConditionEntity;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GridExample {
|
||||
protected String orderByClause;
|
||||
|
||||
protected boolean distinct;
|
||||
|
||||
protected List<Criteria> oredCriteria;
|
||||
|
||||
public GridExample() {
|
||||
oredCriteria = new ArrayList<Criteria>();
|
||||
}
|
||||
|
||||
public void setOrderByClause(String orderByClause) {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
public String getOrderByClause() {
|
||||
return orderByClause;
|
||||
}
|
||||
|
||||
public void setDistinct(boolean distinct) {
|
||||
this.distinct = distinct;
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return distinct;
|
||||
}
|
||||
|
||||
public List<Criteria> getOredCriteria() {
|
||||
return oredCriteria;
|
||||
}
|
||||
|
||||
public void or(Criteria criteria) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
|
||||
public Criteria or() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
oredCriteria.add(criteria);
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public Criteria createCriteria() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
if (oredCriteria.size() == 0) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected Criteria createCriteriaInternal() {
|
||||
Criteria criteria = new Criteria();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
oredCriteria.clear();
|
||||
orderByClause = null;
|
||||
distinct = false;
|
||||
}
|
||||
|
||||
protected abstract static class GeneratedCriteria {
|
||||
protected List<Criterion> criteria;
|
||||
|
||||
protected GeneratedCriteria() {
|
||||
super();
|
||||
criteria = new ArrayList<Criterion>();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return criteria.size() > 0;
|
||||
}
|
||||
|
||||
public List<Criterion> getAllCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public List<Criterion> getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition) {
|
||||
if (condition == null) {
|
||||
throw new RuntimeException("Value for condition cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value, String property) {
|
||||
if (value == null) {
|
||||
throw new RuntimeException("Value for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value1, Object value2, String property) {
|
||||
if (value1 == null || value2 == null) {
|
||||
throw new RuntimeException("Between values for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value1, value2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Criteria addCondtion(ConditionEntity conditionEntity){
|
||||
String field = conditionEntity.getField();
|
||||
Object value = conditionEntity.getValue();
|
||||
String operator = conditionEntity.getOperator();
|
||||
if (StringUtils.isEmpty(operator))
|
||||
operator = "like";
|
||||
switch (operator){
|
||||
case "eq":
|
||||
addCriterion(field+" = ", value, field);
|
||||
break;
|
||||
case "ne":
|
||||
addCriterion(field+" <> ", value, field);
|
||||
break;
|
||||
case "like":
|
||||
addCriterion(field+" like ", "%"+value+"%", field);
|
||||
break;
|
||||
case "not like":
|
||||
addCriterion(field+" not like ", value, field);
|
||||
break;
|
||||
case "in":
|
||||
List<Object> invalues = (List<Object>)value;
|
||||
addCriterion(field+" in", invalues, field);
|
||||
break;
|
||||
case "not in":
|
||||
List<Object> notinvalues = (List<Object>)value;
|
||||
addCriterion(field+" not in", notinvalues, field);
|
||||
break;
|
||||
case "between":
|
||||
List<Object> values = (List<Object>)value;
|
||||
Object v1 = values.get(0);
|
||||
Object v2 = values.get(1);
|
||||
addCriterion(field+" between", v1, v2, field);
|
||||
break;
|
||||
case "gt":
|
||||
addCriterion(field+" > ", value, field);
|
||||
break;
|
||||
case "ge":
|
||||
addCriterion(field+" >= ", value, field);
|
||||
break;
|
||||
case "lt":
|
||||
addCriterion(field+" < ", value, field);
|
||||
break;
|
||||
case "le":
|
||||
addCriterion(field+" <= ", value, field);
|
||||
break;
|
||||
}
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
||||
protected Criteria() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criterion {
|
||||
private String condition;
|
||||
|
||||
private Object value;
|
||||
|
||||
private Object secondValue;
|
||||
|
||||
private boolean noValue;
|
||||
|
||||
private boolean singleValue;
|
||||
|
||||
private boolean betweenValue;
|
||||
|
||||
private boolean listValue;
|
||||
|
||||
private String typeHandler;
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object getSecondValue() {
|
||||
return secondValue;
|
||||
}
|
||||
|
||||
public boolean isNoValue() {
|
||||
return noValue;
|
||||
}
|
||||
|
||||
public boolean isSingleValue() {
|
||||
return singleValue;
|
||||
}
|
||||
|
||||
public boolean isBetweenValue() {
|
||||
return betweenValue;
|
||||
}
|
||||
|
||||
public boolean isListValue() {
|
||||
return listValue;
|
||||
}
|
||||
|
||||
public String getTypeHandler() {
|
||||
return typeHandler;
|
||||
}
|
||||
|
||||
protected Criterion(String condition) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.typeHandler = null;
|
||||
this.noValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.typeHandler = typeHandler;
|
||||
if (value instanceof List<?>) {
|
||||
this.listValue = true;
|
||||
} else {
|
||||
this.singleValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value) {
|
||||
this(condition, value, null);
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.secondValue = secondValue;
|
||||
this.typeHandler = typeHandler;
|
||||
this.betweenValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue) {
|
||||
this(condition, value, secondValue, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
package io.dataease.base.mapper.ext.query;
|
||||
|
||||
public interface GridSql {
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.dataease.base.mapper.ext.query.GridSql">
|
||||
|
||||
<sql id="gridCondition">
|
||||
<where>
|
||||
<foreach collection="oredCriteria" item="criteria" separator="or">
|
||||
<if test="criteria.valid">
|
||||
<trim prefix="(" prefixOverrides="and" suffix=")">
|
||||
<foreach collection="criteria.criteria" item="criterion">
|
||||
<choose>
|
||||
<when test="criterion.noValue">
|
||||
and ${criterion.condition}
|
||||
</when>
|
||||
<when test="criterion.singleValue">
|
||||
and ${criterion.condition} #{criterion.value}
|
||||
</when>
|
||||
<when test="criterion.betweenValue">
|
||||
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
|
||||
</when>
|
||||
<when test="criterion.listValue">
|
||||
and ${criterion.condition}
|
||||
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
|
||||
#{listItem}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</foreach>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
@ -0,0 +1,6 @@
|
||||
package io.dataease.commons.constants;
|
||||
|
||||
public class DatasetMode {
|
||||
public static final String EXTRACT = "1";
|
||||
public static final String DIRECT = "0";
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package io.dataease.commons.constants;
|
||||
|
||||
public enum JobStatus {
|
||||
Prepare, Underway, Completed, Error
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
package io.dataease.commons.constants;
|
||||
|
||||
public enum TestPlanStatus {
|
||||
Prepare, Underway, Completed
|
||||
}
|
||||
30
backend/src/main/java/io/dataease/config/HbaseConfig.java
Normal file
@ -0,0 +1,30 @@
|
||||
package io.dataease.config;
|
||||
|
||||
import com.fit2cloud.autoconfigure.QuartzAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureBefore(QuartzAutoConfiguration.class)
|
||||
public class HbaseConfig {
|
||||
|
||||
@Resource
|
||||
private Environment env; // 保存了配置文件的信息
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public org.apache.hadoop.conf.Configuration configuration(){
|
||||
org.apache.hadoop.conf.Configuration configuration = new org.apache.hadoop.conf.Configuration();
|
||||
configuration.set("hbase.zookeeper.quorum", env.getProperty("hbase.zookeeper.quorum"));
|
||||
configuration.set("hbase.zookeeper.property.clientPort", env.getProperty("hbase.zookeeper.property.clientPort"));
|
||||
configuration.set("hbase.client.retries.number", env.getProperty("hbase.client.retries.number", "1"));
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ public class DataSetTableFieldController {
|
||||
|
||||
@PostMapping("list/{tableId}")
|
||||
public List<DatasetTableField> list(@PathVariable String tableId) {
|
||||
DatasetTableField datasetTableField = new DatasetTableField();
|
||||
DatasetTableField datasetTableField = DatasetTableField.builder().build();
|
||||
datasetTableField.setTableId(tableId);
|
||||
return dataSetTableFieldsService.list(datasetTableField);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package io.dataease.controller.sys;
|
||||
import io.dataease.base.domain.SysDept;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.controller.ResultHolder;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.DeptCreateRequest;
|
||||
import io.dataease.controller.sys.request.DeptDeleteRequest;
|
||||
import io.dataease.controller.sys.request.DeptStatusRequest;
|
||||
@ -39,6 +40,19 @@ public class SysDeptController extends ResultHolder {
|
||||
return nodeResponses;
|
||||
}
|
||||
|
||||
@PostMapping("/search")
|
||||
public List<DeptNodeResponse> search(@RequestBody BaseGridRequest request){
|
||||
List<SysDept> nodes = deptService.nodesTreeByCondition(request);
|
||||
//List<SysDept> nodes = deptService.nodesByPid(pid);
|
||||
List<DeptNodeResponse> nodeResponses = nodes.stream().map(node -> {
|
||||
DeptNodeResponse deptNodeResponse = BeanUtils.copyBean(new DeptNodeResponse(), node);
|
||||
deptNodeResponse.setHasChildren(node.getSubCount() > 0);
|
||||
deptNodeResponse.setTop(node.getPid() == deptService.DEPT_ROOT_PID);
|
||||
return deptNodeResponse;
|
||||
}).collect(Collectors.toList());
|
||||
return nodeResponses;
|
||||
}
|
||||
|
||||
@ApiOperation("查询部门")
|
||||
@PostMapping("/root")
|
||||
public ResultHolder rootData(){
|
||||
|
||||
@ -6,6 +6,7 @@ import com.github.pagehelper.PageHelper;
|
||||
import io.dataease.base.domain.SysRole;
|
||||
import io.dataease.commons.utils.PageUtils;
|
||||
import io.dataease.commons.utils.Pager;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.RoleGridRequest;
|
||||
import io.dataease.controller.sys.request.RoleMenusRequest;
|
||||
import io.dataease.controller.sys.response.RoleUserItem;
|
||||
@ -49,7 +50,7 @@ public class SysRoleController {
|
||||
|
||||
@ApiOperation("查询角色")
|
||||
@PostMapping("/roleGrid/{goPage}/{pageSize}")
|
||||
public Pager<List<SysRole>> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody RoleGridRequest request) {
|
||||
public Pager<List<SysRole>> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
Pager<List<SysRole>> listPager = PageUtils.setPageInfo(page, sysRoleService.query(request));
|
||||
return listPager;
|
||||
|
||||
@ -5,6 +5,7 @@ import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.dataease.commons.utils.PageUtils;
|
||||
import io.dataease.commons.utils.Pager;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.SysUserCreateRequest;
|
||||
import io.dataease.controller.sys.request.SysUserPwdRequest;
|
||||
import io.dataease.controller.sys.request.SysUserStateRequest;
|
||||
@ -27,10 +28,14 @@ public class SysUserController {
|
||||
|
||||
@ApiOperation("查询用户")
|
||||
@PostMapping("/userGrid/{goPage}/{pageSize}")
|
||||
public Pager<List<SysUserGridResponse>> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody UserGridRequest request) {
|
||||
public Pager<List<SysUserGridResponse>> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, sysUserService.query(request));
|
||||
}
|
||||
/*public Pager<List<SysUserGridResponse>> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody UserGridRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, sysUserService.query(request));
|
||||
}*/
|
||||
|
||||
@ApiOperation("创建用户")
|
||||
@PostMapping("/create")
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package io.dataease.controller.sys.base;
|
||||
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class BaseGridRequest implements Serializable {
|
||||
|
||||
private List<ConditionEntity> conditions;
|
||||
|
||||
public GridExample convertExample(){
|
||||
GridExample gridExample = new GridExample();
|
||||
if (CollectionUtils.isEmpty(conditions))return gridExample;
|
||||
|
||||
GridExample.Criteria criteria = gridExample.createCriteria();
|
||||
conditions.forEach(criteria::addCondtion);
|
||||
return gridExample;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package io.dataease.controller.sys.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ConditionEntity implements Serializable {
|
||||
|
||||
private String field;
|
||||
|
||||
private String operator;
|
||||
|
||||
private Object value;
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package io.dataease.controller.sys.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SimpleTreeNode {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long pid;
|
||||
}
|
||||
@ -1,10 +1,18 @@
|
||||
package io.dataease.controller.sys.request;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class UserGridRequest implements Serializable {
|
||||
@ApiModelProperty("快速检索")
|
||||
private String quick;
|
||||
@ApiModelProperty("名称")
|
||||
private String name;
|
||||
@ApiModelProperty("组织")
|
||||
private String deptId;
|
||||
@ApiModelProperty("状态")
|
||||
private String enabled;
|
||||
}
|
||||
|
||||
@ -23,4 +23,8 @@ public abstract class DatasourceProvider {
|
||||
getData(datasourceRequest);
|
||||
}
|
||||
|
||||
abstract public Long count(DatasourceRequest datasourceRequest)throws Exception;
|
||||
|
||||
abstract public List<String[]> getPageData(DatasourceRequest datasourceRequest) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import io.dataease.datasource.request.DatasourceRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.sql.*;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
@Service("jdbc")
|
||||
@ -23,23 +24,7 @@ public class JdbcProvider extends DatasourceProvider{
|
||||
Statement stat = connection.createStatement();
|
||||
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery())
|
||||
) {
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
while (rs.next()) {
|
||||
String[] row = new String[columnCount];
|
||||
for (int j = 0; j < columnCount; j++) {
|
||||
int columType = metaData.getColumnType(j + 1);
|
||||
switch (columType) {
|
||||
case java.sql.Types.DATE:
|
||||
row[j] = rs.getDate(j + 1).toString();
|
||||
break;
|
||||
default:
|
||||
row[j] = rs.getString(j + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list.add(row);
|
||||
}
|
||||
list = fetchResult(rs);
|
||||
} catch (SQLException e){
|
||||
throw new Exception("ERROR:" + e.getMessage(), e);
|
||||
}catch (Exception e) {
|
||||
@ -48,6 +33,46 @@ public class JdbcProvider extends DatasourceProvider{
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String[]> getPageData(DatasourceRequest datasourceRequest) throws Exception {
|
||||
List<String[]> list = new LinkedList<>();
|
||||
try (
|
||||
Connection connection = getConnection(datasourceRequest);
|
||||
Statement stat = connection.createStatement();
|
||||
ResultSet rs = stat.executeQuery(datasourceRequest.getQuery() + MessageFormat.format(" LIMIT {0}, {1}", (datasourceRequest.getStartPage() -1)*datasourceRequest.getPageSize(), datasourceRequest.getPageSize()))
|
||||
) {
|
||||
list = fetchResult(rs);
|
||||
} catch (SQLException e){
|
||||
throw new Exception("ERROR:" + e.getMessage(), e);
|
||||
}catch (Exception e) {
|
||||
throw new Exception("ERROR:" + e.getMessage(), e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
private List<String[]> fetchResult( ResultSet rs) throws Exception{
|
||||
List<String[]> list = new LinkedList<>();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
while (rs.next()) {
|
||||
String[] row = new String[columnCount];
|
||||
for (int j = 0; j < columnCount; j++) {
|
||||
int columType = metaData.getColumnType(j + 1);
|
||||
switch (columType) {
|
||||
case java.sql.Types.DATE:
|
||||
row[j] = rs.getDate(j + 1).toString();
|
||||
break;
|
||||
default:
|
||||
row[j] = rs.getString(j + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list.add(row);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTables(DatasourceRequest datasourceRequest) throws Exception {
|
||||
List<String> tables = new ArrayList<>();
|
||||
@ -106,6 +131,19 @@ public class JdbcProvider extends DatasourceProvider{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Long count(DatasourceRequest datasourceRequest)throws Exception{
|
||||
try (Connection con = getConnection(datasourceRequest); Statement ps = con.createStatement()) {
|
||||
ResultSet resultSet = ps.executeQuery(datasourceRequest.getQuery());
|
||||
while (resultSet.next()) {
|
||||
return resultSet.getLong(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception("ERROR: " + e.getMessage(), e);
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private Connection getConnection(DatasourceRequest datasourceRequest) throws Exception {
|
||||
String username = null;
|
||||
String password = null;
|
||||
|
||||
@ -11,5 +11,8 @@ public class DatasourceRequest {
|
||||
protected String query;
|
||||
protected String table;
|
||||
protected Datasource datasource;
|
||||
private Long pageSize;
|
||||
private Long startPage;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package io.dataease.dto.chart;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author gin
|
||||
* @Date 2021/3/11 1:18 下午
|
||||
*/
|
||||
@Data
|
||||
public class ChartViewFieldDTO {
|
||||
private String id;
|
||||
|
||||
private String tableId;
|
||||
|
||||
private String originName;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private Boolean checked;
|
||||
|
||||
private Integer columnIndex;
|
||||
|
||||
private Long lastSyncTime;
|
||||
|
||||
private Integer deType;
|
||||
|
||||
private String summary;
|
||||
}
|
||||
@ -1,22 +1,25 @@
|
||||
package io.dataease.job.sechedule;
|
||||
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import org.quartz.*;
|
||||
|
||||
public abstract class DeScheduleJob implements Job {
|
||||
|
||||
protected String datasetTableId;
|
||||
protected String expression;
|
||||
protected String taskId;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
JobKey jobKey = context.getTrigger().getJobKey();
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
this.datasetTableId = jobDataMap.getString("datasetTableId");
|
||||
this.expression = jobDataMap.getString("expression");
|
||||
this.taskId = jobDataMap.getString("taskId");
|
||||
|
||||
// JobKey jobKey = context.getTrigger().getJobKey();
|
||||
// JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
// this.resourceId = jobDataMap.getString("resourceId");
|
||||
// this.userId = jobDataMap.getString("userId");
|
||||
// this.expression = jobDataMap.getString("expression");
|
||||
//
|
||||
// LogUtil.info(jobKey.getGroup() + " Running: " + resourceId);
|
||||
// LogUtil.info("CronExpression: " + expression);
|
||||
LogUtil.info(jobKey.getGroup() + " Running: " + datasetTableId);
|
||||
LogUtil.info(jobKey.getName() + " Running: " + datasetTableId);
|
||||
LogUtil.info("CronExpression: " + expression);
|
||||
businessExecute(context);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package io.dataease.job.sechedule;
|
||||
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.service.dataset.ExtractDataService;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ExtractDataJob extends DeScheduleJob{
|
||||
private ExtractDataService extractDataService;
|
||||
|
||||
public ExtractDataJob() {
|
||||
extractDataService = (ExtractDataService) CommonBeanFactory.getBean(ExtractDataService.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void businessExecute(JobExecutionContext context) {
|
||||
extractDataService.extractData(datasetTableId, taskId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -369,11 +369,11 @@ public class ScheduleManager {
|
||||
addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, startTime, endTime, null);
|
||||
}
|
||||
|
||||
public JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) {
|
||||
public JobDataMap getDefaultJobDataMap(String resourceId, String expression, String taskId) {
|
||||
JobDataMap jobDataMap = new JobDataMap();
|
||||
jobDataMap.put("resourceId", resourceId);
|
||||
jobDataMap.put("datasetTableId", resourceId);
|
||||
jobDataMap.put("taskId", taskId);
|
||||
jobDataMap.put("expression", expression);
|
||||
jobDataMap.put("userId", userId);
|
||||
return jobDataMap;
|
||||
}
|
||||
|
||||
|
||||
@ -20,13 +20,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
|
||||
System.out.println("================= 应用启动 =================");
|
||||
/* cron schedule */
|
||||
// scheduleManager.addCronJob(new JobKey("abc", "def"), new TriggerKey("abc", "def"), TestJob.class, "*/10 * * * * ?");
|
||||
/* single schedule*/
|
||||
// long timestamp = System.currentTimeMillis() + 90 * 1000;
|
||||
// Date date = new Date(timestamp);
|
||||
// scheduleManager.addSingleJob(new JobKey("abc", "def"), new TriggerKey("abc", "def"), TestJob.class, date);
|
||||
System.out.println("================= Application start =================");
|
||||
// 项目启动,从数据库读取任务加入到Quartz
|
||||
List<DatasetTableTask> list = dataSetTableTaskService.list(new DatasetTableTask());
|
||||
for (DatasetTableTask task : list) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package io.dataease.service;
|
||||
|
||||
import io.dataease.base.domain.DatasetTableTask;
|
||||
import io.dataease.job.sechedule.ExtractDataJob;
|
||||
import io.dataease.job.sechedule.ScheduleManager;
|
||||
import io.dataease.job.sechedule.TestJob;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerKey;
|
||||
@ -24,8 +24,8 @@ public class ScheduleService {
|
||||
if (StringUtils.equalsIgnoreCase(datasetTableTask.getRate(), "0")) {
|
||||
scheduleManager.addOrUpdateSingleJob(new JobKey(datasetTableTask.getId(), datasetTableTask.getTableId()),
|
||||
new TriggerKey(datasetTableTask.getId(), datasetTableTask.getTableId()),
|
||||
TestJob.class,//TODO
|
||||
new Date(datasetTableTask.getStartTime()));
|
||||
ExtractDataJob.class,
|
||||
new Date(datasetTableTask.getStartTime()), scheduleManager.getDefaultJobDataMap(datasetTableTask.getTableId(), datasetTableTask.getCron(), datasetTableTask.getId()));
|
||||
} else if (StringUtils.equalsIgnoreCase(datasetTableTask.getRate(), "1")) {
|
||||
Date endTime;
|
||||
if (datasetTableTask.getEndTime() == null || datasetTableTask.getEndTime() == 0) {
|
||||
@ -36,8 +36,9 @@ public class ScheduleService {
|
||||
|
||||
scheduleManager.addOrUpdateCronJob(new JobKey(datasetTableTask.getId(), datasetTableTask.getTableId()),
|
||||
new TriggerKey(datasetTableTask.getId(), datasetTableTask.getTableId()),
|
||||
TestJob.class,// TODO
|
||||
datasetTableTask.getCron(), new Date(datasetTableTask.getStartTime()), endTime);
|
||||
ExtractDataJob.class,
|
||||
datasetTableTask.getCron(), new Date(datasetTableTask.getStartTime()), endTime,
|
||||
scheduleManager.getDefaultJobDataMap(datasetTableTask.getTableId(), datasetTableTask.getCron(), datasetTableTask.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import io.dataease.datasource.provider.ProviderFactory;
|
||||
import io.dataease.datasource.request.DatasourceRequest;
|
||||
import io.dataease.datasource.service.DatasourceService;
|
||||
import io.dataease.dto.chart.ChartViewDTO;
|
||||
import io.dataease.dto.chart.ChartViewFieldDTO;
|
||||
import io.dataease.dto.chart.Series;
|
||||
import io.dataease.dto.dataset.DataTableInfoDTO;
|
||||
import io.dataease.service.dataset.DataSetTableFieldsService;
|
||||
@ -76,9 +77,9 @@ public class ChartViewService {
|
||||
|
||||
public ChartViewDTO getData(String id) throws Exception {
|
||||
ChartViewWithBLOBs view = chartViewMapper.selectByPrimaryKey(id);
|
||||
List<DatasetTableField> xAxis = new Gson().fromJson(view.getXAxis(), new TypeToken<List<DatasetTableField>>() {
|
||||
List<ChartViewFieldDTO> xAxis = new Gson().fromJson(view.getXAxis(), new TypeToken<List<ChartViewFieldDTO>>() {
|
||||
}.getType());
|
||||
List<DatasetTableField> yAxis = new Gson().fromJson(view.getYAxis(), new TypeToken<List<DatasetTableField>>() {
|
||||
List<ChartViewFieldDTO> yAxis = new Gson().fromJson(view.getYAxis(), new TypeToken<List<ChartViewFieldDTO>>() {
|
||||
}.getType());
|
||||
|
||||
List<String> x = new ArrayList<>();
|
||||
@ -88,25 +89,25 @@ public class ChartViewService {
|
||||
BeanUtils.copyBean(dto, view);
|
||||
return dto;
|
||||
}
|
||||
List<String> xIds = xAxis.stream().map(DatasetTableField::getId).collect(Collectors.toList());
|
||||
List<String> yIds = yAxis.stream().map(DatasetTableField::getId).collect(Collectors.toList());
|
||||
List<DatasetTableField> xList = dataSetTableFieldsService.getListByIds(xIds);
|
||||
List<DatasetTableField> yList = dataSetTableFieldsService.getListByIds(yIds);
|
||||
// List<String> xIds = xAxis.stream().map(DatasetTableField::getId).collect(Collectors.toList());
|
||||
// List<String> yIds = yAxis.stream().map(DatasetTableField::getId).collect(Collectors.toList());
|
||||
// List<DatasetTableField> xList = dataSetTableFieldsService.getListByIds(xIds);
|
||||
// List<DatasetTableField> yList = dataSetTableFieldsService.getListByIds(yIds);
|
||||
|
||||
// 获取数据源
|
||||
// 获取数据集
|
||||
DatasetTable table = dataSetTableService.get(view.getTableId());
|
||||
// todo 判断连接方式,直连或者定时抽取 table.mode
|
||||
Datasource ds = datasourceService.get(table.getDataSourceId());
|
||||
|
||||
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(ds.getType());
|
||||
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||
datasourceRequest.setDatasource(ds);
|
||||
DataTableInfoDTO dataTableInfoDTO = new Gson().fromJson(table.getInfo(), DataTableInfoDTO.class);
|
||||
datasourceRequest.setTable(dataTableInfoDTO.getTable());
|
||||
datasourceRequest.setQuery(getSQL(ds.getType(), dataTableInfoDTO.getTable(), xList, yList));
|
||||
datasourceRequest.setQuery(getSQL(ds.getType(), dataTableInfoDTO.getTable(), xAxis, yAxis));
|
||||
List<String[]> data = datasourceProvider.getData(datasourceRequest);
|
||||
|
||||
// todo 处理结果,目前做一个单系列图表,后期图表组件再扩展
|
||||
for (DatasetTableField y : yList) {
|
||||
for (ChartViewFieldDTO y : yAxis) {
|
||||
Series series1 = new Series();
|
||||
series1.setName(y.getName());
|
||||
series1.setType(view.getType());
|
||||
@ -116,16 +117,16 @@ public class ChartViewService {
|
||||
for (String[] d : data) {
|
||||
StringBuilder a = new StringBuilder();
|
||||
BigDecimal b = new BigDecimal("0");
|
||||
for (int i = 0; i < xList.size(); i++) {
|
||||
if (i == xList.size() - 1) {
|
||||
for (int i = 0; i < xAxis.size(); i++) {
|
||||
if (i == xAxis.size() - 1) {
|
||||
a.append(d[i]);
|
||||
} else {
|
||||
a.append(d[i]).append("\n");
|
||||
}
|
||||
}
|
||||
x.add(a.toString());
|
||||
for (int i = xList.size(); i < xList.size() + yList.size(); i++) {
|
||||
int j = i - xList.size();
|
||||
for (int i = xAxis.size(); i < xAxis.size() + yAxis.size(); i++) {
|
||||
int j = i - xAxis.size();
|
||||
series.get(j).getData().add(new BigDecimal(d[i]));
|
||||
}
|
||||
}
|
||||
@ -139,7 +140,7 @@ public class ChartViewService {
|
||||
return dto;
|
||||
}
|
||||
|
||||
public String getSQL(String type, String table, List<DatasetTableField> xAxis, List<DatasetTableField> yAxis) {
|
||||
public String getSQL(String type, String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis) {
|
||||
DatasourceTypes datasourceType = DatasourceTypes.valueOf(type);
|
||||
switch (datasourceType) {
|
||||
case mysql:
|
||||
@ -150,10 +151,10 @@ public class ChartViewService {
|
||||
}
|
||||
}
|
||||
|
||||
public String transMysqlSQL(String table, List<DatasetTableField> xAxis, List<DatasetTableField> yAxis) {
|
||||
// TODO 此处sum后期由用户前端传入
|
||||
String[] field = yAxis.stream().map(y -> "sum(" + y.getOriginName() + ")").toArray(String[]::new);
|
||||
String[] group = xAxis.stream().map(DatasetTableField::getOriginName).toArray(String[]::new);
|
||||
public String transMysqlSQL(String table, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis) {
|
||||
// TODO 字段汇总 排序等
|
||||
String[] field = yAxis.stream().map(y -> "CAST(" + y.getSummary() + "(" + y.getOriginName() + ") AS DECIMAL(20,2))").toArray(String[]::new);
|
||||
String[] group = xAxis.stream().map(ChartViewFieldDTO::getOriginName).toArray(String[]::new);
|
||||
return MessageFormat.format("SELECT {0},{1} FROM {2} GROUP BY {3}", StringUtils.join(group, ","), StringUtils.join(field, ","), table, StringUtils.join(group, ","));
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ public class DataSetTableService {
|
||||
private DatasourceMapper datasourceMapper;
|
||||
@Resource
|
||||
private DataSetTableFieldsService dataSetTableFieldsService;
|
||||
@Resource
|
||||
private DataSetTableTaskService dataSetTableTaskService;
|
||||
|
||||
public void batchInsert(List<DatasetTable> datasetTable) throws Exception {
|
||||
for (DatasetTable table : datasetTable) {
|
||||
@ -67,11 +69,15 @@ public class DataSetTableService {
|
||||
public void delete(String id) {
|
||||
datasetTableMapper.deleteByPrimaryKey(id);
|
||||
dataSetTableFieldsService.deleteByTableId(id);
|
||||
// 删除同步任务
|
||||
dataSetTableTaskService.deleteByTableId(id);
|
||||
}
|
||||
|
||||
public List<DatasetTable> list(DataSetTableRequest dataSetTableRequest) {
|
||||
DatasetTableExample datasetTableExample = new DatasetTableExample();
|
||||
datasetTableExample.createCriteria().andSceneIdEqualTo(dataSetTableRequest.getSceneId());
|
||||
if (StringUtils.isNotEmpty(dataSetTableRequest.getSceneId())) {
|
||||
datasetTableExample.createCriteria().andSceneIdEqualTo(dataSetTableRequest.getSceneId());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(dataSetTableRequest.getSort())) {
|
||||
datasetTableExample.setOrderByClause(dataSetTableRequest.getSort());
|
||||
}
|
||||
@ -92,7 +98,7 @@ public class DataSetTableService {
|
||||
}
|
||||
|
||||
public Map<String, List<DatasetTableField>> getFieldsFromDE(DataSetTableRequest dataSetTableRequest) throws Exception {
|
||||
DatasetTableField datasetTableField = new DatasetTableField();
|
||||
DatasetTableField datasetTableField = DatasetTableField.builder().build();
|
||||
datasetTableField.setTableId(dataSetTableRequest.getId());
|
||||
datasetTableField.setChecked(Boolean.TRUE);
|
||||
List<DatasetTableField> fields = dataSetTableFieldsService.list(datasetTableField);
|
||||
@ -121,7 +127,7 @@ public class DataSetTableService {
|
||||
datasourceRequest.setDatasource(ds);
|
||||
String table = new Gson().fromJson(dataSetTableRequest.getInfo(), DataTableInfoDTO.class).getTable();
|
||||
|
||||
DatasetTableField datasetTableField = new DatasetTableField();
|
||||
DatasetTableField datasetTableField = DatasetTableField.builder().build();
|
||||
datasetTableField.setTableId(dataSetTableRequest.getId());
|
||||
datasetTableField.setChecked(Boolean.TRUE);
|
||||
List<DatasetTableField> fields = dataSetTableFieldsService.list(datasetTableField);
|
||||
@ -137,15 +143,13 @@ public class DataSetTableService {
|
||||
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||
datasourceRequest.setDatasource(ds);
|
||||
String table = new Gson().fromJson(dataSetTableRequest.getInfo(), DataTableInfoDTO.class).getTable();
|
||||
// datasourceRequest.setTable(table);
|
||||
|
||||
DatasetTableField datasetTableField = new DatasetTableField();
|
||||
DatasetTableField datasetTableField = DatasetTableField.builder().build();
|
||||
datasetTableField.setTableId(dataSetTableRequest.getId());
|
||||
datasetTableField.setChecked(Boolean.TRUE);
|
||||
List<DatasetTableField> fields = dataSetTableFieldsService.list(datasetTableField);
|
||||
|
||||
String[] fieldArray = fields.stream().map(DatasetTableField::getOriginName).toArray(String[]::new);
|
||||
// datasourceRequest.setQuery("SELECT " + StringUtils.join(fieldArray, ",") + " FROM " + table + " LIMIT 0,10;");
|
||||
datasourceRequest.setQuery(createQuerySQL(ds.getType(), table, fieldArray) + " LIMIT 0,10");
|
||||
|
||||
List<String[]> data = new ArrayList<>();
|
||||
@ -154,17 +158,6 @@ public class DataSetTableService {
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
|
||||
/*JSONArray jsonArray = new JSONArray();
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
data.forEach(ele -> {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for (int i = 0; i < ele.length; i++) {
|
||||
jsonObject.put(fieldArray[i], ele[i]);
|
||||
}
|
||||
jsonArray.add(jsonObject);
|
||||
});
|
||||
}*/
|
||||
List<Map<String, Object>> jsonArray = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
jsonArray = data.stream().map(ele -> {
|
||||
@ -184,6 +177,53 @@ public class DataSetTableService {
|
||||
return map;
|
||||
}
|
||||
|
||||
public List<String[]> getDataSetData(String datasourceId, String table, List<DatasetTableField> fields) {
|
||||
List<String[]> data = new ArrayList<>();
|
||||
Datasource ds = datasourceMapper.selectByPrimaryKey(datasourceId);
|
||||
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(ds.getType());
|
||||
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||
datasourceRequest.setDatasource(ds);
|
||||
String[] fieldArray = fields.stream().map(DatasetTableField::getOriginName).toArray(String[]::new);
|
||||
datasourceRequest.setQuery(createQuerySQL(ds.getType(), table, fieldArray) + " LIMIT 0, 10");
|
||||
try {
|
||||
data.addAll(datasourceProvider.getData(datasourceRequest));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public Long getDataSetTotalData(String datasourceId, String table) {
|
||||
List<String[]> data = new ArrayList<>();
|
||||
Datasource ds = datasourceMapper.selectByPrimaryKey(datasourceId);
|
||||
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(ds.getType());
|
||||
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||
datasourceRequest.setDatasource(ds);
|
||||
datasourceRequest.setQuery("select count(*) from " + table);
|
||||
try {
|
||||
return datasourceProvider.count(datasourceRequest);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
return 0l;
|
||||
}
|
||||
|
||||
public List<String[]> getDataSetPageData(String datasourceId, String table, List<DatasetTableField> fields, Long startPage, Long pageSize) {
|
||||
List<String[]> data = new ArrayList<>();
|
||||
Datasource ds = datasourceMapper.selectByPrimaryKey(datasourceId);
|
||||
DatasourceProvider datasourceProvider = ProviderFactory.getProvider(ds.getType());
|
||||
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||
datasourceRequest.setDatasource(ds);
|
||||
String[] fieldArray = fields.stream().map(DatasetTableField::getOriginName).toArray(String[]::new);
|
||||
datasourceRequest.setPageSize(pageSize);
|
||||
datasourceRequest.setStartPage(startPage);
|
||||
datasourceRequest.setQuery(createQuerySQL(ds.getType(), table, fieldArray));
|
||||
try {
|
||||
return datasourceProvider.getData(datasourceRequest);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public void saveTableField(DatasetTable datasetTable) throws Exception {
|
||||
Datasource ds = datasourceMapper.selectByPrimaryKey(datasetTable.getDataSourceId());
|
||||
DataSetTableRequest dataSetTableRequest = new DataSetTableRequest();
|
||||
@ -193,7 +233,7 @@ public class DataSetTableService {
|
||||
if (CollectionUtils.isNotEmpty(fields)) {
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
TableFiled filed = fields.get(i);
|
||||
DatasetTableField datasetTableField = new DatasetTableField();
|
||||
DatasetTableField datasetTableField = DatasetTableField.builder().build();
|
||||
datasetTableField.setTableId(datasetTable.getId());
|
||||
datasetTableField.setOriginName(filed.getFieldName());
|
||||
datasetTableField.setName(filed.getRemarks());
|
||||
|
||||
@ -48,4 +48,11 @@ public class DataSetTableTaskLogService {
|
||||
return extDataSetTaskMapper.list(request);
|
||||
}
|
||||
|
||||
public void deleteByTaskId(String taskId){
|
||||
DatasetTableTaskLogExample datasetTableTaskLogExample = new DatasetTableTaskLogExample();
|
||||
DatasetTableTaskLogExample.Criteria criteria = datasetTableTaskLogExample.createCriteria();
|
||||
criteria.andTaskIdEqualTo(taskId);
|
||||
datasetTableTaskLogMapper.deleteByExample(datasetTableTaskLogExample);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import io.dataease.service.ScheduleService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.CronExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
@ -17,10 +18,12 @@ import java.util.UUID;
|
||||
* @Date 2021/3/4 1:26 下午
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class DataSetTableTaskService {
|
||||
@Resource
|
||||
private DatasetTableTaskMapper datasetTableTaskMapper;
|
||||
|
||||
@Resource
|
||||
private DataSetTableTaskLogService dataSetTableTaskLogService;
|
||||
@Resource
|
||||
private ScheduleService scheduleService;
|
||||
|
||||
@ -46,6 +49,25 @@ public class DataSetTableTaskService {
|
||||
DatasetTableTask datasetTableTask = datasetTableTaskMapper.selectByPrimaryKey(id);
|
||||
datasetTableTaskMapper.deleteByPrimaryKey(id);
|
||||
scheduleService.deleteSchedule(datasetTableTask);
|
||||
dataSetTableTaskLogService.deleteByTaskId(id);
|
||||
}
|
||||
|
||||
public void delete(DatasetTableTask task) {
|
||||
datasetTableTaskMapper.deleteByPrimaryKey(task.getId());
|
||||
scheduleService.deleteSchedule(task);
|
||||
dataSetTableTaskLogService.deleteByTaskId(task.getId());
|
||||
}
|
||||
|
||||
public void deleteByTableId(String id) {
|
||||
DatasetTableTaskExample datasetTableTaskExample = new DatasetTableTaskExample();
|
||||
DatasetTableTaskExample.Criteria criteria = datasetTableTaskExample.createCriteria();
|
||||
criteria.andTableIdEqualTo(id);
|
||||
List<DatasetTableTask> datasetTableTasks = datasetTableTaskMapper.selectByExample(datasetTableTaskExample);
|
||||
datasetTableTasks.forEach(this::delete);
|
||||
}
|
||||
|
||||
public DatasetTableTask get(String id) {
|
||||
return datasetTableTaskMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
||||
public List<DatasetTableTask> list(DatasetTableTask datasetTableTask) {
|
||||
|
||||
@ -0,0 +1,93 @@
|
||||
package io.dataease.service.dataset;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.dataease.base.domain.DatasetTable;
|
||||
import io.dataease.base.domain.DatasetTableField;
|
||||
import io.dataease.base.domain.DatasetTableTaskLog;
|
||||
import io.dataease.commons.constants.JobStatus;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.dto.dataset.DataTableInfoDTO;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.client.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Service
|
||||
public class ExtractDataService {
|
||||
|
||||
@Resource
|
||||
private DataSetTableService dataSetTableService;
|
||||
@Resource
|
||||
private DataSetTableFieldsService dataSetTableFieldsService;
|
||||
@Resource
|
||||
private DataSetTableTaskLogService dataSetTableTaskLogService;
|
||||
private Long pageSize = 10000l;
|
||||
private static ExecutorService pool = Executors.newScheduledThreadPool(50); //设置连接池
|
||||
private Connection connection;
|
||||
|
||||
public void extractData(String datasetTableId, String taskId) {
|
||||
DatasetTableTaskLog datasetTableTaskLog = new DatasetTableTaskLog();
|
||||
try {
|
||||
datasetTableTaskLog.setTableId(datasetTableId);
|
||||
datasetTableTaskLog.setTaskId(taskId);
|
||||
datasetTableTaskLog.setStatus(JobStatus.Underway.name());
|
||||
datasetTableTaskLog.setStartTime(System.currentTimeMillis());
|
||||
dataSetTableTaskLogService.save(datasetTableTaskLog);
|
||||
Admin admin = getConnection().getAdmin();
|
||||
DatasetTable datasetTable = dataSetTableService.get(datasetTableId);
|
||||
List<DatasetTableField> datasetTableFields = dataSetTableFieldsService.list(DatasetTableField.builder().tableId(datasetTable.getId()).build());
|
||||
String table = new Gson().fromJson(datasetTable.getInfo(), DataTableInfoDTO.class).getTable();
|
||||
TableName tableName = TableName.valueOf(table + "-" + datasetTable.getDataSourceId());
|
||||
if(!admin.tableExists(tableName)){
|
||||
TableDescriptorBuilder descBuilder = TableDescriptorBuilder.newBuilder(tableName);
|
||||
ColumnFamilyDescriptor hcd = ColumnFamilyDescriptorBuilder.of("cf");
|
||||
descBuilder.setColumnFamily(hcd);
|
||||
TableDescriptor desc = descBuilder.build();
|
||||
admin.createTable(desc);
|
||||
}
|
||||
admin.disableTable(tableName);
|
||||
admin.truncateTable(tableName, true);
|
||||
|
||||
Table tab = getConnection().getTable(tableName);
|
||||
Long total = dataSetTableService.getDataSetTotalData(datasetTable.getDataSourceId(), table);
|
||||
Long pageCount = total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1;
|
||||
|
||||
for (Long pageIndex = 1l; pageIndex <= pageCount; pageIndex++) {
|
||||
List<String[]> data = dataSetTableService.getDataSetPageData(datasetTable.getDataSourceId(), table, datasetTableFields, pageIndex, pageSize);
|
||||
for (String[] d : data) {
|
||||
for(int i=0;i<datasetTableFields.size();i++){
|
||||
Put put = new Put(UUID.randomUUID().toString().getBytes());
|
||||
String value = d[i];
|
||||
if(value == null){
|
||||
value = "null";
|
||||
}
|
||||
put.addColumn("cf".getBytes(), datasetTableFields.get(i).getOriginName().getBytes(), value.getBytes());
|
||||
tab.put(put);
|
||||
}
|
||||
}
|
||||
}
|
||||
datasetTableTaskLog.setStatus(JobStatus.Completed.name());
|
||||
datasetTableTaskLog.setEndTime(System.currentTimeMillis());
|
||||
dataSetTableTaskLogService.save(datasetTableTaskLog);
|
||||
}catch (Exception e){
|
||||
datasetTableTaskLog.setStatus(JobStatus.Error.name());
|
||||
datasetTableTaskLog.setEndTime(System.currentTimeMillis());
|
||||
dataSetTableTaskLogService.save(datasetTableTaskLog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private synchronized Connection getConnection() throws Exception{
|
||||
if(connection == null || connection.isClosed()){
|
||||
Configuration cfg = CommonBeanFactory.getBean(Configuration.class);
|
||||
connection = ConnectionFactory.createConnection(cfg, pool);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@ -4,16 +4,20 @@ import io.dataease.base.domain.SysDept;
|
||||
import io.dataease.base.domain.SysDeptExample;
|
||||
import io.dataease.base.mapper.SysDeptMapper;
|
||||
import io.dataease.base.mapper.ext.ExtDeptMapper;
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.DeptCreateRequest;
|
||||
import io.dataease.controller.sys.request.DeptDeleteRequest;
|
||||
import io.dataease.controller.sys.request.DeptStatusRequest;
|
||||
import io.dataease.controller.sys.request.SimpleTreeNode;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@ -23,11 +27,11 @@ public class DeptService {
|
||||
private final static Integer DEFAULT_SUBCOUNT = 0;
|
||||
public final static Long DEPT_ROOT_PID = 0L;
|
||||
|
||||
@Resource
|
||||
@Autowired(required = false)
|
||||
private SysDeptMapper sysDeptMapper;
|
||||
|
||||
|
||||
@Resource
|
||||
@Autowired(required = false)
|
||||
private ExtDeptMapper extDeptMapper;
|
||||
|
||||
public List<SysDept> nodesByPid(Long pid){
|
||||
@ -120,4 +124,59 @@ public class DeptService {
|
||||
return sysDeptMapper.updateByPrimaryKeySelective(sysDept);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<SysDept> nodesTreeByCondition(BaseGridRequest request){
|
||||
//DeptService proxy = proxy();
|
||||
List<SimpleTreeNode> allNodes = allNodes();
|
||||
List<SimpleTreeNode> targetNodes = nodeByCondition(request);
|
||||
List<Long> ids = upTree(allNodes, targetNodes);
|
||||
SysDeptExample example = new SysDeptExample();
|
||||
SysDeptExample.Criteria criteria = example.createCriteria();
|
||||
criteria.andDeptIdIn(ids);
|
||||
example.setOrderByClause("dept_sort");
|
||||
List<SysDept> sysDepts = sysDeptMapper.selectByExample(example);
|
||||
return sysDepts;
|
||||
}
|
||||
|
||||
private DeptService proxy(){
|
||||
return CommonBeanFactory.getBean(DeptService.class);
|
||||
}
|
||||
|
||||
|
||||
private List<SimpleTreeNode> allNodes(){
|
||||
List<SimpleTreeNode> simpleTreeNodes = extDeptMapper.allNodes();
|
||||
return simpleTreeNodes;
|
||||
}
|
||||
|
||||
private List<SimpleTreeNode> nodeByCondition(BaseGridRequest request){
|
||||
GridExample gridExample = request.convertExample();
|
||||
List<SimpleTreeNode> simpleTreeNodes = extDeptMapper.nodesByExample(gridExample);
|
||||
return simpleTreeNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 找出目标节点所在路径上的所有节点 向上找
|
||||
* @param allNodes 所有节点
|
||||
* @param targetNodes 目标节点
|
||||
* @return
|
||||
*/
|
||||
private List<Long> upTree(List<SimpleTreeNode> allNodes, List<SimpleTreeNode> targetNodes){
|
||||
final Map<Long, SimpleTreeNode> map = allNodes.stream().collect(Collectors.toMap(SimpleTreeNode::getId, node -> node));
|
||||
List<Long> results = targetNodes.parallelStream().flatMap(targetNode -> {
|
||||
//向上逐级找爹
|
||||
List<Long> ids = new ArrayList<>();
|
||||
SimpleTreeNode node = targetNode;
|
||||
while (node != null) {
|
||||
ids.add(node.getId());
|
||||
Long pid = node.getPid();
|
||||
node = map.get(pid);
|
||||
}
|
||||
return ids.stream();
|
||||
}).distinct().collect(Collectors.toList());
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import io.dataease.base.domain.SysUsersRolesExample;
|
||||
import io.dataease.base.mapper.SysRoleMapper;
|
||||
import io.dataease.base.mapper.SysUsersRolesMapper;
|
||||
import io.dataease.base.mapper.ext.ExtSysRoleMapper;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.RoleGridRequest;
|
||||
import io.dataease.controller.sys.request.RoleMenusRequest;
|
||||
import io.dataease.controller.sys.response.RoleUserItem;
|
||||
@ -56,8 +57,8 @@ public class SysRoleService {
|
||||
}
|
||||
|
||||
|
||||
public List<SysRole> query(RoleGridRequest request){
|
||||
List<SysRole> result = extSysRoleMapper.query(request);
|
||||
public List<SysRole> query(BaseGridRequest request){
|
||||
List<SysRole> result = extSysRoleMapper.query(request.convertExample());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@ import io.dataease.base.domain.SysUsersRolesKey;
|
||||
import io.dataease.base.mapper.SysUserMapper;
|
||||
import io.dataease.base.mapper.SysUsersRolesMapper;
|
||||
import io.dataease.base.mapper.ext.ExtSysUserMapper;
|
||||
import io.dataease.base.mapper.ext.query.GridExample;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.controller.sys.base.BaseGridRequest;
|
||||
import io.dataease.controller.sys.request.SysUserCreateRequest;
|
||||
import io.dataease.controller.sys.request.SysUserPwdRequest;
|
||||
import io.dataease.controller.sys.request.SysUserStateRequest;
|
||||
@ -40,8 +42,10 @@ public class SysUserService {
|
||||
@Resource
|
||||
private ExtSysUserMapper extSysUserMapper;
|
||||
|
||||
public List<SysUserGridResponse> query(UserGridRequest request){
|
||||
List<SysUserGridResponse> lists = extSysUserMapper.query(request);
|
||||
|
||||
public List<SysUserGridResponse> query(BaseGridRequest request){
|
||||
GridExample gridExample = request.convertExample();
|
||||
List<SysUserGridResponse> lists = extSysUserMapper.query(gridExample);
|
||||
lists.forEach(item -> {
|
||||
List<SysUserRole> roles = item.getRoles();
|
||||
List<Long> roleIds = roles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
|
||||
@ -111,6 +115,7 @@ public class SysUserService {
|
||||
return sysUserMapper.updateByPrimaryKeySelective(sysUser);
|
||||
}
|
||||
|
||||
@CacheEvict(value = USER_CACHE_NAME, key = "'user' + #request.userId")
|
||||
public int adminUpdatePwd(SysUserPwdRequest request){
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserId(request.getUserId());
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
user.dir - 用户当前工作目录
|
||||
java.io.tmpdir - 默认临时文件路径
|
||||
-->
|
||||
<!-- <diskStore path="D:/home/Tmp_Ehcache"/>-->
|
||||
<diskStore path="/opt/dataease/data/ehcache"/>
|
||||
<!--
|
||||
name:缓存名称。
|
||||
maxElementsInMemory:缓存最大数目
|
||||
maxElementsInMemory:jvm缓存最大数目
|
||||
maxElementsOnDisk:硬盘最大缓存个数。
|
||||
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
|
||||
overflowToDisk:是否保存到磁盘,当系统宕机时
|
||||
@ -39,10 +39,23 @@
|
||||
name="users_info"
|
||||
eternal="false"
|
||||
maxElementsInMemory="100"
|
||||
overflowToDisk="false"
|
||||
diskPersistent="false"
|
||||
timeToIdleSeconds="0"
|
||||
timeToLiveSeconds="300"
|
||||
maxElementsOnDisk="1000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="true"
|
||||
timeToIdleSeconds="1800"
|
||||
timeToLiveSeconds="3600"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
<cache
|
||||
name="tokens_expire"
|
||||
eternal="false"
|
||||
maxElementsInMemory="100"
|
||||
maxElementsOnDisk="1000"
|
||||
overflowToDisk="true"
|
||||
diskPersistent="true"
|
||||
timeToIdleSeconds="1800"
|
||||
timeToLiveSeconds="3600"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 110 KiB |
@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="947.2 183.1 174 35" style="enable-background:new 947.2 183.1 174 35;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#783887;}
|
||||
.st1{fill:#622870;}
|
||||
.st2{fill:#8B489B;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g id="XMLID_803_">
|
||||
<path id="XMLID_829_" class="st0" d="M998.3,209.6l-1.1-11.2l-3.1,11.2h-3.6l-3-11.2l-1.1,11.2l-5,0l2.4-16.5h6.3l2.2,7.8l2.2-7.8
|
||||
h6.2l2.5,16.5H998.3z"/>
|
||||
<path id="XMLID_826_" class="st0" d="M1015.2,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1015.1,200.7,1015.2,201.6,1015.2,202.7z M1011.8,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_823_" class="st0" d="M1037.3,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1037.2,200.7,1037.3,201.6,1037.3,202.7z M1033.9,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1L1033.9,202.1z"/>
|
||||
<path id="XMLID_820_" class="st0" d="M1098.2,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1098.1,200.7,1098.2,201.6,1098.2,202.7z M1094.8,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_817_" class="st0" d="M1120.3,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1120.2,200.7,1120.3,201.6,1120.3,202.7z M1116.9,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_815_" class="st0" d="M1025.7,209.6h-2.1c-0.4,0-0.7,0-0.9,0c-0.7-0.1-1.3-0.2-1.7-0.4c-0.5-0.3-1-0.7-1.2-1.2
|
||||
c-0.3-0.6-0.5-1.4-0.5-2.5l0-4.6h-1.7v-3h1.7v-2.3l1.7,0l1.8-0.2v2.6h2.7l-0.4,3h-2.3v4.4c0,0.1,0,0.2,0,0.3c0,0.2,0,0.3,0.1,0.5
|
||||
c0.1,0.3,0.3,0.5,0.7,0.6c0.3,0.1,1.9,0.1,1.9,0.1L1025.7,209.6z"/>
|
||||
<path id="XMLID_813_" class="st0" d="M1047.7,197.9l-0.1,2.8c-0.3,0-1.2,0-2.1,0.2c-0.8,0.2-1.7,0.6-2.1,0.8v8h-3.5v-11.8h3.3
|
||||
c0,0-0.1,0.6,0,0.9l0.8-0.3c0.5-0.2,1-0.3,1.7-0.4C1046.7,197.8,1047.3,197.9,1047.7,197.9z"/>
|
||||
<path id="XMLID_811_" class="st0" d="M1108.9,197.9l-0.1,2.8c-0.3,0-1.2,0-2.1,0.2c-0.8,0.2-1.7,0.6-2.1,0.8v8h-3.5v-11.8h3.3
|
||||
c0,0-0.1,0.6,0,0.9l0.8-0.3c0.5-0.2,1-0.3,1.7-0.4C1107.9,197.8,1108.5,197.9,1108.9,197.9z"/>
|
||||
<path id="XMLID_809_" class="st0" d="M1054.6,210.1c-0.8,0-1.8-0.1-2.7-0.2c-0.4,0-0.8-0.1-1.2-0.2l-1.6-0.2l0-4.1l2.4,0.4
|
||||
c0,0,1,0.1,1.4,0.2c0.5,0.1,1,0.1,1.4,0.1c1.5,0,2.4-0.4,2.7-1.1c0.1-0.3,0.1-0.6,0-0.9c-0.2-0.3-0.5-0.6-0.9-0.8
|
||||
c-0.2-0.1-0.5-0.2-0.8-0.3l-0.9-0.3c-0.4-0.1-0.8-0.2-1.1-0.3c-0.4-0.1-0.8-0.3-1.1-0.4c-0.8-0.4-1.5-0.8-2-1.3
|
||||
c-0.4-0.5-0.7-1.1-0.9-1.8c-0.1-0.5-0.1-1.1,0-1.7c0.2-1.8,1-3.1,2.3-3.8c0.5-0.3,1.1-0.5,1.8-0.6c0.3,0,0.6-0.1,0.9-0.1l0.9-0.1
|
||||
h0.6c0.7,0,1.5,0,2.3,0.1l1,0.1l1.2,0.2l0,3.6c-0.5-0.1-1-0.2-1.7-0.3c-0.9-0.1-1.7-0.2-2.4-0.2c-1.6,0-2.2,0.3-2.5,1.1
|
||||
c-0.1,0.3-0.1,0.6-0.1,0.9c0,0.4,0,0.5,0.7,0.8c0.2,0.1,0.5,0.2,0.8,0.3l2.1,0.6c0.4,0.1,0.8,0.3,1.1,0.4c0.8,0.3,1.4,0.7,1.8,1.1
|
||||
c0.5,0.5,0.8,1.1,0.9,1.8c0.1,0.5,0.1,1.1,0,1.7c-0.2,1.8-1.1,3.4-2.4,4.1c-0.5,0.3-1.1,0.5-1.8,0.6c-0.3,0-0.6,0.1-0.9,0.1
|
||||
l-0.8,0.1L1054.6,210.1L1054.6,210.1z"/>
|
||||
<path id="XMLID_806_" class="st0" d="M1063.6,197.8h3.2l-0.1,0.8c0.3-0.2,0.6-0.3,1-0.4c0.4-0.2,0.8-0.3,1.1-0.3
|
||||
c0.9-0.2,1.8-0.2,2.7,0.1c0.5,0.2,1,0.5,1.4,1c0.2,0.2,0.3,0.4,0.4,0.6l0.1,0.2c0,0.1,0.1,0.1,0.1,0.2c0.2,0.4,0.3,0.9,0.4,1.4
|
||||
c0.1,0.6,0.2,1.3,0.2,2.2v0.7c0,1.8-0.1,2.7-0.4,3.4c-0.5,1.1-1.6,1.6-3.7,1.7c-0.3,0-0.7,0-1.2,0l-0.8,0c-0.3,0-0.5,0-0.7,0v5.1
|
||||
l-3.6,0.2V197.8L1063.6,197.8z M1067.2,206.1c0.7,0.1,1.1,0.1,1.7,0.1l0.6-0.1c0.7-0.2,1-0.6,1-1.3v-2.3c0-0.3,0-0.6-0.1-0.7
|
||||
c-0.2-0.7-0.8-1-1.8-0.9l-0.4,0.1l-0.7,0.2l-0.3,0.1L1067.2,206.1L1067.2,206.1z"/>
|
||||
<path id="XMLID_804_" class="st0" d="M1086.5,203.2v6.4h-3.6v-7c0-0.4-0.3-1.1-0.8-1.4c-0.4-0.2-1-0.2-1.2-0.1
|
||||
c-0.5,0.1-1,0.4-1.3,0.6v7.9h-3.6v-17l3.6,0v6c0.4-0.2,0.9-0.3,1.4-0.4c0.4-0.1,0.8-0.1,1.2-0.1c2.1,0,3.2,0.6,3.7,1.7
|
||||
C1086.2,200.2,1086.5,201.4,1086.5,203.2z"/>
|
||||
</g>
|
||||
<g id="XMLID_799_">
|
||||
<path id="XMLID_800_" class="st0" d="M961.7,184.4l13.7,8v16.1l-13.7,8l-13.7-8v-16.1L961.7,184.4 M961.7,183.9l-14.1,8.3v16.5
|
||||
l14.1,8.3l14.1-8.3v-16.5L961.7,183.9L961.7,183.9z"/>
|
||||
</g>
|
||||
<g id="XMLID_796_">
|
||||
<polygon id="XMLID_64_" class="st1" points="961.9,200.6 973.8,193.6 973.8,207.5 961.9,214.5 "/>
|
||||
</g>
|
||||
<polygon id="XMLID_795_" class="st2" points="949.8,193.2 961.7,186.3 973.6,193.2 961.7,200.2 "/>
|
||||
<g id="XMLID_792_">
|
||||
<polygon id="XMLID_65_" class="st0" points="949.6,207.5 949.6,193.6 961.5,200.6 961.5,214.5 "/>
|
||||
</g>
|
||||
<g id="XMLID_789_">
|
||||
<path id="XMLID_790_" class="st3" d="M957.8,209.4v-4.9l-1.8,3.9l-1.5-0.9l-0.8-5.4l-0.9,4.3l-2.1-1.3l1.7-6.2l2.6,1.6l0.6,3.8
|
||||
l1.2-2.7l2.6,1.5l0.4,7.5L957.8,209.4z"/>
|
||||
</g>
|
||||
<g id="XMLID_786_">
|
||||
<path id="XMLID_787_" class="st3" d="M968,209.1c-0.4,0.2-0.9,0.3-1.4,0.5c-0.2,0.1-0.4,0.1-0.6,0.2l-0.8,0.2l0-2l1.2-0.3
|
||||
c0,0,0.5-0.1,0.7-0.2c0.3-0.1,0.5-0.2,0.7-0.3c0.8-0.3,1.2-0.7,1.3-1.1c0.1-0.2,0.1-0.3,0-0.4c-0.1-0.1-0.2-0.2-0.5-0.2
|
||||
c-0.1,0-0.2,0-0.4,0l-0.5,0c-0.2,0-0.4,0.1-0.5,0.1c-0.2,0-0.4,0-0.6,0c-0.4,0-0.8-0.1-1-0.2c-0.2-0.1-0.4-0.4-0.5-0.7
|
||||
c-0.1-0.2-0.1-0.5,0-0.8c0.1-0.9,0.4-1.7,1.1-2.3c0.3-0.2,0.5-0.5,0.9-0.7c0.1-0.1,0.3-0.2,0.5-0.2l0.5-0.2l0.3-0.1
|
||||
c0.4-0.1,0.7-0.3,1.2-0.4l0.5-0.2l0.6-0.2l0.1,1.8c-0.2,0-0.5,0.1-0.9,0.2c-0.4,0.1-0.9,0.3-1.2,0.4c-0.8,0.3-1.1,0.6-1.2,1
|
||||
c0,0.2,0,0.3,0,0.5c0,0.2,0,0.2,0.4,0.3c0.1,0,0.3,0,0.4,0l1.1-0.1c0.2,0,0.4,0,0.5,0c0.4,0,0.7,0.1,0.9,0.2
|
||||
c0.2,0.1,0.4,0.4,0.5,0.7c0.1,0.2,0.1,0.5,0,0.8c-0.1,0.9-0.5,1.9-1.1,2.5c-0.2,0.2-0.5,0.5-0.9,0.7c-0.1,0.1-0.3,0.2-0.5,0.2
|
||||
l-0.4,0.2L968,209.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.6 KiB |
@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="947.2 183.1 174 35" style="enable-background:new 947.2 183.1 174 35;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g id="XMLID_140_">
|
||||
<path id="XMLID_166_" class="st0" d="M998.3,209.6l-1.1-11.2l-3.1,11.2h-3.6l-3-11.2l-1.1,11.2l-5,0l2.4-16.5h6.3l2.2,7.8l2.2-7.8
|
||||
h6.2l2.5,16.5H998.3z"/>
|
||||
<path id="XMLID_163_" class="st0" d="M1015.2,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1015.1,200.7,1015.2,201.6,1015.2,202.7z M1011.8,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_160_" class="st0" d="M1037.3,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1037.2,200.7,1037.3,201.6,1037.3,202.7z M1033.9,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1L1033.9,202.1z"/>
|
||||
<path id="XMLID_157_" class="st0" d="M1098.2,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1098.1,200.7,1098.2,201.6,1098.2,202.7z M1094.8,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_154_" class="st0" d="M1120.3,202.7v2.1h-6.5l0,0.4c0,0.8,0.3,1.3,0.8,1.4c0.4,0.1,0.8,0.2,1.3,0.2h0.3
|
||||
c1.3,0,3.1-0.3,4.5-0.6h0l-0.5,2.9c0,0-0.6,0.3-1.8,0.5c-0.8,0.1-1.6,0.1-2.6,0.1c-2.6,0-4.2-0.9-4.9-2.6
|
||||
c-0.3-0.7-0.5-1.4-0.5-2.2v-2.8c0-2.1,1-3.4,2.7-4.1c0.8-0.3,1.6-0.4,2.4-0.4c2.4,0,4,0.8,4.7,2.4
|
||||
C1120.2,200.7,1120.3,201.6,1120.3,202.7z M1116.9,202.1c0-0.8-0.2-1.4-0.6-1.5c-0.3-0.2-0.7-0.2-1-0.2c-1,0-1.4,0.5-1.4,1.4
|
||||
l-0.1,0.6h3.1V202.1z"/>
|
||||
<path id="XMLID_152_" class="st0" d="M1025.7,209.6h-2.1c-0.4,0-0.7,0-0.9,0c-0.7-0.1-1.3-0.2-1.7-0.4c-0.5-0.3-1-0.7-1.2-1.2
|
||||
c-0.3-0.6-0.5-1.4-0.5-2.5l0-4.6h-1.7v-3h1.7v-2.3l1.7,0l1.8-0.2v2.6h2.7l-0.4,3h-2.3v4.4c0,0.1,0,0.2,0,0.3c0,0.2,0,0.3,0.1,0.5
|
||||
c0.1,0.3,0.3,0.5,0.7,0.6c0.3,0.1,1.9,0.1,1.9,0.1L1025.7,209.6z"/>
|
||||
<path id="XMLID_150_" class="st0" d="M1047.7,197.9l-0.1,2.8c-0.3,0-1.2,0-2.1,0.2c-0.8,0.2-1.7,0.6-2.1,0.8v8h-3.5v-11.8h3.3
|
||||
c0,0-0.1,0.6,0,0.9l0.8-0.3c0.5-0.2,1-0.3,1.7-0.4C1046.7,197.8,1047.3,197.9,1047.7,197.9z"/>
|
||||
<path id="XMLID_148_" class="st0" d="M1108.9,197.9l-0.1,2.8c-0.3,0-1.2,0-2.1,0.2c-0.8,0.2-1.7,0.6-2.1,0.8v8h-3.5v-11.8h3.3
|
||||
c0,0-0.1,0.6,0,0.9l0.8-0.3c0.5-0.2,1-0.3,1.7-0.4C1107.9,197.8,1108.5,197.9,1108.9,197.9z"/>
|
||||
<path id="XMLID_146_" class="st0" d="M1054.6,210.1c-0.8,0-1.8-0.1-2.7-0.2c-0.4,0-0.8-0.1-1.2-0.2l-1.6-0.2l0-4.1l2.4,0.4
|
||||
c0,0,1,0.1,1.4,0.2c0.5,0.1,1,0.1,1.4,0.1c1.5,0,2.4-0.4,2.7-1.1c0.1-0.3,0.1-0.6,0-0.9c-0.2-0.3-0.5-0.6-0.9-0.8
|
||||
c-0.2-0.1-0.5-0.2-0.8-0.3l-0.9-0.3c-0.4-0.1-0.8-0.2-1.1-0.3c-0.4-0.1-0.8-0.3-1.1-0.4c-0.8-0.4-1.5-0.8-2-1.3
|
||||
c-0.4-0.5-0.7-1.1-0.9-1.8c-0.1-0.5-0.1-1.1,0-1.7c0.2-1.8,1-3.1,2.3-3.8c0.5-0.3,1.1-0.5,1.8-0.6c0.3,0,0.6-0.1,0.9-0.1l0.9-0.1
|
||||
h0.6c0.7,0,1.5,0,2.3,0.1l1,0.1l1.2,0.2l0,3.6c-0.5-0.1-1-0.2-1.7-0.3c-0.9-0.1-1.7-0.2-2.4-0.2c-1.6,0-2.2,0.3-2.5,1.1
|
||||
c-0.1,0.3-0.1,0.6-0.1,0.9c0,0.4,0,0.5,0.7,0.8c0.2,0.1,0.5,0.2,0.8,0.3l2.1,0.6c0.4,0.1,0.8,0.3,1.1,0.4c0.8,0.3,1.4,0.7,1.8,1.1
|
||||
c0.5,0.5,0.8,1.1,0.9,1.8c0.1,0.5,0.1,1.1,0,1.7c-0.2,1.8-1.1,3.4-2.4,4.1c-0.5,0.3-1.1,0.5-1.8,0.6c-0.3,0-0.6,0.1-0.9,0.1
|
||||
l-0.8,0.1L1054.6,210.1L1054.6,210.1z"/>
|
||||
<path id="XMLID_143_" class="st0" d="M1063.6,197.8h3.2l-0.1,0.8c0.3-0.2,0.6-0.3,1-0.4c0.4-0.2,0.8-0.3,1.1-0.3
|
||||
c0.9-0.2,1.8-0.2,2.7,0.1c0.5,0.2,1,0.5,1.4,1c0.2,0.2,0.3,0.4,0.4,0.6l0.1,0.2c0,0.1,0.1,0.1,0.1,0.2c0.2,0.4,0.3,0.9,0.4,1.4
|
||||
c0.1,0.6,0.2,1.3,0.2,2.2v0.7c0,1.8-0.1,2.7-0.4,3.4c-0.5,1.1-1.6,1.6-3.7,1.7c-0.3,0-0.7,0-1.2,0l-0.8,0c-0.3,0-0.5,0-0.7,0v5.1
|
||||
l-3.6,0.2V197.8L1063.6,197.8z M1067.2,206.1c0.7,0.1,1.1,0.1,1.7,0.1l0.6-0.1c0.7-0.2,1-0.6,1-1.3v-2.3c0-0.3,0-0.6-0.1-0.7
|
||||
c-0.2-0.7-0.8-1-1.8-0.9l-0.4,0.1l-0.7,0.2l-0.3,0.1L1067.2,206.1L1067.2,206.1z"/>
|
||||
<path id="XMLID_141_" class="st0" d="M1086.5,203.2v6.4h-3.6v-7c0-0.4-0.3-1.1-0.8-1.4c-0.4-0.2-1-0.2-1.2-0.1
|
||||
c-0.5,0.1-1,0.4-1.3,0.6v7.9h-3.6v-17l3.6,0v6c0.4-0.2,0.9-0.3,1.4-0.4c0.4-0.1,0.8-0.1,1.2-0.1c2.1,0,3.2,0.6,3.7,1.7
|
||||
C1086.2,200.2,1086.5,201.4,1086.5,203.2z"/>
|
||||
</g>
|
||||
<g id="XMLID_136_">
|
||||
<path id="XMLID_137_" class="st0" d="M961.7,184.4l13.7,8v16.1l-13.7,8l-13.7-8v-16.1L961.7,184.4 M961.7,183.9l-14.1,8.3v16.5
|
||||
l14.1,8.3l14.1-8.3v-16.5L961.7,183.9L961.7,183.9z"/>
|
||||
</g>
|
||||
<polygon id="XMLID_132_" class="st0" points="949.8,193.2 961.7,186.3 973.6,193.2 961.7,200.2 "/>
|
||||
<g id="XMLID_278_">
|
||||
<g id="XMLID_42_">
|
||||
<path id="XMLID_43_" class="st0" d="M949.6,193.6v13.9l11.9,6.9v-13.9L949.6,193.6z M957.8,209.4v-4.9l-1.8,3.9l-1.5-0.9
|
||||
l-0.8-5.4l-0.9,4.3l-2.1-1.3l1.7-6.2l2.6,1.6l0.6,3.8l1.2-2.7l2.6,1.5l0.4,7.5L957.8,209.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="XMLID_129_">
|
||||
<g id="XMLID_37_">
|
||||
<path id="XMLID_38_" class="st0" d="M961.9,200.6v13.9l11.9-6.9v-13.9L961.9,200.6z M971.3,205.3c-0.1,0.9-0.5,1.9-1.1,2.5
|
||||
c-0.2,0.2-0.5,0.5-0.9,0.7c-0.1,0.1-0.3,0.2-0.5,0.2l-0.4,0.2l-0.3,0.1c-0.4,0.2-0.9,0.3-1.4,0.5c-0.2,0.1-0.4,0.1-0.6,0.2
|
||||
l-0.8,0.2l0-2l1.2-0.3c0,0,0.5-0.1,0.7-0.2c0.3-0.1,0.5-0.2,0.7-0.3c0.8-0.3,1.2-0.7,1.3-1.1c0.1-0.2,0.1-0.3,0-0.4
|
||||
c-0.1-0.1-0.2-0.2-0.5-0.2c-0.1,0-0.2,0-0.4,0l-0.5,0c-0.2,0-0.4,0.1-0.5,0.1c-0.2,0-0.4,0-0.6,0c-0.4,0-0.8-0.1-1-0.2
|
||||
c-0.2-0.1-0.4-0.4-0.5-0.7c-0.1-0.2-0.1-0.5,0-0.8c0.1-0.9,0.4-1.7,1.1-2.3c0.3-0.2,0.5-0.5,0.9-0.7c0.1-0.1,0.3-0.2,0.5-0.2
|
||||
l0.5-0.2l0.3-0.1c0.4-0.1,0.7-0.3,1.2-0.4l0.5-0.2l0.6-0.2l0.1,1.8c-0.2,0-0.5,0.1-0.9,0.2c-0.4,0.1-0.9,0.3-1.2,0.4
|
||||
c-0.8,0.3-1.1,0.6-1.2,1c0,0.2,0,0.3,0,0.5c0,0.2,0,0.2,0.4,0.3c0.1,0,0.3,0,0.4,0l1.1-0.1c0.2,0,0.4,0,0.5,0
|
||||
c0.4,0,0.7,0.1,0.9,0.2c0.2,0.1,0.4,0.4,0.5,0.7C971.3,204.7,971.3,205,971.3,205.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
@ -2,5 +2,5 @@
|
||||
ENV = 'production'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/prod-api'
|
||||
VUE_APP_BASE_API = 'http://localhost:8081/'
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"build:prod": "vue-cli-service build",
|
||||
"build:stage": "vue-cli-service build --mode staging",
|
||||
"preview": "node build/index.js --preview",
|
||||
|
||||
64
frontend/pom.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<artifactId>dataease-server</artifactId>
|
||||
<groupId>io.dataease</groupId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>frontend</artifactId>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<frontend-maven-plugin.version>1.9.1</frontend-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>${frontend-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
<goals>
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- See https://nodejs.org/en/download/ for latest node and npm (lts) versions -->
|
||||
<nodeVersion>v8.11.1</nodeVersion>
|
||||
<npmVersion>5.6.0</npmVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>npm install</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<!-- Optional configuration which provides for running any npm command -->
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>npm run build</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<arguments>run build</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -3,7 +3,17 @@ import request from '@/utils/request'
|
||||
export function getDeptTree(pid) {
|
||||
return request({
|
||||
url: 'api/dept/childNodes/' + pid,
|
||||
method: 'post'
|
||||
method: 'post',
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
export function loadTable(data) {
|
||||
return request({
|
||||
url: 'api/dept/search',
|
||||
method: 'post',
|
||||
data,
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
@ -31,4 +41,4 @@ export function editDept(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export default { addDept, delDept, editDept, getDeptTree }
|
||||
export default { addDept, delDept, editDept, getDeptTree, loadTable }
|
||||
|
||||
@ -3,7 +3,8 @@ import request from '@/utils/request'
|
||||
export function getMenusTree(pid) {
|
||||
return request({
|
||||
url: 'api/menu/childNodes/' + pid,
|
||||
method: 'post'
|
||||
method: 'post',
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,8 @@ import request from '@/utils/request'
|
||||
export function allRoles() {
|
||||
return request({
|
||||
url: '/api/role/all',
|
||||
method: 'post'
|
||||
method: 'post',
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
@ -11,7 +12,8 @@ export function roleGrid(pageIndex, pageSize, data) {
|
||||
return request({
|
||||
url: '/api/role/roleGrid/' + pageIndex + '/' + pageSize,
|
||||
method: 'post',
|
||||
data
|
||||
data,
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
95
frontend/src/components/business/condition-table/index.vue
Normal file
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <el-switch v-model="value" active-text="当前用户" /> -->
|
||||
|
||||
<treeselect
|
||||
v-model="value"
|
||||
:options="options"
|
||||
:load-options="loadData"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ComplexCondition } from 'fit2cloud-ui/src/components/search-bar/model'
|
||||
import { getDeptTree } from '@/api/system/dept'
|
||||
import { LOAD_CHILDREN_OPTIONS, LOAD_ROOT_OPTIONS } from '@riophae/vue-treeselect'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
export default {
|
||||
components: { Treeselect },
|
||||
props: {
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
field: String,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
label: String,
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
defaultOperator: String
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
// options: Array
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
// loadData: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: undefined,
|
||||
operator: 'dept',
|
||||
operatorLabel: '组织',
|
||||
options: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valueLabel() {
|
||||
return this.value
|
||||
}
|
||||
},
|
||||
// 自定义搜索控件的2个方法
|
||||
methods: {
|
||||
init() { // 初始化方法,在打开复合搜索界面时会被调用
|
||||
// 例如清空之前填写的内容
|
||||
this.value = undefined
|
||||
},
|
||||
getCondition() { // 点击确认时调用
|
||||
const { field, label, operator, operatorLabel, value, valueLabel } = this
|
||||
// 必须返回ComplexCondition类型的对象
|
||||
return new ComplexCondition({ field, label, operator, operatorLabel, value, valueLabel })
|
||||
},
|
||||
|
||||
// 获取弹窗内部门数据
|
||||
loadData({ action, parentNode, callback }) {
|
||||
if (action === LOAD_ROOT_OPTIONS) {
|
||||
const _self = this
|
||||
!this.options && getDeptTree('0').then(res => {
|
||||
_self.options = res.data.map(node => _self.normalizer(node))
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
if (action === LOAD_CHILDREN_OPTIONS) {
|
||||
const _self = this
|
||||
getDeptTree(parentNode.id).then(res => {
|
||||
parentNode.children = res.data.map(function(obj) {
|
||||
return _self.normalizer(obj)
|
||||
})
|
||||
callback()
|
||||
})
|
||||
}
|
||||
},
|
||||
normalizer(node) {
|
||||
if (node.hasChildren) {
|
||||
node.children = null
|
||||
}
|
||||
return {
|
||||
id: node.deptId,
|
||||
label: node.name,
|
||||
children: node.children
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -11,17 +11,22 @@ import zhLocale from './zh'
|
||||
import twLocale from './tw'
|
||||
import esLocale from './es'
|
||||
import jaLocale from './ja'
|
||||
import fuZh from 'fit2cloud-ui/src/locale/lang/zh-CN' // 加载fit2cloud的内容
|
||||
|
||||
import fuEn from 'fit2cloud-ui/src/locale/lang/en_US' // 加载fit2cloud的内容
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
const messages = {
|
||||
en: {
|
||||
...enLocale,
|
||||
...elementEnLocale
|
||||
...elementEnLocale,
|
||||
...fuEn
|
||||
},
|
||||
zh: {
|
||||
...zhLocale,
|
||||
...elementZhLocale
|
||||
...elementZhLocale,
|
||||
...fuZh
|
||||
},
|
||||
tw: {
|
||||
...twLocale,
|
||||
|
||||
@ -80,7 +80,9 @@ export default {
|
||||
password: '密码',
|
||||
any: '随便填',
|
||||
thirdparty: '第三方登录',
|
||||
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
|
||||
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!',
|
||||
expires: '登录token过期,请重新登录',
|
||||
tokenError: 'token错误,请重新登录'
|
||||
},
|
||||
commons: {
|
||||
upload: '上传',
|
||||
@ -422,6 +424,7 @@ export default {
|
||||
input_email: '请输入邮箱',
|
||||
input_password: '请输入密码',
|
||||
input_phone: '请输入电话号码',
|
||||
input_roles: '请选择角色',
|
||||
special_characters_are_not_supported: '不支持特殊字符',
|
||||
mobile_number_format_is_incorrect: '手机号码格式不正确',
|
||||
email_format_is_incorrect: '邮箱格式不正确',
|
||||
@ -445,7 +448,8 @@ export default {
|
||||
menu: {
|
||||
create: '创建菜单',
|
||||
modify: '修改菜单',
|
||||
delete: '删除菜单'
|
||||
delete: '删除菜单',
|
||||
delete_confirm: '确定删除菜单吗'
|
||||
},
|
||||
organization: {
|
||||
create: '创建组织',
|
||||
@ -587,7 +591,16 @@ export default {
|
||||
result_filter: '结果过滤器',
|
||||
x_axis: '横轴',
|
||||
y_axis: '纵轴',
|
||||
chart: '视图'
|
||||
chart: '视图',
|
||||
close: '关闭',
|
||||
summary: '汇总方式',
|
||||
fast_calc: '快速计算',
|
||||
sum: '求和',
|
||||
avg: '平均',
|
||||
max: '最大值',
|
||||
min: '最小值',
|
||||
std: '标准差',
|
||||
var_samp: '方差'
|
||||
},
|
||||
dataset: {
|
||||
datalist: '数据集',
|
||||
|
||||
@ -42,6 +42,9 @@ const mutations = {
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
},
|
||||
SET_LOGIN_MSG: (state, msg) => {
|
||||
state.loginMsg = msg
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +56,7 @@ const actions = {
|
||||
login({ username: username.trim(), password: password }).then(response => {
|
||||
const { data } = response
|
||||
commit('SET_TOKEN', data.token)
|
||||
commit('SET_LOGIN_MSG', null)
|
||||
setToken(data.token)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
@ -117,6 +121,9 @@ const actions = {
|
||||
commit('RESET_STATE')
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
setLoginMsg({ commit, msg }) {
|
||||
commit('SET_LOGIN_MSG', msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import Cookies from 'js-cookie'
|
||||
import Config from '@/settings'
|
||||
|
||||
const TokenKey = Config.TokenKey
|
||||
|
||||
export function getToken() {
|
||||
@ -13,3 +14,4 @@ export function setToken(token) {
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
|
||||
|
||||
@ -136,3 +136,29 @@ export function param2Obj(url) {
|
||||
'"}'
|
||||
)
|
||||
}
|
||||
|
||||
// export function formatCondition(param) {
|
||||
// if (!param) {
|
||||
// return null
|
||||
// }
|
||||
// const condition = {}
|
||||
// for (const key in param) {
|
||||
// if (Object.hasOwnProperty.call(param, key)) {
|
||||
// const element = param[key]
|
||||
// condition[element.field] = element.value
|
||||
// }
|
||||
// }
|
||||
// return condition
|
||||
// }
|
||||
|
||||
export function formatCondition(param) {
|
||||
if (!param) {
|
||||
return null
|
||||
}
|
||||
const result = { conditions: [] }
|
||||
for (const [key, value] of Object.entries(param)) {
|
||||
console.log(`${key}`)
|
||||
result.conditions.push(value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { MessageBox, Message } from 'element-ui'
|
||||
|
||||
import i18n from '@/lang'
|
||||
export const $alert = (message, callback, options) => {
|
||||
const title = this.$t('common.message_box.alert')
|
||||
const title = i18n.t('common.message_box.alert')
|
||||
MessageBox.alert(message, title, options).then(() => {
|
||||
callback()
|
||||
})
|
||||
@ -9,12 +9,12 @@ export const $alert = (message, callback, options) => {
|
||||
|
||||
export const $confirm = (message, callback, options = {}) => {
|
||||
const defaultOptions = {
|
||||
confirmButtonText: this.$t('common.button.ok'),
|
||||
cancelButtonText: this.$t('common.button.cancel'),
|
||||
confirmButtonText: i18n.t('common.button.ok'),
|
||||
cancelButtonText: i18n.t('common.button.cancel'),
|
||||
type: 'warning',
|
||||
...options
|
||||
}
|
||||
const title = this.$t('common.message_box.confirm')
|
||||
const title = i18n.t('common.message_box.confirm')
|
||||
MessageBox.confirm(message, title, defaultOptions).then(() => {
|
||||
callback()
|
||||
})
|
||||
|
||||
9
frontend/src/utils/permission.js
Normal file
@ -0,0 +1,9 @@
|
||||
import store from '@/store'
|
||||
export function checkPermission(pers) {
|
||||
const permissions = store.getters.permissions
|
||||
const hasPermission = pers.every(needP => {
|
||||
const result = permissions.includes(needP)
|
||||
return result
|
||||
})
|
||||
return hasPermission
|
||||
}
|
||||
@ -4,7 +4,7 @@ import store from '@/store'
|
||||
import { $alert, $error } from './message'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import Config from '@/settings'
|
||||
|
||||
import i18n from '@/lang'
|
||||
import { tryShowLoading, tryHideLoading } from './loading'
|
||||
// import router from '@/router'
|
||||
|
||||
@ -44,16 +44,19 @@ service.interceptors.request.use(
|
||||
|
||||
const checkAuth = response => {
|
||||
// 请根据实际需求修改
|
||||
if (response.headers['authentication-status'] === 'invalid' || response.status === 401) {
|
||||
const message = this.$t('login.expires')
|
||||
|
||||
if (response.headers['authentication-status'] === 'login_expire') {
|
||||
const message = i18n.t('login.expires')
|
||||
store.dispatch('user/setLoginMsg', message)
|
||||
$alert(message, () => {
|
||||
store.dispatch('user/logout').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
}
|
||||
if (response.headers['authentication-status'] === 'login_expire') {
|
||||
const message = this.$t('login.expires')
|
||||
|
||||
if (response.headers['authentication-status'] === 'invalid' || response.status === 401) {
|
||||
const message = i18n.t('login.tokenError')
|
||||
$alert(message, () => {
|
||||
store.dispatch('user/logout').then(() => {
|
||||
location.reload()
|
||||
|
||||
@ -18,3 +18,5 @@ export function validUsername(str) {
|
||||
const valid_map = ['admin', 'cyw']
|
||||
return valid_map.indexOf(str.trim()) >= 0
|
||||
}
|
||||
|
||||
export const PHONE_REGEX = '^1[3|4|5|7|8][0-9]{9}$'
|
||||
|
||||
@ -15,6 +15,23 @@ export const BASE_BAR = {
|
||||
series: []
|
||||
}
|
||||
|
||||
export default {
|
||||
BASE_BAR
|
||||
export const BASE_LINE = {
|
||||
title: {
|
||||
text: ''
|
||||
},
|
||||
tooltip: {},
|
||||
legend: {
|
||||
data: []
|
||||
},
|
||||
xAxis: {
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: []
|
||||
}
|
||||
|
||||
export default {
|
||||
BASE_BAR, BASE_LINE
|
||||
}
|
||||
|
||||
68
frontend/src/views/chart/components/ChartComponent.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="Echarts" style="height: 100%;display: flex;margin-top: 10px;">
|
||||
<div id="echart" style="width: 100%;height: 80vh;" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BASE_BAR, BASE_LINE } from '../chart/chart'
|
||||
|
||||
export default {
|
||||
name: 'ChartComponent',
|
||||
props: {
|
||||
chart: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
myChart: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
chart() {
|
||||
this.drawEcharts()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
this.myChart = this.$echarts.init(document.getElementById('echart'))
|
||||
},
|
||||
methods: {
|
||||
drawEcharts() {
|
||||
const chart = this.chart
|
||||
let chart_option = {}
|
||||
// todo type
|
||||
if (chart.type === 'bar') {
|
||||
chart_option = JSON.parse(JSON.stringify(BASE_BAR))
|
||||
} else if (chart.type === 'line') {
|
||||
chart_option = JSON.parse(JSON.stringify(BASE_LINE))
|
||||
}
|
||||
// console.log(chart_option);
|
||||
if (chart.data) {
|
||||
chart_option.title.text = chart.title
|
||||
chart_option.xAxis.data = chart.data.x
|
||||
chart.data.series.forEach(function(y) {
|
||||
chart_option.legend.data.push(y.name)
|
||||
chart_option.series.push(y)
|
||||
})
|
||||
}
|
||||
// console.log(chart_option);
|
||||
this.myEcharts(chart_option)
|
||||
},
|
||||
myEcharts(option) {
|
||||
// 指定图表的配置项和数据
|
||||
const chart = this.myChart
|
||||
setTimeout(chart.setOption(option, true), 500)
|
||||
window.onresize = function() {
|
||||
chart.resize()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
60
frontend/src/views/chart/components/DimensionItem.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<span>
|
||||
<el-dropdown trigger="click" size="small">
|
||||
<span class="el-dropdown-link">
|
||||
<el-tag size="small" class="item-axis">
|
||||
{{ item.name }}<i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-tag>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item icon="el-icon-edit-outline">
|
||||
item1
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-delete">
|
||||
item2
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</span>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DimensionItem',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-axis {
|
||||
padding: 1px 6px;
|
||||
margin: 0 3px 2px 3px;
|
||||
text-align: left;
|
||||
height: 24px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-axis:hover {
|
||||
background-color: #fdfdfd;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
89
frontend/src/views/chart/components/QuotaItem.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<span>
|
||||
<el-dropdown trigger="click" size="small">
|
||||
<span class="el-dropdown-link">
|
||||
<el-tag size="small" class="item-axis">
|
||||
{{ item.name }}<span class="summary-span">{{ $t('chart.'+item.summary) }}</span><i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-tag>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item icon="el-icon-notebook-2">
|
||||
<el-dropdown placement="right-start" size="small" @command="summary">
|
||||
<span class="el-dropdown-link">
|
||||
{{ $t('chart.summary') }}<span class="summary-span">({{ $t('chart.'+item.summary) }})</span><i class="el-icon-arrow-right el-icon--right" />
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item :command="beforeSummary('sum')">{{ $t('chart.sum') }}</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeSummary('avg')">{{ $t('chart.avg') }}</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeSummary('max')">{{ $t('chart.max') }}</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeSummary('min')">{{ $t('chart.min') }}</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeSummary('std')">{{ $t('chart.std') }}</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeSummary('var_samp')">{{ $t('chart.var_samp') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-delete">
|
||||
item4
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</span>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'QuotaItem',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
summary(param) {
|
||||
// console.log(param)
|
||||
this.item.summary = param.type
|
||||
this.$emit('onQuotaSummaryChange', this.item)
|
||||
},
|
||||
beforeSummary(type) {
|
||||
return {
|
||||
type: type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-axis {
|
||||
padding: 1px 6px;
|
||||
margin: 0 3px 2px 3px;
|
||||
text-align: left;
|
||||
height: 24px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-axis:hover {
|
||||
background-color: #fdfdfd;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.summary-span{
|
||||
margin-left: 4px;
|
||||
color: #878d9f;;
|
||||
}
|
||||
</style>
|
||||
@ -7,7 +7,7 @@
|
||||
{{ $t('chart.datalist') }}
|
||||
</span>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
|
||||
<el-row>
|
||||
<el-button icon="el-icon-circle-plus" type="primary" size="mini" @click="add('group')">
|
||||
@ -101,7 +101,7 @@
|
||||
<el-dialog :title="dialogTitle" :visible="editGroup" :show-close="false" width="30%">
|
||||
<el-form ref="groupForm" :model="groupForm" :rules="groupFormRules">
|
||||
<el-form-item :label="$t('commons.name')" prop="name">
|
||||
<el-input v-model="groupForm.name"/>
|
||||
<el-input v-model="groupForm.name" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
@ -121,7 +121,7 @@
|
||||
{{ $t('chart.back') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
<el-row>
|
||||
<el-button type="primary" size="mini" plain @click="selectTable">
|
||||
{{ $t('chart.add_chart') }}
|
||||
@ -180,7 +180,7 @@
|
||||
<el-dialog :title="$t('chart.chart')" :visible="editTable" :show-close="false" width="30%">
|
||||
<el-form ref="tableForm" :model="tableForm" :rules="tableFormRules">
|
||||
<el-form-item :label="$t('commons.name')" prop="name">
|
||||
<el-input v-model="tableForm.name"/>
|
||||
<el-input v-model="tableForm.name" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
@ -197,7 +197,7 @@
|
||||
width="70%"
|
||||
class="dialog-css"
|
||||
>
|
||||
<table-selector @getTable="getTable"/>
|
||||
<table-selector @getTable="getTable" />
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="mini" @click="selectTableFlag = false">{{ $t('chart.cancel') }}</el-button>
|
||||
<el-button type="primary" size="mini" @click="createChart">{{ $t('chart.confirm') }}</el-button>
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
<ms-container v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<ms-aside-container>
|
||||
<group @switchComponent="switchComponent"/>
|
||||
<group @switchComponent="switchComponent" />
|
||||
</ms-aside-container>
|
||||
|
||||
<ms-main-container>
|
||||
<!-- <router-view />-->
|
||||
<component :is="component" :param="param" @switchComponent="switchComponent"/>
|
||||
<component :is="component" :param="param" @switchComponent="switchComponent" />
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
@ -7,12 +7,12 @@
|
||||
<el-row style="height: 40px;" class="padding-lr">
|
||||
<span style="line-height: 40px;">{{ view.name }}</span>
|
||||
<span style="float: right;line-height: 40px;">
|
||||
<el-button size="mini">
|
||||
{{ $t('chart.cancel') }}
|
||||
</el-button>
|
||||
<el-button type="primary" size="mini" @click="save">
|
||||
{{ $t('chart.confirm') }}
|
||||
<el-button size="mini" @click="closeEdit">
|
||||
{{ $t('chart.close') }}
|
||||
</el-button>
|
||||
<!-- <el-button type="primary" size="mini" @click="save">-->
|
||||
<!-- {{ $t('chart.confirm') }}-->
|
||||
<!-- </el-button>-->
|
||||
</span>
|
||||
</el-row>
|
||||
<el-row style="display: flex;height: 100%">
|
||||
@ -23,14 +23,15 @@
|
||||
<span>{{ $t('chart.dimension') }}</span>
|
||||
<draggable
|
||||
v-model="dimension"
|
||||
:options="{group:{name: 'itxst',pull:'clone'},sort: true}"
|
||||
:options="{group:{name: 'dimension',pull:'clone'},sort: true}"
|
||||
animation="300"
|
||||
:move="onMove"
|
||||
style="height: 90%;overflow:auto"
|
||||
@end="end1"
|
||||
@start="start1"
|
||||
>
|
||||
<transition-group>
|
||||
<span v-for="item in dimension" :key="item.id" class="item" @click="click1(item)">{{ item.name }}</span>
|
||||
<span v-for="item in dimension" :key="item.id" class="item">{{ item.name }}</span>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</div>
|
||||
@ -38,14 +39,15 @@
|
||||
<span>{{ $t('chart.quota') }}</span>
|
||||
<draggable
|
||||
v-model="quota"
|
||||
:options="{group:{name: 'itxst',pull:'clone'},sort: true}"
|
||||
:options="{group:{name: 'quota',pull:'clone'},sort: true}"
|
||||
animation="300"
|
||||
:move="onMove"
|
||||
style="height: 90%;overflow:auto"
|
||||
@end="end2"
|
||||
@end="end1"
|
||||
@start="start1"
|
||||
>
|
||||
<transition-group>
|
||||
<span v-for="item in quota" :key="item.id" class="item" @click="click2(item)">{{ item.name }}</span>
|
||||
<span v-for="item in quota" :key="item.id" class="item">{{ item.name }}</span>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</div>
|
||||
@ -67,6 +69,7 @@
|
||||
:placeholder="$t('chart.title')"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@blur="save"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -97,58 +100,38 @@
|
||||
<el-row style="width: 100%;height: 100%;" class="padding-lr">
|
||||
<el-row style="margin-top: 10px;">
|
||||
<el-row style="display:flex;height: 32px;">
|
||||
<span style="line-height: 32px;width: 60px;text-align: right;">{{ $t('chart.x_axis') }}</span>
|
||||
<span style="line-height: 32px;width: 60px;text-align: right;">{{ $t('chart.dimension') }}</span>
|
||||
<draggable
|
||||
v-model="view.xaxis"
|
||||
group="itxst"
|
||||
group="dimension"
|
||||
animation="300"
|
||||
:move="onMove"
|
||||
style="width:100%;height: 100%;margin:0 10px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;"
|
||||
@end="end3"
|
||||
style="width:100%;height: 100%;margin:0 10px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;"
|
||||
@end="end2"
|
||||
>
|
||||
<transition-group style="width: 100%;height: 100%;">
|
||||
<el-tag
|
||||
v-for="(item,index) in view.xaxis"
|
||||
:key="index"
|
||||
size="small"
|
||||
class="item-axis"
|
||||
closable
|
||||
@close="clear1(index)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
<transition-group class="draggable-group">
|
||||
<dimension-item v-for="(item) in view.xaxis" :key="item.id" :item="item" />
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</el-row>
|
||||
<el-row style="display:flex;height: 32px;margin-top: 10px;">
|
||||
<span style="line-height: 32px;width: 60px;text-align: right;">{{ $t('chart.y_axis') }}</span>
|
||||
<span style="line-height: 32px;width: 60px;text-align: right;">{{ $t('chart.quota') }}</span>
|
||||
<draggable
|
||||
v-model="view.yaxis"
|
||||
group="itxst"
|
||||
group="quota"
|
||||
animation="300"
|
||||
:move="onMove"
|
||||
style="width:100%;height: 100%;margin:0 10px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;"
|
||||
@end="end4"
|
||||
style="width:100%;height: 100%;margin:0 10px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;"
|
||||
@end="end2"
|
||||
>
|
||||
<transition-group style="width:100%;height: 100%;">
|
||||
<el-tag
|
||||
v-for="(item,index) in view.yaxis"
|
||||
:key="index"
|
||||
size="small"
|
||||
class="item-axis"
|
||||
closable
|
||||
@close="clear2(index)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
<transition-group class="draggable-group">
|
||||
<quota-item v-for="(item) in view.yaxis" :key="item.id" :item="item" @onQuotaSummaryChange="quotaSummaryChange" />
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</el-row>
|
||||
</el-row>
|
||||
|
||||
<div class="Echarts" style="height: 100%;display: flex;margin-top: 10px;">
|
||||
<div id="echart" style="width: 100%;height: 80vh;"/>
|
||||
</div>
|
||||
<chart-component :chart="chart" />
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -158,11 +141,13 @@
|
||||
<script>
|
||||
import { post } from '@/api/dataset/dataset'
|
||||
import draggable from 'vuedraggable'
|
||||
import { BASE_BAR } from '../chart/chart'
|
||||
import DimensionItem from '../components/DimensionItem'
|
||||
import QuotaItem from '../components/QuotaItem'
|
||||
import ChartComponent from '../components/ChartComponent'
|
||||
|
||||
export default {
|
||||
name: 'ChartEdit',
|
||||
components: { draggable },
|
||||
components: { ChartComponent, QuotaItem, DimensionItem, draggable },
|
||||
data() {
|
||||
return {
|
||||
table: {},
|
||||
@ -186,7 +171,8 @@ export default {
|
||||
arr2: [
|
||||
{ id: 11, name: '容量' }
|
||||
],
|
||||
moveId: -1
|
||||
moveId: -1,
|
||||
chart: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -206,7 +192,13 @@ export default {
|
||||
}
|
||||
|
||||
},
|
||||
watch: {},
|
||||
watch: {
|
||||
'view.type': {
|
||||
handler: function() {
|
||||
this.save()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.get(this.$store.state.chart.viewId);
|
||||
},
|
||||
@ -232,32 +224,6 @@ export default {
|
||||
this.quota = response.data.quota
|
||||
})
|
||||
},
|
||||
click1(item) {
|
||||
// console.log(item);
|
||||
const c = this.view.xaxis.filter(function(ele) {
|
||||
return ele.id === item.id
|
||||
})
|
||||
// console.log(c);
|
||||
if (c && c.length === 0) {
|
||||
this.view.xaxis.push(item)
|
||||
}
|
||||
},
|
||||
click2(item) {
|
||||
// console.log(item);
|
||||
const c = this.view.yaxis.filter(function(ele) {
|
||||
return ele.id === item.id
|
||||
})
|
||||
// console.log(c);
|
||||
if (c && c.length === 0) {
|
||||
this.view.yaxis.push(item)
|
||||
}
|
||||
},
|
||||
clear1(index) {
|
||||
this.view.xaxis.splice(index, 1)
|
||||
},
|
||||
clear2(index) {
|
||||
this.view.yaxis.splice(index, 1)
|
||||
},
|
||||
get(id) {
|
||||
if (id) {
|
||||
post('/chart/view/get/' + id, null).then(response => {
|
||||
@ -275,6 +241,16 @@ export default {
|
||||
view.sceneId = this.sceneId
|
||||
view.name = this.table.name
|
||||
view.tableId = this.$store.state.chart.tableId
|
||||
view.xaxis.forEach(function(ele) {
|
||||
if (!ele.summary || ele.summary === '') {
|
||||
ele.summary = 'sum'
|
||||
}
|
||||
})
|
||||
view.yaxis.forEach(function(ele) {
|
||||
if (!ele.summary || ele.summary === '') {
|
||||
ele.summary = 'sum'
|
||||
}
|
||||
})
|
||||
view.xaxis = JSON.stringify(view.xaxis)
|
||||
view.yaxis = JSON.stringify(view.yaxis)
|
||||
post('/chart/view/save', view).then(response => {
|
||||
@ -284,26 +260,17 @@ export default {
|
||||
this.$store.dispatch('chart/setChartSceneData', this.sceneId)
|
||||
})
|
||||
},
|
||||
closeEdit() {
|
||||
this.$emit('switchComponent', { name: '' })
|
||||
},
|
||||
getData(id) {
|
||||
if (id) {
|
||||
post('/chart/view/getData/' + id, null).then(response => {
|
||||
this.view = response.data
|
||||
this.view.xaxis = this.view.xaxis ? JSON.parse(this.view.xaxis) : []
|
||||
this.view.yaxis = this.view.yaxis ? JSON.parse(this.view.yaxis) : []
|
||||
|
||||
const chart = response.data
|
||||
const chart_option = JSON.parse(JSON.stringify(BASE_BAR))
|
||||
// console.log(chart_option);
|
||||
if (chart.data) {
|
||||
chart_option.title.text = chart.title
|
||||
chart_option.xAxis.data = chart.data.x
|
||||
chart.data.series.forEach(function(y) {
|
||||
chart_option.legend.data.push(y.name)
|
||||
chart_option.series.push(y)
|
||||
})
|
||||
}
|
||||
// console.log(chart_option);
|
||||
this.myEcharts(chart_option)
|
||||
// 将视图传入echart组件
|
||||
this.chart = response.data
|
||||
})
|
||||
} else {
|
||||
this.view = {}
|
||||
@ -311,37 +278,77 @@ export default {
|
||||
},
|
||||
|
||||
// 左边往右边拖动时的事件
|
||||
start1(e) {
|
||||
console.log(e)
|
||||
e.clone.className = 'item-on-move'
|
||||
e.item.className = 'item-on-move'
|
||||
},
|
||||
end1(e) {
|
||||
// console.log(e)
|
||||
// var that = this;
|
||||
// var items = this.arr2.filter(function (m) {
|
||||
// return m.id == that.moveId
|
||||
// })
|
||||
// //如果左边
|
||||
// if (items.length < 2) return;
|
||||
// this.arr2.splice(e.newDraggableIndex, 1)
|
||||
console.log(e)
|
||||
e.clone.className = 'item'
|
||||
e.item.className = 'item'
|
||||
this.refuseMove(e)
|
||||
this.removeCheckedKey(e)
|
||||
this.save()
|
||||
},
|
||||
start2(e) {
|
||||
console.log(e)
|
||||
},
|
||||
// 右边往左边拖动时的事件
|
||||
end2(e) {
|
||||
// console.log(e)
|
||||
// var that = this;
|
||||
// var items = this.yAxisData.filter(function (m) {
|
||||
// return m.id == that.moveId
|
||||
// })
|
||||
// //如果左边
|
||||
// if (items.length < 2) return;
|
||||
// this.yAxisData.splice(e.newDraggableIndex, 1)
|
||||
console.log(e)
|
||||
this.removeDuplicateKey(e)
|
||||
this.save()
|
||||
},
|
||||
end3(e) {
|
||||
|
||||
removeCheckedKey(e) {
|
||||
const that = this
|
||||
const xItems = this.view.xaxis.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
const yItems = this.view.yaxis.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
if (xItems && xItems.length > 1) {
|
||||
this.view.xaxis.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
if (yItems && yItems.length > 1) {
|
||||
this.view.yaxis.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
},
|
||||
end4(e) {
|
||||
|
||||
refuseMove(e) {
|
||||
const that = this
|
||||
const xItems = this.dimension.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
const yItems = this.quota.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
if (xItems && xItems.length > 1) {
|
||||
this.dimension.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
if (yItems && yItems.length > 1) {
|
||||
this.quota.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
},
|
||||
removeDuplicateKey(e) {
|
||||
const that = this
|
||||
const xItems = this.dimension.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
const yItems = this.quota.filter(function(m) {
|
||||
return m.id === that.moveId
|
||||
})
|
||||
if (xItems && xItems.length > 0) {
|
||||
this.dimension.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
if (yItems && yItems.length > 0) {
|
||||
this.quota.splice(e.newDraggableIndex, 1)
|
||||
}
|
||||
},
|
||||
// move回调方法
|
||||
onMove(e, originalEvent) {
|
||||
console.log(e)
|
||||
// this.moveId = e.relatedContext.element.id;
|
||||
this.moveId = e.draggedContext.element.id
|
||||
// //不允许停靠
|
||||
// if (e.relatedContext.element.id == 1) return false;
|
||||
// //不允许拖拽
|
||||
@ -350,14 +357,14 @@ export default {
|
||||
return true
|
||||
},
|
||||
|
||||
myEcharts(option) {
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
var myChart = this.$echarts.init(document.getElementById('echart'))
|
||||
// 指定图表的配置项和数据
|
||||
setTimeout(myChart.setOption(option, true), 500)
|
||||
window.onresize = function() {
|
||||
myChart.resize()
|
||||
}
|
||||
quotaSummaryChange(item) {
|
||||
// 更新item
|
||||
this.view.yaxis.forEach(function(ele) {
|
||||
if (ele.id === item.id) {
|
||||
ele.summary = item.summary
|
||||
}
|
||||
})
|
||||
this.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -387,34 +394,30 @@ export default {
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 2px 12px;
|
||||
padding: 3px 10px;
|
||||
margin: 3px 3px 0 3px;
|
||||
border: solid 1px #eee;
|
||||
background-color: #f1f1f1;
|
||||
text-align: left;
|
||||
color: #606266;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.item-on-move {
|
||||
padding: 3px 10px;
|
||||
margin: 3px 3px 0 3px;
|
||||
border: solid 1px #eee;
|
||||
text-align: left;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.item + .item {
|
||||
border-top: none;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
background-color: #fdfdfd;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item-axis {
|
||||
padding: 2px 12px;
|
||||
margin: 3px 3px 0 3px;
|
||||
border: solid 1px #eee;
|
||||
background-color: #f1f1f1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.item-axis:hover {
|
||||
background-color: #fdfdfd;
|
||||
color: #1890ff;
|
||||
background: #e8f4ff;
|
||||
border-color: #a3d3ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -425,4 +428,10 @@ export default {
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.draggable-group {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: calc(100% - 6px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
<el-row>
|
||||
<el-form :inline="true">
|
||||
<el-form-item class="form-item">
|
||||
@ -45,7 +45,7 @@
|
||||
<el-row style="overflow: auto;height: 600px;">
|
||||
<el-checkbox-group v-model="checkTableList" size="small">
|
||||
<el-checkbox
|
||||
v-for="t in tables"
|
||||
v-for="t in tableData"
|
||||
:key="t"
|
||||
border
|
||||
:label="t"
|
||||
@ -60,10 +60,10 @@
|
||||
import { listDatasource, post } from '@/api/dataset/dataset'
|
||||
|
||||
export default {
|
||||
name: 'AddDB',
|
||||
props: {
|
||||
param: Object
|
||||
},
|
||||
name: 'AddDB',
|
||||
data() {
|
||||
return {
|
||||
searchTable: '',
|
||||
@ -71,7 +71,8 @@ export default {
|
||||
dataSource: '',
|
||||
tables: [],
|
||||
checkTableList: [],
|
||||
mode: '0'
|
||||
mode: '0',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -79,8 +80,16 @@ export default {
|
||||
if (val) {
|
||||
post('/datasource/getTables', { id: val }).then(response => {
|
||||
this.tables = response.data
|
||||
this.tableData = JSON.parse(JSON.stringify(this.tables))
|
||||
})
|
||||
}
|
||||
},
|
||||
searchTable(val) {
|
||||
if (val && val !== '') {
|
||||
this.tableData = JSON.parse(JSON.stringify(this.tables.filter(ele => { return ele.includes(val) })))
|
||||
} else {
|
||||
this.tableData = JSON.parse(JSON.stringify(this.tables))
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
{{ $t('dataset.datalist') }}
|
||||
</span>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
|
||||
<el-row>
|
||||
<el-form>
|
||||
@ -59,7 +59,7 @@
|
||||
{{ $t('dataset.back') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
<el-row>
|
||||
<el-form>
|
||||
<el-form-item class="form-item">
|
||||
@ -85,8 +85,8 @@
|
||||
({{ data.type }})
|
||||
</span>
|
||||
<span>
|
||||
<span v-if="data.mode === 0" style="margin-left: 6px"><i class="el-icon-s-operation"/></span>
|
||||
<span v-if="data.mode === 1" style="margin-left: 6px"><i class="el-icon-time"/></span>
|
||||
<span v-if="data.mode === 0" style="margin-left: 6px"><i class="el-icon-s-operation" /></span>
|
||||
<span v-if="data.mode === 1" style="margin-left: 6px"><i class="el-icon-time" /></span>
|
||||
</span>
|
||||
<span style="margin-left: 6px">{{ data.name }}</span>
|
||||
</span>
|
||||
|
||||
@ -109,7 +109,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="taskForm.rate === '1'" label="">
|
||||
<el-input v-model="taskForm.cron" size="mini" style="width: 50%"/>
|
||||
<el-input v-model="taskForm.cron" size="mini" style="width: 50%" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dataset.end_time')" prop="end">
|
||||
<el-select v-model="taskForm.end" size="mini" :disabled="taskForm.rate === '0'">
|
||||
|
||||
@ -15,17 +15,17 @@
|
||||
<!-- </el-button>-->
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
|
||||
<el-tabs v-model="tabActive">
|
||||
<el-tab-pane :label="$t('dataset.data_preview')" name="dataPreview">
|
||||
<tab-data-preview :table="table" :fields="fields" :data="data"/>
|
||||
<tab-data-preview :table="table" :fields="fields" :data="data" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('dataset.join_view')" name="joinView">
|
||||
关联视图 TODO
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('dataset.update_info')" name="updateInfo">
|
||||
<update-info :table="table"/>
|
||||
<el-tab-pane v-if="table.mode === 1" :label="$t('dataset.update_info')" name="updateInfo">
|
||||
<update-info :table="table" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
@ -40,17 +40,17 @@
|
||||
</el-table-column>
|
||||
<el-table-column property="name" :label="$t('dataset.field_name')" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.name" size="mini"/>
|
||||
<el-input v-model="scope.row.name" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="originName" :label="$t('dataset.field_origin_name')" width="180"/>
|
||||
<el-table-column property="originName" :label="$t('dataset.field_origin_name')" width="180" />
|
||||
<el-table-column property="checked" :label="$t('dataset.field_check')" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-checkbox v-model="scope.row.checked"/>
|
||||
<el-checkbox v-model="scope.row.checked" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!--下面这一列占位-->
|
||||
<el-table-column property=""/>
|
||||
<el-table-column property="" />
|
||||
</el-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="mini" @click="closeEdit">{{ $t('dataset.cancel') }}</el-button>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
{{ $t('dataset.datalist') }}
|
||||
</span>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
|
||||
<el-row>
|
||||
<el-button icon="el-icon-circle-plus" type="primary" size="mini" @click="add('group')">
|
||||
@ -103,7 +103,7 @@
|
||||
<el-dialog :title="dialogTitle" :visible="editGroup" :show-close="false" width="30%">
|
||||
<el-form ref="groupForm" :model="groupForm" :rules="groupFormRules">
|
||||
<el-form-item :label="$t('commons.name')" prop="name">
|
||||
<el-input v-model="groupForm.name"/>
|
||||
<el-input v-model="groupForm.name" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
@ -124,7 +124,7 @@
|
||||
{{ $t('dataset.back') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-divider/>
|
||||
<el-divider />
|
||||
<el-row>
|
||||
<el-dropdown style="margin-right: 10px;" size="small" trigger="click" @command="clickAddData">
|
||||
<el-button type="primary" size="mini" plain>
|
||||
@ -178,8 +178,8 @@
|
||||
({{ data.type }})
|
||||
</span>
|
||||
<span>
|
||||
<span v-if="data.mode === 0" style="margin-left: 6px"><i class="el-icon-s-operation"/></span>
|
||||
<span v-if="data.mode === 1" style="margin-left: 6px"><i class="el-icon-time"/></span>
|
||||
<span v-if="data.mode === 0" style="margin-left: 6px"><i class="el-icon-s-operation" /></span>
|
||||
<span v-if="data.mode === 1" style="margin-left: 6px"><i class="el-icon-time" /></span>
|
||||
</span>
|
||||
<span style="margin-left: 6px">{{ data.name }}</span>
|
||||
</span>
|
||||
@ -213,12 +213,12 @@
|
||||
<el-dialog :title="$t('dataset.table')" :visible="editTable" :show-close="false" width="30%">
|
||||
<el-form ref="tableForm" :model="tableForm" :rules="tableFormRules">
|
||||
<el-form-item :label="$t('commons.name')" prop="name">
|
||||
<el-input v-model="tableForm.name"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dataset.mode')" prop="mode">
|
||||
<el-radio v-model="tableForm.mode" label="0">{{ $t('dataset.direct_connect') }}</el-radio>
|
||||
<el-radio v-model="tableForm.mode" label="1">{{ $t('dataset.sync_data') }}</el-radio>
|
||||
<el-input v-model="tableForm.name" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item :label="$t('dataset.mode')" prop="mode">-->
|
||||
<!-- <el-radio v-model="tableForm.mode" label="0">{{ $t('dataset.direct_connect') }}</el-radio>-->
|
||||
<!-- <el-radio v-model="tableForm.mode" label="1">{{ $t('dataset.sync_data') }}</el-radio>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="mini" @click="closeTable()">{{ $t('dataset.cancel') }}</el-button>
|
||||
|
||||
@ -79,8 +79,12 @@ export default {
|
||||
},
|
||||
loading: false,
|
||||
passwordType: 'password',
|
||||
redirect: undefined,
|
||||
msg: null
|
||||
redirect: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
msg() {
|
||||
return this.$store.state.user.loginMsg
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@ -1,73 +1,63 @@
|
||||
<template>
|
||||
<div v-loading="result.loading">
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('organization.create')"
|
||||
:title="$t('commons.organization')"
|
||||
@search="initTableData"
|
||||
@create="create"
|
||||
/>
|
||||
<complex-table
|
||||
ref="table"
|
||||
:data="tableData"
|
||||
:lazy="isLazy"
|
||||
:load="loadExpandDatas"
|
||||
:columns="columns"
|
||||
:buttons="buttons"
|
||||
:header="header"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
:default-expand-all="isTableExpand"
|
||||
row-key="deptId"
|
||||
@search="search"
|
||||
>
|
||||
<template #buttons>
|
||||
<fu-table-button icon="el-icon-circle-plus-outline" :label="$t('organization.create')" @click="create" />
|
||||
</template>
|
||||
<!-- system menu organization table-->
|
||||
<el-table
|
||||
ref="table"
|
||||
border
|
||||
class="adjust-table"
|
||||
:data="tableData"
|
||||
lazy
|
||||
:load="initTableData"
|
||||
style="width: 100%"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
row-key="deptId"
|
||||
>
|
||||
<!-- <el-table-column :selectable="checkboxT" type="selection" width="55" /> -->
|
||||
<el-table-column label="名称" prop="name" />
|
||||
<el-table-column label="下属部门数" prop="subCount" />
|
||||
<el-table-column label="状态" align="center" prop="enabled">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.enabled"
|
||||
:disabled="scope.row.id === 1"
|
||||
active-color="#409EFF"
|
||||
inactive-color="#F56C6C"
|
||||
@change="changeEnabled(scope.row, scope.row.enabled,)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建日期">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
<!-- <el-table-column type="selection" fix /> -->
|
||||
<el-table-column label="名称" prop="name" />
|
||||
<el-table-column label="下属组织数" prop="subCount" />
|
||||
<!-- <el-table-column label="状态" align="center" prop="enabled">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.enabled"
|
||||
:disabled="scope.row.id === 1"
|
||||
active-color="#409EFF"
|
||||
inactive-color="#F56C6C"
|
||||
@change="changeEnabled(scope.row, scope.row.enabled,)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column prop="createTime" label="创建日期">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-card>
|
||||
<fu-table-operations :buttons="buttons" label="操作" fix />
|
||||
</complex-table>
|
||||
|
||||
<!-- add organization form -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="formType=='add' ? $t('organization.create') : $t('organization.modify')"
|
||||
:visible.sync="dialogOrgAddVisible"
|
||||
width="30%"
|
||||
width="500px"
|
||||
:destroy-on-close="true"
|
||||
@closed="closeFunc"
|
||||
>
|
||||
<el-form ref="createOrganization" inline :model="form" :rules="rule" size="small" label-width="80px">
|
||||
|
||||
<el-form-item label="部门名称" prop="name">
|
||||
<el-form-item label="组织名称" prop="name">
|
||||
<el-input v-model="form.name" style="width: 370px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门排序" prop="deptSort">
|
||||
<el-form-item label="组织排序" prop="deptSort">
|
||||
<el-input-number
|
||||
v-model.number="form.deptSort"
|
||||
:min="0"
|
||||
@ -77,7 +67,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="顶级部门" prop="top">
|
||||
<el-form-item label="顶级组织" prop="top">
|
||||
<el-radio-group v-model="form.top" style="width: 140px">
|
||||
<el-radio :label="true">是</el-radio>
|
||||
<el-radio :label="false">否</el-radio>
|
||||
@ -85,14 +75,14 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态" prop="enabled">
|
||||
<el-radio-group v-model="form.enabled" style="width: 140px">
|
||||
<el-radio-group v-model="form.enabled" style="width: 140px" disabled>
|
||||
<el-radio :label="true">启用</el-radio>
|
||||
<el-radio :label="false">停用</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<!-- <el-radio v-for="item in dict.dept_status" :key="item.id" v-model="form.enabled" :label="item.value">{{ item.label }}</el-radio> -->
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!form.top" style="margin-bottom: 0;" label="上级部门" prop="pid">
|
||||
<el-form-item v-if="!form.top" style="margin-bottom: 0;" label="上级组织" prop="pid">
|
||||
<treeselect
|
||||
v-model="form.pid"
|
||||
:auto-load-root-options="false"
|
||||
@ -103,44 +93,32 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||
</div> -->
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogOrgAddVisible = false"
|
||||
@confirm="createDept('createOrganization')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="dialogOrgAddVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="createDept('createOrganization')">确认</el-button>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
<ms-delete-confirm ref="deleteConfirm" :title="$t('organization.delete')" @delete="_handleDelete" />
|
||||
|
||||
</div>
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import { formatCondition } from '@/utils/index'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import { LOAD_CHILDREN_OPTIONS, LOAD_ROOT_OPTIONS } from '@riophae/vue-treeselect'
|
||||
import MsTableHeader from '@/metersphere/common/components/MsTableHeader'
|
||||
import MsTableOperator from '@/metersphere/common/components/MsTableOperator'
|
||||
import MsDialogFooter from '@/metersphere/common/components/MsDialogFooter'
|
||||
import {
|
||||
listenGoBack,
|
||||
removeGoBackListener
|
||||
} from '@/metersphere/common/js/utils'
|
||||
import MsDeleteConfirm from '@/metersphere/common/components/MsDeleteConfirm'
|
||||
import { getDeptTree, addDept, editDept, delDept } from '@/api/system/dept'
|
||||
|
||||
import { getDeptTree, addDept, editDept, delDept, loadTable } from '@/api/system/dept'
|
||||
|
||||
export default {
|
||||
name: 'MsOrganization',
|
||||
components: {
|
||||
MsDeleteConfirm,
|
||||
MsTableHeader,
|
||||
MsTableOperator,
|
||||
MsDialogFooter,
|
||||
LayoutContent,
|
||||
ComplexTable,
|
||||
Treeselect
|
||||
},
|
||||
data() {
|
||||
@ -155,7 +133,6 @@ export default {
|
||||
changeStatusPath: '/api/dept/updateStatus',
|
||||
result: {},
|
||||
dialogOrgAddVisible: false,
|
||||
condition: {},
|
||||
tableData: [],
|
||||
maps: new Map(),
|
||||
oldPid: null,
|
||||
@ -173,30 +150,55 @@ export default {
|
||||
add: ['dept:add'],
|
||||
edit: ['dept:edit'],
|
||||
del: ['dept:del']
|
||||
}
|
||||
},
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
{
|
||||
label: this.$t('commons.edit'), icon: 'el-icon-edit', click: this.edit
|
||||
}, {
|
||||
label: this.$t('commons.delete'), icon: 'el-icon-delete', type: 'danger', click: this._handleDelete
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
useQuickSearch: true,
|
||||
useComplexSearch: false,
|
||||
quickPlaceholder: '按名称搜索',
|
||||
components: [
|
||||
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
defaultCondition: {
|
||||
field: 'pid',
|
||||
operator: 'eq',
|
||||
value: 0
|
||||
},
|
||||
defaultForm: { deptId: null, top: true, enabled: true, pid: null },
|
||||
isTableExpand: false,
|
||||
isLazy: true
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.initTableData()
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
create() {
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.dialogOrgAddVisible = true
|
||||
this.formType = 'add'
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
search(condition) {
|
||||
console.log(condition)
|
||||
},
|
||||
|
||||
edit(row) {
|
||||
this.dialogOrgAddVisible = true
|
||||
this.formType = 'modify'
|
||||
this.oldPid = row.pid
|
||||
this.form = Object.assign({}, row)
|
||||
this.treeByRow(row)
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
|
||||
treeByRow(row) {
|
||||
@ -240,35 +242,127 @@ export default {
|
||||
return roots
|
||||
},
|
||||
|
||||
initTableData(row, treeNode, resolve) {
|
||||
const _self = this
|
||||
const pid = row ? row.deptId : '0'
|
||||
getDeptTree(pid).then(response => {
|
||||
let data = response.data
|
||||
quick_condition(condition) {
|
||||
const result = {}
|
||||
if (condition && condition.quick) {
|
||||
for (const [key, value] of Object.entries(condition)) {
|
||||
// console.log(`${key}`)
|
||||
if (`${key}` === 'quick') {
|
||||
const v_new = Object.assign({}, value)
|
||||
v_new['field'] = 'name'
|
||||
result['name'] = v_new
|
||||
} else {
|
||||
result[`${key}`] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
return Object.assign({}, condition)
|
||||
},
|
||||
|
||||
setTableAttr(isSearch) {
|
||||
if (isSearch) {
|
||||
this.lazy = false
|
||||
this.isTableExpand = true
|
||||
} else {
|
||||
this.lazy = true
|
||||
this.isTableExpand = false
|
||||
}
|
||||
},
|
||||
// 加载表格数据
|
||||
search(condition) {
|
||||
this.setTableAttr()
|
||||
this.tableData = []
|
||||
let param = {}
|
||||
if (condition && condition.quick) {
|
||||
const con = this.quick_condition(condition)
|
||||
param = formatCondition(con)
|
||||
} else {
|
||||
param = { conditions: [this.defaultCondition] }
|
||||
}
|
||||
|
||||
// param.conditions.push(this.defaultCondition)
|
||||
loadTable(param).then(res => {
|
||||
let data = res.data
|
||||
data = data.map(obj => {
|
||||
if (obj.subCount > 0) {
|
||||
obj.hasChildren = true
|
||||
}
|
||||
return obj
|
||||
})
|
||||
if (!row) {
|
||||
data.some(node => {
|
||||
node.children = null
|
||||
})
|
||||
_self.tableData = data
|
||||
_self.depts = null
|
||||
} else {
|
||||
this.maps.set(row.deptId, { row, treeNode, resolve })
|
||||
resolve && resolve(data)
|
||||
|
||||
if (condition && condition.quick) {
|
||||
data = this.buildTree(data)
|
||||
this.setTableAttr(true)
|
||||
}
|
||||
this.tableData = data
|
||||
this.depts = null
|
||||
})
|
||||
},
|
||||
|
||||
buildTree(arrs) {
|
||||
const idMapping = arrs.reduce((acc, el, i) => {
|
||||
acc[el.deptId] = i
|
||||
return acc
|
||||
}, {})
|
||||
const roots = []
|
||||
arrs.forEach(el => {
|
||||
// 判断根节点
|
||||
if (el.pid === null || el.pid === 0) {
|
||||
roots.push(el)
|
||||
return
|
||||
}
|
||||
// 用映射表找到父元素
|
||||
const parentEl = arrs[idMapping[el.pid]]
|
||||
// 把当前元素添加到父元素的`children`数组中
|
||||
parentEl.children = [...(parentEl.children || []), el]
|
||||
})
|
||||
return roots
|
||||
},
|
||||
|
||||
// 加载下一级子节点数据
|
||||
loadExpandDatas(row, treeNode, resolve) {
|
||||
getDeptTree(row.deptId).then(res => {
|
||||
let data = res.data
|
||||
data = data.map(obj => {
|
||||
if (obj.subCount > 0) {
|
||||
obj.hasChildren = true
|
||||
}
|
||||
return obj
|
||||
})
|
||||
this.maps.set(row.deptId, { row, treeNode, resolve })
|
||||
resolve && resolve(data)
|
||||
})
|
||||
},
|
||||
|
||||
// initTableData(row, treeNode, resolve) {
|
||||
// const _self = this
|
||||
// const pid = (row && row.deptId) ? row.deptId : '0'
|
||||
// getDeptTree(pid).then(response => {
|
||||
// let data = response.data
|
||||
// data = data.map(obj => {
|
||||
// if (obj.subCount > 0) {
|
||||
// obj.hasChildren = true
|
||||
// }
|
||||
// return obj
|
||||
// })
|
||||
// if (!row) {
|
||||
// data.some(node => {
|
||||
// node.children = null
|
||||
// })
|
||||
// _self.tableData = data
|
||||
// _self.depts = null
|
||||
// } else {
|
||||
// this.maps.set(row.deptId, { row, treeNode, resolve })
|
||||
// resolve && resolve(data)
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
closeFunc() {
|
||||
this.initTableData()
|
||||
this.search()
|
||||
this.form = {}
|
||||
this.oldPid = null
|
||||
this.depts = null
|
||||
removeGoBackListener(this.closeFunc)
|
||||
this.dialogOrgAddVisible = false
|
||||
},
|
||||
|
||||
@ -307,12 +401,12 @@ export default {
|
||||
id: node.deptId,
|
||||
pid: node.pid,
|
||||
label: node.name,
|
||||
children: node.children
|
||||
children: node.children || null
|
||||
}
|
||||
},
|
||||
// 改变状态
|
||||
changeEnabled(data, val) {
|
||||
this.$confirm('此操作将 "停用" ' + data.name + '部门, 是否继续?', '提示', {
|
||||
this.$confirm('此操作将 "停用" ' + data.name + '组织, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
@ -334,7 +428,7 @@ export default {
|
||||
if (this.formType !== 'modify') {
|
||||
addDept(this.form).then(res => {
|
||||
this.$success(this.$t('commons.save_success'))
|
||||
this.initTableData()
|
||||
this.search()
|
||||
this.oldPid && this.reloadByPid(this.oldPid)
|
||||
this.reloadByPid(this.form['pid'])
|
||||
this.dialogOrgAddVisible = false
|
||||
@ -342,7 +436,7 @@ export default {
|
||||
} else {
|
||||
editDept(this.form).then(res => {
|
||||
this.$success(this.$t('commons.save_success'))
|
||||
this.initTableData()
|
||||
this.search()
|
||||
this.oldPid && this.reloadByPid(this.oldPid)
|
||||
this.reloadByPid(this.form['pid'])
|
||||
this.dialogOrgAddVisible = false
|
||||
@ -353,9 +447,7 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(organization) {
|
||||
this.$refs.deleteConfirm.open(organization)
|
||||
},
|
||||
|
||||
_handleDelete(organization) {
|
||||
this.$confirm(this.$t('organization.delete_confirm'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
@ -365,7 +457,7 @@ export default {
|
||||
const requests = [{ deptId: organization.deptId, pid: organization.pid }]
|
||||
delDept(requests).then(res => {
|
||||
this.$success(this.$t('commons.delete_success'))
|
||||
this.initTableData()
|
||||
this.search()
|
||||
this.reloadByPid(organization.pid)
|
||||
})
|
||||
}).catch(() => {
|
||||
@ -379,7 +471,7 @@ export default {
|
||||
if (pid !== 0 && this.maps.get(pid)) {
|
||||
const { row, treeNode, resolve } = this.maps.get(pid)
|
||||
this.$set(this.$refs.table.store.states.lazyTreeNodeMap, pid, [])
|
||||
this.initTableData(row, treeNode, resolve)
|
||||
this.loadExpandDatas(row, treeNode, resolve)
|
||||
}
|
||||
},
|
||||
array2Tree(arr) {
|
||||
@ -407,7 +499,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "~@/metersphere/common/css/index.css";
|
||||
.member-size {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@ -1,70 +1,59 @@
|
||||
<template>
|
||||
<div v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('menu.create')"
|
||||
:title="$t('commons.menu')"
|
||||
@search="initTableData"
|
||||
@create="create"
|
||||
/>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<complex-table
|
||||
ref="table"
|
||||
:data="tableData"
|
||||
lazy
|
||||
:load="initTableData"
|
||||
:columns="columns"
|
||||
:buttons="buttons"
|
||||
:header="header"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
row-key="menuId"
|
||||
@search="initTableData"
|
||||
>
|
||||
<template #buttons>
|
||||
<fu-table-button icon="el-icon-circle-plus-outline" :label="$t('menu.create')" @click="create" />
|
||||
</template>
|
||||
<el-table
|
||||
ref="table"
|
||||
border
|
||||
class="adjust-table"
|
||||
:data="tableData"
|
||||
lazy
|
||||
:load="initTableData"
|
||||
style="width: 100%"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
row-key="menuId"
|
||||
>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" label="菜单标题" width="150px" prop="title" />
|
||||
<el-table-column prop="icon" label="图标" align="center" width="60px">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon :icon-class="scope.row.icon ? scope.row.icon : ''" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column type="selection" fix /> -->
|
||||
<el-table-column :show-overflow-tooltip="true" label="菜单标题" width="150px" prop="title" />
|
||||
<el-table-column prop="icon" label="图标" align="center" width="60px">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon :icon-class="scope.row.icon ? scope.row.icon : ''" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" prop="permission" label="权限标识" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="component" label="组件路径" />
|
||||
<el-table-column prop="iframe" label="外链" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.iframe">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="cache" label="缓存" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.cache">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hidden" label="可见" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.hidden">否</span>
|
||||
<span v-else>是</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建日期" width="160px">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :show-overflow-tooltip="true" prop="permission" label="权限标识" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="component" label="组件路径" />
|
||||
<!-- <el-table-column prop="iframe" label="外链" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.iframe">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="cache" label="缓存" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.cache">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hidden" label="可见" width="75px">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.hidden">否</span>
|
||||
<span v-else>是</span>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column prop="createTime" label="创建日期" width="160px">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</el-card>
|
||||
<fu-table-operations :buttons="buttons" label="操作" fix />
|
||||
</complex-table>
|
||||
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
@ -97,7 +86,7 @@
|
||||
</el-input>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="form.type !== '2'" label="外链菜单" prop="iframe">
|
||||
<!-- <el-form-item v-show="form.type !== '2'" label="外链菜单" prop="iframe">
|
||||
<el-radio-group v-model="form.iframe" size="mini">
|
||||
<el-radio-button label="true">是</el-radio-button>
|
||||
<el-radio-button label="false">否</el-radio-button>
|
||||
@ -114,7 +103,7 @@
|
||||
<el-radio-button label="false">是</el-radio-button>
|
||||
<el-radio-button label="true">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item v-if="form.type !== '2'" label="菜单标题" prop="title">
|
||||
<el-input v-model="form.title" :style=" form.type === '0' ? 'width: 450px' : 'width: 179px'" placeholder="菜单标题" />
|
||||
</el-form-item>
|
||||
@ -146,43 +135,37 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="dialogVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="createMenu('menuForm')">确认</el-button>
|
||||
</div>
|
||||
<!-- <template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogVisible = false"
|
||||
@confirm="createMenu('menuForm')"
|
||||
/>
|
||||
</template>
|
||||
</template> -->
|
||||
</el-dialog>
|
||||
|
||||
<ms-delete-confirm ref="deleteConfirm" :title="$t('menu.delete')" @delete="_handleDelete" />
|
||||
|
||||
</div>
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
// import { checkPermission } from '@/utils/permission'
|
||||
import IconSelect from '@/components/IconSelect'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import { LOAD_CHILDREN_OPTIONS, LOAD_ROOT_OPTIONS } from '@riophae/vue-treeselect'
|
||||
import MsTableHeader from '@/metersphere/common/components/MsTableHeader'
|
||||
import MsTableOperator from '@/metersphere/common/components/MsTableOperator'
|
||||
import MsDialogFooter from '@/metersphere/common/components/MsDialogFooter'
|
||||
import {
|
||||
listenGoBack,
|
||||
removeGoBackListener
|
||||
} from '@/metersphere/common/js/utils'
|
||||
import MsDeleteConfirm from '@/metersphere/common/components/MsDeleteConfirm'
|
||||
|
||||
import { addMenu, editMenu, delMenu, getMenusTree } from '@/api/system/menu'
|
||||
|
||||
export default {
|
||||
name: 'MsMenu',
|
||||
components: {
|
||||
MsDeleteConfirm,
|
||||
MsTableHeader,
|
||||
MsTableOperator,
|
||||
MsDialogFooter,
|
||||
ComplexTable,
|
||||
LayoutContent,
|
||||
Treeselect,
|
||||
IconSelect
|
||||
},
|
||||
@ -191,11 +174,6 @@ export default {
|
||||
menus: [],
|
||||
topMunu: { id: 0, label: '顶级类目', children: null },
|
||||
formType: 'add',
|
||||
queryPath: '/api/menu/childNodes/',
|
||||
deletePath: '/api/menu/delete',
|
||||
createPath: '/api/menu/create',
|
||||
updatePath: '/api/menu/update',
|
||||
result: {},
|
||||
dialogVisible: false,
|
||||
condition: {},
|
||||
tableData: [],
|
||||
@ -216,6 +194,41 @@ export default {
|
||||
add: ['menu:add'],
|
||||
edit: ['menu:edit'],
|
||||
del: ['menu:del']
|
||||
},
|
||||
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
{
|
||||
label: this.$t('commons.edit'), icon: 'el-icon-edit', click: this.edit
|
||||
}, {
|
||||
label: this.$t('commons.delete'), icon: 'el-icon-delete', type: 'danger', click: this._handleDelete
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
useQuickSearch: false,
|
||||
useComplexSearch: false,
|
||||
quickPlaceholder: '按姓名搜索',
|
||||
components: [
|
||||
|
||||
// { field: 'name', label: '姓名', component: 'FuComplexInput' },
|
||||
|
||||
// {
|
||||
// field: 'enabled',
|
||||
// label: '状态',
|
||||
// component: 'FuComplexSelect',
|
||||
// options: [
|
||||
// { label: '启用', value: '1' },
|
||||
// { label: '禁用', value: '0' }
|
||||
// ],
|
||||
// multiple: false
|
||||
// }
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
|
||||
}
|
||||
@ -229,7 +242,6 @@ export default {
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.dialogVisible = true
|
||||
this.formType = 'add'
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
search(condition) {
|
||||
console.log(condition)
|
||||
@ -241,7 +253,6 @@ export default {
|
||||
this.oldPid = row.pid
|
||||
this.form = Object.assign({}, row)
|
||||
this.treeByRow(row)
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
|
||||
treeByRow(row) {
|
||||
@ -288,7 +299,7 @@ export default {
|
||||
|
||||
initTableData(row, treeNode, resolve) {
|
||||
const _self = this
|
||||
const pid = row ? row.menuId : '0'
|
||||
const pid = (row && row.menuId) ? row.menuId : '0'
|
||||
|
||||
getMenusTree(pid).then(response => {
|
||||
let data = response.data
|
||||
@ -314,7 +325,6 @@ export default {
|
||||
this.form = this.defaultForm
|
||||
this.oldPid = null
|
||||
this.menus = null
|
||||
removeGoBackListener(this.closeFunc)
|
||||
this.dialogVisible = false
|
||||
},
|
||||
|
||||
@ -374,9 +384,7 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(menu) {
|
||||
this.$refs.deleteConfirm.open(menu)
|
||||
},
|
||||
|
||||
_handleDelete(menu) {
|
||||
this.$confirm(this.$t('menu.delete_confirm'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
@ -414,7 +422,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "~@/metersphere/common/css/index.css";
|
||||
.member-size {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@ -1,31 +1,34 @@
|
||||
<template>
|
||||
<div v-loading="result.loading" style="height: 100%">
|
||||
<el-container style="width: 100%; height: 100%;border: 1px solid #eee">
|
||||
<el-aside width="70%" style="border: 1px solid #eee">
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :permission="permission" :condition.sync="condition" :create-tip="$t('role.add')" :title="$t('commons.role')" @search="search" @create="create" />
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<!-- <div v-loading="result.loading" style="height: 100%"> -->
|
||||
<el-container style="width: 100%; height: 100%;">
|
||||
<el-aside width="70%">
|
||||
<complex-table
|
||||
highlight-current-row
|
||||
:data="tableData"
|
||||
:columns="columns"
|
||||
:buttons="buttons"
|
||||
:header="header"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search"
|
||||
@row-click="rowClick"
|
||||
>
|
||||
<template #buttons>
|
||||
<fu-table-button icon="el-icon-circle-plus-outline" :label="$t('role.add')" @click="create" />
|
||||
</template>
|
||||
<el-table border highlight-current-row class="adjust-table" :data="tableData" style="width: 100%;" @row-click="rowClick">
|
||||
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="code" label="代码" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建日期">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" />
|
||||
|
||||
</el-card>
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="code" label="代码" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建日期">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations :buttons="buttons" label="操作" fix />
|
||||
</complex-table>
|
||||
</el-aside>
|
||||
<el-main style="">
|
||||
<el-main style="padding: 8px 20px;">
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane label="菜单授权" name="first">
|
||||
<el-tree
|
||||
@ -67,52 +70,32 @@
|
||||
<el-input v-model="form.description" style="width: 380px;" rows="5" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogVisible = false"
|
||||
@confirm="saveRole('roleForm')"
|
||||
/>
|
||||
</template>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="dialogVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="saveRole('roleForm')">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</layout-content>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import MsTablePagination from '@/metersphere/common/pagination/TablePagination'
|
||||
import MsTableHeader from '@/metersphere/common/components/MsTableHeader'
|
||||
import MsTableOperator from '@/metersphere/common/components/MsTableOperator'
|
||||
import MsDialogFooter from '@/metersphere/common/components/MsDialogFooter'
|
||||
import {
|
||||
listenGoBack,
|
||||
removeGoBackListener
|
||||
} from '@/metersphere/common/js/utils'
|
||||
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import { formatCondition } from '@/utils/index'
|
||||
import { addRole, editRole, delRole, roleGrid, addRoleMenus, menuIds } from '@/api/system/role'
|
||||
|
||||
import { getMenusTree, getChild } from '@/api/system/menu'
|
||||
export default {
|
||||
name: 'Role',
|
||||
components: {
|
||||
MsTablePagination,
|
||||
MsTableHeader,
|
||||
MsTableOperator,
|
||||
MsDialogFooter
|
||||
LayoutContent,
|
||||
ComplexTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
queryPath: '/api/role/roleGrid',
|
||||
deletePath: '/api/role/delete/',
|
||||
createPath: '/api/role/create',
|
||||
updatePath: '/api/role/update',
|
||||
queryMenusPath: '/api/menu/childNodes/',
|
||||
childMenusPath: '/api/menu/childMenus/',
|
||||
saveRoleMenusPath: '/api/role/saveRolesMenus',
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
condition: {},
|
||||
|
||||
tableData: [],
|
||||
menus: [],
|
||||
menuIds: [],
|
||||
@ -131,6 +114,31 @@ export default {
|
||||
add: ['role:add'],
|
||||
edit: ['role:edit'],
|
||||
del: ['role:del']
|
||||
},
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
{
|
||||
label: this.$t('commons.edit'), icon: 'el-icon-edit', click: this.edit
|
||||
}, {
|
||||
label: this.$t('commons.delete'), icon: 'el-icon-delete', type: 'danger', click: this.handleDelete
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
useQuickSearch: false,
|
||||
quickPlaceholder: '按名称搜索',
|
||||
components: [
|
||||
// { field: 'name', label: '姓名', component: 'FuComplexInput', defaultOperator: 'eq' },
|
||||
{ field: 'name', label: '角色名称', component: 'FuComplexInput' },
|
||||
|
||||
{ field: 'code', label: '角色代码', component: 'FuComplexInput', defaultOperator: 'eq' }
|
||||
// { field: 'deptId', label: '组织', component: conditionTable }
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -148,10 +156,11 @@ export default {
|
||||
this.form = {}
|
||||
this.formType = 'add'
|
||||
this.dialogVisible = true
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
search() {
|
||||
roleGrid(this.currentPage, this.pageSize, this.condition).then(response => {
|
||||
search(condition) {
|
||||
const temp = formatCondition(condition)
|
||||
const param = temp || {}
|
||||
roleGrid(this.paginationConfig.currentPage, this.paginationConfig.pageSize, param).then(response => {
|
||||
const data = response.data
|
||||
this.total = data.itemCount
|
||||
this.tableData = data.listObject
|
||||
@ -162,7 +171,6 @@ export default {
|
||||
this.formType = 'modify'
|
||||
this.dialogVisible = true
|
||||
this.form = Object.assign({}, row)
|
||||
listenGoBack(this.closeFunc)
|
||||
},
|
||||
|
||||
saveRole(roleForm) {
|
||||
@ -182,7 +190,6 @@ export default {
|
||||
|
||||
closeFunc() {
|
||||
this.dialogVisible = false
|
||||
removeGoBackListener(this.closeFunc)
|
||||
},
|
||||
|
||||
getMenuDatas(node, resolve) {
|
||||
@ -272,5 +279,4 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "~@/metersphere/common/css/index.css";
|
||||
</style>
|
||||
|
||||
@ -1,62 +1,44 @@
|
||||
<template>
|
||||
<div v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('user.create')"
|
||||
:title="$t('commons.user')"
|
||||
@search="search"
|
||||
@create="create"
|
||||
/>
|
||||
<layout-content v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:buttons="buttons"
|
||||
:header="header"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
@select="select"
|
||||
@search="search"
|
||||
>
|
||||
<template #buttons>
|
||||
<fu-table-button icon="el-icon-circle-plus-outline" :label="$t('user.create')" @click="create" />
|
||||
</template>
|
||||
|
||||
<el-table border class="adjust-table" :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="username" label="ID" />
|
||||
<el-table-column prop="nickName" :label="$t('commons.name')" width="200" />
|
||||
<el-table-column prop="gender" label="性别" />
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column prop="username" label="ID" width="80" />
|
||||
<el-table-column prop="nickName" :label="$t('commons.name')" width="140" />
|
||||
<el-table-column prop="gender" label="性别" width="50" />
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" prop="phone" width="100" label="电话" />
|
||||
<el-table-column :show-overflow-tooltip="true" width="135" prop="email" :label="$t('commons.email')" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="dept" :label="$t('commons.organization')">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.dept.deptName }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')" width="120">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch v-model="scope.row.enabled" :active-value="1" :inactive-value="0" inactive-color="#DCDFE6" @change="changeSwitch(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('commons.create_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :show-overflow-tooltip="true" prop="phone" width="200" label="电话" />
|
||||
<el-table-column :show-overflow-tooltip="true" width="200" prop="email" :label="$t('commons.email')" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="dept" :label="$t('commons.organization')">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.dept.deptName }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')" width="60">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch v-model="scope.row.enabled" :active-value="1" :inactive-value="0" inactive-color="#DCDFE6" @change="changeSwitch(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('commons.create_time')" width="160">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations :buttons="buttons" label="操作" fix />
|
||||
</complex-table>
|
||||
|
||||
<!-- <el-table-column prop="source" :label="$t('user.source')"/> -->
|
||||
<el-table-column :label="$t('commons.operating')" min-width="120px">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
||||
<template v-slot:behind>
|
||||
<ms-table-operator-button
|
||||
v-permission="permission.editPwd"
|
||||
:tip="$t('member.edit_password')"
|
||||
icon="el-icon-s-tools"
|
||||
type="success"
|
||||
@exec="editPassword(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</ms-table-operator>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" />
|
||||
|
||||
</el-card>
|
||||
<el-dialog
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
@ -72,7 +54,7 @@
|
||||
<el-input v-model="form.username" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input v-model.number="form.phone" />
|
||||
<el-input v-model="form.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" />
|
||||
@ -102,11 +84,12 @@
|
||||
placeholder="选择部门"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item style="margin-bottom: 0;" label="角色" prop="roles">
|
||||
<el-form-item style="margin-bottom: 0;" label="角色" prop="roleIds">
|
||||
<el-select
|
||||
v-model="form.roleIds"
|
||||
style="width: 430px"
|
||||
multiple
|
||||
required="true"
|
||||
placeholder="请选择"
|
||||
@remove-tag="deleteTag"
|
||||
@change="changeRole"
|
||||
@ -120,12 +103,10 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogVisible = false"
|
||||
@confirm="createUser('createUserForm')"
|
||||
/>
|
||||
</template>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="dialogVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="createUser('createUserForm')">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!--Changing user password in system settings-->
|
||||
@ -153,60 +134,77 @@
|
||||
<el-input v-model="ruleForm.userId" autocomplete="off" :disabled="true" style="display:none" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="editPasswordVisible = false"
|
||||
@confirm="editUserPassword('editPasswordForm')"
|
||||
/>
|
||||
</span>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="editPasswordVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="editUserPassword('editPasswordForm')">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import MsCreateBox from '@/metersphere/common/components/CreateBox'
|
||||
import MsTablePagination from '@/metersphere/common/pagination/TablePagination'
|
||||
import MsTableHeader from '@/metersphere/common/components/MsTableHeader'
|
||||
import MsTableOperator from '@/metersphere/common/components/MsTableOperator'
|
||||
import MsDialogFooter from '@/metersphere/common/components/MsDialogFooter'
|
||||
import MsTableOperatorButton from '@/metersphere/common/components/MsTableOperatorButton'
|
||||
import { listenGoBack, removeGoBackListener } from '@/metersphere/common/js/utils'
|
||||
import { PHONE_REGEX } from '@/metersphere/common/js/regex'
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
// import conditionTable from '@/components/business/condition-table'
|
||||
// import CustomCondition from './CustomCondtion'
|
||||
// import { GridButton } from '@/components/GridButton'
|
||||
import { checkPermission } from '@/utils/permission'
|
||||
import { formatCondition } from '@/utils/index'
|
||||
import { PHONE_REGEX } from '@/utils/validate'
|
||||
import { LOAD_CHILDREN_OPTIONS, LOAD_ROOT_OPTIONS } from '@riophae/vue-treeselect'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
|
||||
import { userLists, addUser, editUser, delUser, editPassword, editStatus } from '@/api/system/user'
|
||||
import { allRoles } from '@/api/system/role'
|
||||
import { getDeptTree } from '@/api/system/dept'
|
||||
export default {
|
||||
name: 'MsUser',
|
||||
|
||||
components: {
|
||||
// MsCreateBox,
|
||||
MsTablePagination,
|
||||
MsTableHeader,
|
||||
MsTableOperator,
|
||||
MsDialogFooter,
|
||||
MsTableOperatorButton,
|
||||
Treeselect
|
||||
},
|
||||
export default {
|
||||
|
||||
components: { ComplexTable, LayoutContent, Treeselect },
|
||||
data() {
|
||||
return {
|
||||
queryPath: '/api/user/userGrid',
|
||||
deletePath: '/api/user/delete/',
|
||||
createPath: '/api/user/create',
|
||||
updatePath: '/api/user/update',
|
||||
editPasswordPath: '/api/user/password',
|
||||
result: {},
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
{
|
||||
label: this.$t('commons.edit'), icon: 'el-icon-edit', click: this.edit
|
||||
}, {
|
||||
label: this.$t('commons.delete'), icon: 'el-icon-delete', type: 'danger', click: this.del
|
||||
}, {
|
||||
label: this.$t('member.edit_password'), icon: 'el-icon-s-tools', type: 'danger', click: this.editPassword,
|
||||
show: checkPermission(['user:editPwd'])
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
useQuickSearch: false,
|
||||
quickPlaceholder: '按姓名搜索',
|
||||
components: [
|
||||
// { field: 'name', label: '姓名', component: 'FuComplexInput', defaultOperator: 'eq' },
|
||||
{ field: 'nick_name', label: '姓名', component: 'FuComplexInput' },
|
||||
|
||||
{
|
||||
field: 'u.enabled',
|
||||
label: '状态',
|
||||
component: 'FuComplexSelect',
|
||||
options: [
|
||||
{ label: '启用', value: '1' },
|
||||
{ label: '禁用', value: '0' }
|
||||
],
|
||||
multiple: false
|
||||
}
|
||||
// { field: 'deptId', label: '组织', component: conditionTable }
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
data: [],
|
||||
|
||||
dialogVisible: false,
|
||||
editPasswordVisible: false,
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
condition: {},
|
||||
tableData: [],
|
||||
form: {
|
||||
roles: [{
|
||||
id: ''
|
||||
@ -215,7 +213,7 @@ export default {
|
||||
checkPasswordForm: {},
|
||||
ruleForm: {},
|
||||
rule: {
|
||||
id: [
|
||||
username: [
|
||||
{ required: true, message: this.$t('user.input_id'), trigger: 'blur' },
|
||||
{ min: 1, max: 50, message: this.$t('commons.input_limit', [1, 50]), trigger: 'blur' },
|
||||
{
|
||||
@ -225,7 +223,7 @@ export default {
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
name: [
|
||||
nickName: [
|
||||
{ required: true, message: this.$t('user.input_name'), trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: this.$t('commons.input_limit', [2, 50]), trigger: 'blur' },
|
||||
{
|
||||
@ -267,7 +265,9 @@ export default {
|
||||
message: this.$t('member.password_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
],
|
||||
roleIds: [{ required: true, message: this.$t('user.input_roles'), trigger: 'blur' }]
|
||||
|
||||
},
|
||||
defaultForm: { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 1, deptId: null, phone: null },
|
||||
depts: null,
|
||||
@ -283,7 +283,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
activated() {
|
||||
// this.form = Object.assign({}, this.defaultForm);
|
||||
this.allRoles()
|
||||
@ -291,25 +290,35 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
select(selection) {
|
||||
console.log(selection)
|
||||
},
|
||||
|
||||
search(condition) {
|
||||
console.log(condition) // demo只查看搜索条件,没有搜索的实现
|
||||
const temp = formatCondition(condition)
|
||||
const param = temp || {}
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
userLists(currentPage, pageSize, param).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
},
|
||||
|
||||
create() {
|
||||
this.formType = 'add'
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.dialogVisible = true
|
||||
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
edit(row) {
|
||||
this.formType = 'modify'
|
||||
this.dialogVisible = true
|
||||
this.form = Object.assign({}, row)
|
||||
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
editPassword(row) {
|
||||
this.editPasswordVisible = true
|
||||
const tempForm = Object.assign({}, row)
|
||||
this.ruleForm = { userId: tempForm.userId }
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
del(row) {
|
||||
this.$confirm(this.$t('user.delete_confirm'), '', {
|
||||
@ -354,23 +363,9 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
search() {
|
||||
userLists(this.currentPage, this.pageSize, this.condition).then(response => {
|
||||
const data = response.data
|
||||
this.total = data.itemCount
|
||||
this.tableData = data.listObject
|
||||
})
|
||||
// this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
|
||||
// const data = response.data
|
||||
// this.total = data.itemCount
|
||||
// this.tableData = data.listObject
|
||||
|
||||
// })
|
||||
},
|
||||
handleClose() {
|
||||
this.formType = 'add'
|
||||
this.form = {}
|
||||
removeGoBackListener(this.handleClose)
|
||||
this.editPasswordVisible = false
|
||||
this.dialogVisible = false
|
||||
},
|
||||
@ -381,10 +376,6 @@ export default {
|
||||
this.$success(this.$t('commons.modify_success'))
|
||||
})
|
||||
},
|
||||
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
},
|
||||
// 获取弹窗内部门数据
|
||||
loadDepts({ action, parentNode, callback }) {
|
||||
if (action === LOAD_ROOT_OPTIONS) {
|
||||
@ -434,11 +425,10 @@ export default {
|
||||
this.roles = res.data
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "~@/metersphere/common/css/index.css";
|
||||
|
||||
</style>
|
||||
|
||||
@ -1,134 +0,0 @@
|
||||
<template>
|
||||
<layout-content>
|
||||
<complex-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:buttons="buttons"
|
||||
:header="header"
|
||||
:search-config="searchConfig"
|
||||
:pagination-config="paginationConfig"
|
||||
@select="select"
|
||||
@search="search"
|
||||
>
|
||||
<template #buttons>
|
||||
<fu-table-button icon="el-icon-circle-plus-outline" :label="$t('user.create')" @click="add" />
|
||||
</template>
|
||||
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column prop="username" label="ID" />
|
||||
<el-table-column prop="nickName" :label="$t('commons.name')" width="200" />
|
||||
<el-table-column prop="gender" label="性别" />
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" prop="phone" width="100" label="电话" />
|
||||
<el-table-column :show-overflow-tooltip="true" width="135" prop="email" :label="$t('commons.email')" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="dept" :label="$t('commons.organization')">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.dept.deptName }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')" width="120">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch v-model="scope.row.enabled" :active-value="1" :inactive-value="0" inactive-color="#DCDFE6" @change="changeSwitch(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('commons.create_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations :buttons="buttons" label="操作" fix />
|
||||
</complex-table>
|
||||
</layout-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LayoutContent from '@/components/business/LayoutContent'
|
||||
import { userLists } from '@/api/system/user'
|
||||
import ComplexTable from '@/components/business/complex-table'
|
||||
import CustomCondition from './CustomCondtion'
|
||||
// import { GridButton } from '@/components/GridButton'
|
||||
// import { checkPermission } from '@/utils/permisstion'
|
||||
|
||||
const buttonClick = function(row) {
|
||||
console.log(this.label + ': ' + row.id)
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'UserManagement',
|
||||
components: { ComplexTable, LayoutContent },
|
||||
data() {
|
||||
return {
|
||||
header: '',
|
||||
columns: [],
|
||||
buttons: [
|
||||
{
|
||||
label: '编辑', icon: 'el-icon-edit', click: this.edit
|
||||
}, {
|
||||
label: '执行', icon: 'el-icon-video-play', click: buttonClick
|
||||
}, {
|
||||
label: '删除', icon: 'el-icon-delete', type: 'danger', click: buttonClick
|
||||
}, {
|
||||
label: '删除(权限)', icon: 'el-icon-delete', type: 'danger', click: buttonClick
|
||||
// show: checkPermission('editor') // 必须有editor权限才能看到
|
||||
}, {
|
||||
label: '复制', icon: 'el-icon-document-copy', click: buttonClick
|
||||
}, {
|
||||
label: '定时任务', icon: 'el-icon-timer', click: buttonClick
|
||||
}
|
||||
],
|
||||
searchConfig: {
|
||||
quickPlaceholder: '按 姓名/邮箱 搜索',
|
||||
components: [
|
||||
{ field: 'name', label: '姓名', component: 'FuComplexInput', defaultOperator: 'eq' },
|
||||
{ field: 'email', label: 'Email', component: 'FuComplexInput' },
|
||||
{
|
||||
field: 'status',
|
||||
label: '状态',
|
||||
component: 'FuComplexSelect',
|
||||
options: [
|
||||
{ label: '运行中', value: 'Running' },
|
||||
{ label: '成功', value: 'Success' },
|
||||
{ label: '失败', value: 'Fail' }
|
||||
],
|
||||
multiple: true
|
||||
},
|
||||
{ field: 'create_time', label: '创建时间', component: 'FuComplexDateTime' },
|
||||
{ field: 'user', component: CustomCondition } // 如何自定义搜索控件,看CustomCondition
|
||||
]
|
||||
},
|
||||
paginationConfig: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
data: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
select(selection) {
|
||||
console.log(selection)
|
||||
},
|
||||
edit(row) {
|
||||
console.log('编辑: ', row)
|
||||
},
|
||||
add() {
|
||||
|
||||
},
|
||||
search(condition) {
|
||||
console.log(condition) // demo只查看搜索条件,没有搜索的实现
|
||||
const { currentPage, pageSize } = this.paginationConfig
|
||||
userLists(currentPage, pageSize, {}).then(response => {
|
||||
this.data = response.data.listObject
|
||||
this.paginationConfig.total = response.data.itemCount
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
444
frontend/src/views/system/user/index_back.vue
Normal file
@ -0,0 +1,444 @@
|
||||
<template>
|
||||
<div v-loading="$store.getters.loadingMap[$store.getters.currentPath]">
|
||||
|
||||
<el-card class="table-card">
|
||||
<template v-slot:header>
|
||||
<ms-table-header
|
||||
:permission="permission"
|
||||
:condition.sync="condition"
|
||||
:create-tip="$t('user.create')"
|
||||
:title="$t('commons.user')"
|
||||
@search="search"
|
||||
@create="create"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<el-table border class="adjust-table" :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="username" label="ID" />
|
||||
<el-table-column prop="nickName" :label="$t('commons.name')" width="200" />
|
||||
<el-table-column prop="gender" label="性别" />
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" prop="phone" width="100" label="电话" />
|
||||
<el-table-column :show-overflow-tooltip="true" width="135" prop="email" :label="$t('commons.email')" />
|
||||
<el-table-column :show-overflow-tooltip="true" prop="dept" :label="$t('commons.organization')">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.dept.deptName }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')" width="120">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch v-model="scope.row.enabled" :active-value="1" :inactive-value="0" inactive-color="#DCDFE6" @change="changeSwitch(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('commons.create_time')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- <el-table-column prop="source" :label="$t('user.source')"/> -->
|
||||
<el-table-column :label="$t('commons.operating')" min-width="120px">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :permission="permission" @editClick="edit(scope.row)" @deleteClick="del(scope.row)">
|
||||
<template v-slot:behind>
|
||||
<ms-table-operator-button
|
||||
v-permission="permission.editPwd"
|
||||
:tip="$t('member.edit_password')"
|
||||
icon="el-icon-s-tools"
|
||||
type="success"
|
||||
@exec="editPassword(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</ms-table-operator>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" />
|
||||
|
||||
</el-card>
|
||||
<el-dialog
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
:title="formType=='add' ? $t('user.create') : $t('user.modify')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="570px"
|
||||
:destroy-on-close="true"
|
||||
@closed="handleClose"
|
||||
>
|
||||
<el-form ref="createUserForm" :inline="true" :model="form" :rules="rule" size="small" label-width="66px">
|
||||
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="form.username" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input v-model.number="form.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickName">
|
||||
<el-input v-model="form.nickName" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="form.gender" style="width: 178px">
|
||||
<el-radio label="男">男</el-radio>
|
||||
<el-radio label="女">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.enabled" style="width: 140px">
|
||||
<el-radio :label="1">启用</el-radio>
|
||||
<el-radio :label="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="dept">
|
||||
<treeselect
|
||||
v-model="form.deptId"
|
||||
:options="depts"
|
||||
:load-options="loadDepts"
|
||||
style="width: 430px"
|
||||
placeholder="选择部门"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item style="margin-bottom: 0;" label="角色" prop="roles">
|
||||
<el-select
|
||||
v-model="form.roleIds"
|
||||
style="width: 430px"
|
||||
multiple
|
||||
placeholder="请选择"
|
||||
@remove-tag="deleteTag"
|
||||
@change="changeRole"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in roles"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogVisible = false"
|
||||
@confirm="createUser('createUserForm')"
|
||||
/>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!--Changing user password in system settings-->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="$t('member.edit_password')"
|
||||
:visible.sync="editPasswordVisible"
|
||||
width="30%"
|
||||
:destroy-on-close="true"
|
||||
left
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="editPasswordForm"
|
||||
:model="ruleForm"
|
||||
label-position="right"
|
||||
label-width="120px"
|
||||
:rules="rule"
|
||||
class="demo-ruleForm"
|
||||
>
|
||||
<el-form-item :label="$t('member.new_password')" prop="newpassword">
|
||||
<el-input v-model="ruleForm.newPassword" type="password" autocomplete="off" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input v-model="ruleForm.userId" autocomplete="off" :disabled="true" style="display:none" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="editPasswordVisible = false"
|
||||
@confirm="editUserPassword('editPasswordForm')"
|
||||
/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import MsCreateBox from '@/metersphere/common/components/CreateBox'
|
||||
import MsTablePagination from '@/metersphere/common/pagination/TablePagination'
|
||||
import MsTableHeader from '@/metersphere/common/components/MsTableHeader'
|
||||
import MsTableOperator from '@/metersphere/common/components/MsTableOperator'
|
||||
import MsDialogFooter from '@/metersphere/common/components/MsDialogFooter'
|
||||
import MsTableOperatorButton from '@/metersphere/common/components/MsTableOperatorButton'
|
||||
import { listenGoBack, removeGoBackListener } from '@/metersphere/common/js/utils'
|
||||
import { PHONE_REGEX } from '@/metersphere/common/js/regex'
|
||||
import { LOAD_CHILDREN_OPTIONS, LOAD_ROOT_OPTIONS } from '@riophae/vue-treeselect'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import { userLists, addUser, editUser, delUser, editPassword, editStatus } from '@/api/system/user'
|
||||
import { allRoles } from '@/api/system/role'
|
||||
import { getDeptTree } from '@/api/system/dept'
|
||||
export default {
|
||||
name: 'MsUser',
|
||||
|
||||
components: {
|
||||
// MsCreateBox,
|
||||
MsTablePagination,
|
||||
MsTableHeader,
|
||||
MsTableOperator,
|
||||
MsDialogFooter,
|
||||
MsTableOperatorButton,
|
||||
Treeselect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
queryPath: '/api/user/userGrid',
|
||||
deletePath: '/api/user/delete/',
|
||||
createPath: '/api/user/create',
|
||||
updatePath: '/api/user/update',
|
||||
editPasswordPath: '/api/user/password',
|
||||
result: {},
|
||||
dialogVisible: false,
|
||||
editPasswordVisible: false,
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
condition: {},
|
||||
tableData: [],
|
||||
form: {
|
||||
roles: [{
|
||||
id: ''
|
||||
}]
|
||||
},
|
||||
checkPasswordForm: {},
|
||||
ruleForm: {},
|
||||
rule: {
|
||||
id: [
|
||||
{ required: true, message: this.$t('user.input_id'), trigger: 'blur' },
|
||||
{ min: 1, max: 50, message: this.$t('commons.input_limit', [1, 50]), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: '^[^\u4e00-\u9fa5]+$',
|
||||
message: this.$t('user.special_characters_are_not_supported'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: this.$t('user.input_name'), trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: this.$t('commons.input_limit', [2, 50]), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('user.special_characters_are_not_supported'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('user.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: this.$t('user.input_email'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
|
||||
message: this.$t('user.email_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: this.$t('user.input_password'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t('member.password_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
newPassword: [
|
||||
{ required: true, message: this.$t('user.input_password'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
|
||||
message: this.$t('member.password_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
},
|
||||
defaultForm: { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 1, deptId: null, phone: null },
|
||||
depts: null,
|
||||
roles: [],
|
||||
roleDatas: [],
|
||||
userRoles: [],
|
||||
formType: 'add',
|
||||
permission: {
|
||||
add: ['user:add'],
|
||||
edit: ['user:edit'],
|
||||
del: ['user:del'],
|
||||
editPwd: ['user:editPwd']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
activated() {
|
||||
// this.form = Object.assign({}, this.defaultForm);
|
||||
this.allRoles()
|
||||
this.search()
|
||||
},
|
||||
|
||||
methods: {
|
||||
create() {
|
||||
this.formType = 'add'
|
||||
this.form = Object.assign({}, this.defaultForm)
|
||||
this.dialogVisible = true
|
||||
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
edit(row) {
|
||||
this.formType = 'modify'
|
||||
this.dialogVisible = true
|
||||
this.form = Object.assign({}, row)
|
||||
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
editPassword(row) {
|
||||
this.editPasswordVisible = true
|
||||
const tempForm = Object.assign({}, row)
|
||||
this.ruleForm = { userId: tempForm.userId }
|
||||
listenGoBack(this.handleClose)
|
||||
},
|
||||
del(row) {
|
||||
this.$confirm(this.$t('user.delete_confirm'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
delUser(encodeURIComponent(row.userId)).then(res => {
|
||||
this.$success(this.$t('commons.delete_success'))
|
||||
this.search()
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$info(this.$t('commons.delete_cancel'))
|
||||
})
|
||||
},
|
||||
createUser(createUserForm) {
|
||||
this.$refs[createUserForm].validate(valid => {
|
||||
if (valid) {
|
||||
const method = this.formType === 'add' ? addUser : editUser
|
||||
method(this.form).then(res => {
|
||||
this.$success(this.$t('commons.save_success'))
|
||||
this.search()
|
||||
this.dialogVisible = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
editUserPassword(editPasswordForm) {
|
||||
this.$refs[editPasswordForm].validate(valid => {
|
||||
if (valid) {
|
||||
editPassword(this.ruleForm).then(res => {
|
||||
this.$success(this.$t('commons.modify_success'))
|
||||
this.editPasswordVisible = false
|
||||
this.search()
|
||||
window.location.reload()
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
search() {
|
||||
userLists(this.currentPage, this.pageSize, this.condition).then(response => {
|
||||
const data = response.data
|
||||
this.total = data.itemCount
|
||||
this.tableData = data.listObject
|
||||
})
|
||||
// this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
|
||||
// const data = response.data
|
||||
// this.total = data.itemCount
|
||||
// this.tableData = data.listObject
|
||||
|
||||
// })
|
||||
},
|
||||
handleClose() {
|
||||
this.formType = 'add'
|
||||
this.form = {}
|
||||
removeGoBackListener(this.handleClose)
|
||||
this.editPasswordVisible = false
|
||||
this.dialogVisible = false
|
||||
},
|
||||
changeSwitch(row) {
|
||||
const { userId, enabled } = row
|
||||
const param = { userId: userId, enabled: enabled }
|
||||
editStatus(param).then(res => {
|
||||
this.$success(this.$t('commons.modify_success'))
|
||||
})
|
||||
},
|
||||
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
},
|
||||
// 获取弹窗内部门数据
|
||||
loadDepts({ action, parentNode, callback }) {
|
||||
if (action === LOAD_ROOT_OPTIONS) {
|
||||
const _self = this
|
||||
!this.depts && getDeptTree('0').then(res => {
|
||||
_self.depts = res.data.map(node => _self.normalizer(node))
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
if (action === LOAD_CHILDREN_OPTIONS) {
|
||||
const _self = this
|
||||
getDeptTree(parentNode.id).then(res => {
|
||||
parentNode.children = res.data.map(function(obj) {
|
||||
return _self.normalizer(obj)
|
||||
})
|
||||
callback()
|
||||
})
|
||||
}
|
||||
},
|
||||
normalizer(node) {
|
||||
if (node.hasChildren) {
|
||||
node.children = null
|
||||
}
|
||||
return {
|
||||
id: node.deptId,
|
||||
label: node.name,
|
||||
children: node.children
|
||||
}
|
||||
},
|
||||
deleteTag(value) {
|
||||
this.userRoles.forEach(function(data, index) {
|
||||
if (data.id === value) {
|
||||
this.userRoles.splice(index, value)
|
||||
}
|
||||
}.bind(this))
|
||||
},
|
||||
changeRole(value) {
|
||||
this.userRoles = []
|
||||
value.forEach(function(data, index) {
|
||||
const role = { id: data }
|
||||
this.userRoles.push(role)
|
||||
}.bind(this))
|
||||
},
|
||||
allRoles() {
|
||||
allRoles().then(res => {
|
||||
this.roles = res.data
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "~@/metersphere/common/css/index.css";
|
||||
</style>
|
||||
4
pom.xml
@ -10,13 +10,13 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<!--<version>2.2.6.RELEASE</version>-->
|
||||
<version>2.4.3</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<name>dataease</name>
|
||||
<modules>
|
||||
<module>frontend</module>
|
||||
<module>backend</module>
|
||||
</modules>
|
||||
|
||||
|
||||