diff --git a/core/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java b/core/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java index 0132c5559e..158f76004b 100644 --- a/core/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java +++ b/core/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java @@ -37,6 +37,9 @@ public class DeCleanerAnnotationHandler { switch (type.name()) { + case "DATA_FILL": + catchProcess().cleanDataFiling(paramValue); + break; case "DATASOURCE": catchProcess().cleanDataSource(paramValue); break; diff --git a/core/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java b/core/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java index 6729d39558..be6ea53f64 100644 --- a/core/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java +++ b/core/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java @@ -92,8 +92,7 @@ public class JWTFilter extends BasicHttpAuthenticationFilter { if (isLoginAttempt(request, response) || ApiKeyHandler.isApiKeyCall(hRequest)) { try { - boolean loginSuccess = executeLogin(request, response); - return loginSuccess; + return executeLogin(request, response); } catch (Exception e) { LogUtil.error(e); if (e instanceof AuthenticationException && StringUtils.equals(e.getMessage(), expireMessage)) { diff --git a/core/backend/src/main/java/io/dataease/auth/server/AuthServer.java b/core/backend/src/main/java/io/dataease/auth/server/AuthServer.java index 8ec0b31781..2f594c6039 100644 --- a/core/backend/src/main/java/io/dataease/auth/server/AuthServer.java +++ b/core/backend/src/main/java/io/dataease/auth/server/AuthServer.java @@ -26,7 +26,6 @@ import io.dataease.plugins.xpack.ldap.dto.response.ValidateResult; import io.dataease.plugins.xpack.ldap.service.LdapXpackService; import io.dataease.plugins.xpack.oidc.service.OidcXpackService; import io.dataease.service.sys.SysUserService; - import io.dataease.service.system.SystemParameterService; import io.dataease.websocket.entity.WsMessage; import io.dataease.websocket.service.WsService; @@ -38,15 +37,14 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - @RestController public class AuthServer implements AuthApi { @@ -203,11 +201,12 @@ public class AuthServer implements AuthApi { result.put("defaultPwd", DEFAULT_PWD); } } - + Long expireTime = System.currentTimeMillis() + JWTUtils.getExpireTime(); TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(username).build(); String token = JWTUtils.sign(tokenInfo, realPwd); // 记录token操作时间 result.put("token", token); + result.put("expireTime", expireTime); ServletUtils.setToken(token); DeLogUtils.save(SysLogConstants.OPERATE_TYPE.LOGIN, SysLogConstants.SOURCE_TYPE.USER, user.getUserId(), null, null, null); authUserService.unlockAccount(username, ObjectUtils.isEmpty(loginType) ? 0 : loginType); diff --git a/core/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java b/core/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java index 10bdaeda3c..263e7189d1 100644 --- a/core/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java +++ b/core/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java @@ -15,19 +15,33 @@ public interface ExtAuthService { AuthURD resourceTarget(String resourceId); List dataSourceIdByUser(Long userId); + List dataSetIdByUser(Long userId); + List panelIdByUser(Long userId); + List dataFillingIdByUser(Long userId); + List dataSourceIdByRole(Long roleId); + List dataSetIdByRole(Long roleId); + List panelIdByRole(Long roleId); + List dataFillingIdByRole(Long roleId); + List dataSourceIdByDept(Long deptId); + List dataSetIdByDept(Long deptId); + List panelIdByDept(Long deptId); + List dataFillingIdByDept(Long deptId); + void clearUserResource(Long userId); + void clearDeptResource(Long deptId); + void clearRoleResource(Long roleId); List parentResource(String resourceId, String type); diff --git a/core/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java b/core/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java index dc8b5e8954..5b3e3b6c81 100644 --- a/core/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java +++ b/core/backend/src/main/java/io/dataease/auth/service/impl/DynamicMenuServiceImpl.java @@ -90,7 +90,7 @@ public class DynamicMenuServiceImpl implements DynamicMenuService { dynamicMenuDto.setPermission(sysMenu.getPermission()); dynamicMenuDto.setMenuSort(sysMenu.getMenuSort()); dynamicMenuDto.setHidden(sysMenu.getHidden()); - dynamicMenuDto.setIsPlugin(true); + dynamicMenuDto.setIsPlugin(!sysMenu.isUseBasicResource()); dynamicMenuDto.setNoLayout(!!sysMenu.isNoLayout()); return dynamicMenuDto; } diff --git a/core/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java b/core/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java index 1926f6e513..02e813c4ca 100644 --- a/core/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java +++ b/core/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java @@ -2,12 +2,12 @@ package io.dataease.auth.service.impl; import io.dataease.auth.entity.AuthItem; import io.dataease.auth.service.ExtAuthService; -import io.dataease.commons.constants.SysAuthConstants; -import io.dataease.plugins.common.base.domain.SysAuth; -import io.dataease.ext.ExtAuthMapper; import io.dataease.commons.constants.AuthConstants; +import io.dataease.commons.constants.SysAuthConstants; import io.dataease.commons.model.AuthURD; import io.dataease.commons.utils.LogUtil; +import io.dataease.ext.ExtAuthMapper; +import io.dataease.plugins.common.base.domain.SysAuth; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; @@ -109,6 +109,16 @@ public class ExtAuthServiceImpl implements ExtAuthService { ); } + @Cacheable(value = AuthConstants.USER_DATA_FILL_NAME, key = "'user' + #userId") + @Override + public List dataFillingIdByUser(Long userId) { + return extAuthMapper.queryAuthItems( + SysAuthConstants.AUTH_TARGET_TYPE_USER, + userId.toString(), + SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING + ); + } + @Cacheable(value = AuthConstants.ROLE_LINK_NAME, key = "'role' + #roleId") @Override @@ -140,6 +150,16 @@ public class ExtAuthServiceImpl implements ExtAuthService { ); } + @Cacheable(value = AuthConstants.ROLE_DATA_FILL_NAME, key = "'role' + #roleId") + @Override + public List dataFillingIdByRole(Long roleId) { + return extAuthMapper.queryAuthItems( + SysAuthConstants.AUTH_TARGET_TYPE_ROLE, + roleId.toString(), + SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING + ); + } + @Cacheable(value = AuthConstants.DEPT_LINK_NAME, key = "'dept' + #deptId") @Override public List dataSourceIdByDept(Long deptId) { @@ -173,10 +193,22 @@ public class ExtAuthServiceImpl implements ExtAuthService { ); } + @Cacheable(value = AuthConstants.DEPT_DATA_FILL_NAME, key = "'dept' + #deptId") + @Override + public List dataFillingIdByDept(Long deptId) { + if (ObjectUtils.isEmpty(deptId)) return emptyResult; + return extAuthMapper.queryAuthItems( + SysAuthConstants.AUTH_TARGET_TYPE_DEPT, + deptId.toString(), + SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING + ); + } + @Caching(evict = { @CacheEvict(value = AuthConstants.USER_LINK_NAME, key = "'user' + #userId"), @CacheEvict(value = AuthConstants.USER_DATASET_NAME, key = "'user' + #userId"), - @CacheEvict(value = AuthConstants.USER_PANEL_NAME, key = "'user' + #userId") + @CacheEvict(value = AuthConstants.USER_PANEL_NAME, key = "'user' + #userId"), + @CacheEvict(value = AuthConstants.USER_DATA_FILL_NAME, key = "'user' + #userId") }) public void clearUserResource(Long userId) { LogUtil.info("all permission resource of user {} is cleaning...", userId); @@ -185,7 +217,8 @@ public class ExtAuthServiceImpl implements ExtAuthService { @Caching(evict = { @CacheEvict(value = AuthConstants.DEPT_LINK_NAME, key = "'dept' + #deptId"), @CacheEvict(value = AuthConstants.DEPT_DATASET_NAME, key = "'dept' + #deptId"), - @CacheEvict(value = AuthConstants.DEPT_PANEL_NAME, key = "'dept' + #deptId") + @CacheEvict(value = AuthConstants.DEPT_PANEL_NAME, key = "'dept' + #deptId"), + @CacheEvict(value = AuthConstants.DEPT_DATA_FILL_NAME, key = "'dept' + #deptId") }) public void clearDeptResource(Long deptId) { LogUtil.info("all permission resource of dept {} is cleaning...", deptId); @@ -194,7 +227,8 @@ public class ExtAuthServiceImpl implements ExtAuthService { @Caching(evict = { @CacheEvict(value = AuthConstants.ROLE_LINK_NAME, key = "'role' + #roleId"), @CacheEvict(value = AuthConstants.ROLE_DATASET_NAME, key = "'role' + #roleId"), - @CacheEvict(value = AuthConstants.ROLE_PANEL_NAME, key = "'role' + #roleId") + @CacheEvict(value = AuthConstants.ROLE_PANEL_NAME, key = "'role' + #roleId"), + @CacheEvict(value = AuthConstants.ROLE_DATA_FILL_NAME, key = "'role' + #roleId") }) public void clearRoleResource(Long roleId) { LogUtil.info("all permission resource of role {} is cleaning...", roleId); diff --git a/core/backend/src/main/java/io/dataease/auth/util/JWTUtils.java b/core/backend/src/main/java/io/dataease/auth/util/JWTUtils.java index 38d4779b12..9817264a00 100644 --- a/core/backend/src/main/java/io/dataease/auth/util/JWTUtils.java +++ b/core/backend/src/main/java/io/dataease/auth/util/JWTUtils.java @@ -1,8 +1,8 @@ package io.dataease.auth.util; import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTCreator.Builder; +import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; @@ -10,7 +10,10 @@ import com.google.gson.Gson; import io.dataease.auth.entity.TokenInfo; import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder; import io.dataease.commons.model.OnlineUserModel; -import io.dataease.commons.utils.*; +import io.dataease.commons.utils.CommonBeanFactory; +import io.dataease.commons.utils.IPUtils; +import io.dataease.commons.utils.ServletUtils; +import io.dataease.commons.utils.TokenCacheUtils; import io.dataease.plugins.common.exception.DataEaseException; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -77,6 +80,13 @@ public class JWTUtils { return sign(tokenInfo, secret, true); } + public static Long getExpireTime() { + if (ObjectUtils.isEmpty(expireTime)) { + expireTime = Objects.requireNonNull(CommonBeanFactory.getBean(Environment.class)).getProperty("dataease.login_timeout", Long.class, 480L); + } + return expireTime * 60000L; + } + private static boolean tokenValid(OnlineUserModel model) { String token = model.getToken(); // 如果已经加入黑名单 则直接返回无效 @@ -84,10 +94,7 @@ public class JWTUtils { if (invalid) return false; Long loginTime = model.getLoginTime(); - if (ObjectUtils.isEmpty(expireTime)) { - expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L); - } - long expireTimeMillis = expireTime * 60000L; + long expireTimeMillis = getExpireTime(); // 如果当前时间减去登录时间小于超时时间则说明token未过期 返回有效状态 return System.currentTimeMillis() - loginTime < expireTimeMillis; @@ -133,10 +140,7 @@ public class JWTUtils { DataEaseException.throwException("MultiLoginError1"); } } - if (ObjectUtils.isEmpty(expireTime)) { - expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L); - } - long expireTimeMillis = expireTime * 60000L; + long expireTimeMillis = getExpireTime(); Date date = new Date(System.currentTimeMillis() + expireTimeMillis); Algorithm algorithm = Algorithm.HMAC256(secret); Builder builder = JWT.create() diff --git a/core/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java b/core/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java index 6bd0f2f3d6..2b273465aa 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/AuthConstants.java @@ -12,14 +12,17 @@ public class AuthConstants { public final static String USER_LINK_NAME = "user_link"; public final static String USER_DATASET_NAME = "user_dataset"; public final static String USER_PANEL_NAME = "user_panel"; + public final static String USER_DATA_FILL_NAME = "user_data_fill"; public final static String ROLE_LINK_NAME = "role_link"; public final static String ROLE_DATASET_NAME = "role_dataset"; public final static String ROLE_PANEL_NAME = "role_panel"; + public final static String ROLE_DATA_FILL_NAME = "role_data_fill"; public final static String DEPT_LINK_NAME = "dept_link"; public final static String DEPT_DATASET_NAME = "dept_dataset"; public final static String DEPT_PANEL_NAME = "dept_panel"; + public final static String DEPT_DATA_FILL_NAME = "dept_data_fill"; diff --git a/core/backend/src/main/java/io/dataease/commons/constants/DataFillConstants.java b/core/backend/src/main/java/io/dataease/commons/constants/DataFillConstants.java new file mode 100644 index 0000000000..f4a13f6c93 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/commons/constants/DataFillConstants.java @@ -0,0 +1,19 @@ +package io.dataease.commons.constants; + + +public class DataFillConstants { + + + public final static String DATA_FILL_NODE_TYPE_FOlDER = "folder"; + + public final static String DATA_FILL_NODE_TYPE_DATA_FILL = "data_fill"; + + public final static String OPT_TYPE_INSERT = "insert"; + + public final static String OPT_TYPE_UPDATE = "update"; + + + public final static String DATA_FILL_GATHER_DATA_FILL_LIST = "data_fill_list"; + + +} diff --git a/core/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java b/core/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java index dd2368d391..d8c4a9739d 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/DePermissionType.java @@ -1,5 +1,5 @@ package io.dataease.commons.constants; public enum DePermissionType { - DATASOURCE, DATASET, PANEL + DATASOURCE, DATASET, PANEL, DATA_FILL } diff --git a/core/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java b/core/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java index 99a389f270..de3e85a1ae 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/ResourceAuthLevel.java @@ -19,7 +19,12 @@ public enum ResourceAuthLevel { DATASOURCE_LEVEL_USE(1), DATASOURCE_LEVEL_MANAGE(3), - DATASOURCE_LEVEL_GRANT(15); + DATASOURCE_LEVEL_GRANT(15), + + + DATA_FILLING_LEVEL_USE(1), + DATA_FILLING_LEVEL_MANAGE(3), + DATA_FILLING_LEVEL_GRANT(15); private Integer level; diff --git a/core/backend/src/main/java/io/dataease/commons/constants/SysAuthConstants.java b/core/backend/src/main/java/io/dataease/commons/constants/SysAuthConstants.java index 051f273df1..c5f5485d2c 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/SysAuthConstants.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/SysAuthConstants.java @@ -19,4 +19,6 @@ public class SysAuthConstants { public final static String AUTH_SOURCE_TYPE_DATASOURCE = "link"; + public final static String AUTH_SOURCE_TYPE_DATA_FILLING = "data_fill"; + } diff --git a/core/backend/src/main/java/io/dataease/commons/constants/SysLogConstants.java b/core/backend/src/main/java/io/dataease/commons/constants/SysLogConstants.java index 6a4c0583c8..f0ed71f569 100644 --- a/core/backend/src/main/java/io/dataease/commons/constants/SysLogConstants.java +++ b/core/backend/src/main/java/io/dataease/commons/constants/SysLogConstants.java @@ -70,7 +70,10 @@ public class SysLogConstants { DRIVER(9, "SOURCE_TYPE_DRIVER"), DRIVER_FILE(10, "SOURCE_TYPE_DRIVER_FILE"), MENU(11, "SOURCE_TYPE_MENU"), - APIKEY(12, "SOURCE_TYPE_APIKEY"); + APIKEY(12, "SOURCE_TYPE_APIKEY"), + DATA_FILL_FORM(13,"SOURCE_TYPE_DATA_FILL_FORM"), + DATA_FILL_DATA(14,"SOURCE_TYPE_DATA_FILL_DATA"); + private Integer value; private String name; diff --git a/core/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java b/core/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java index b151519d8c..2360c19fa6 100644 --- a/core/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java +++ b/core/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java @@ -29,6 +29,7 @@ public class AuthUtils { private static final String[] defaultPanelPermissions = { "panel_list" }; private static final String[] defaultDataSetPermissions = { "0" }; private static final String[] defaultLinkPermissions = { "0" }; + private static final String[] defaultDataFillingPermissions = { "0" }; private static final ThreadLocal USER_INFO = new ThreadLocal(); @@ -138,6 +139,18 @@ public class AuthUtils { result.add(new AuthItem(item, ResourceAuthLevel.PANEL_LEVEL_MANAGE.getLevel())); }); return result; + } else if (StringUtils.equals(DePermissionType.DATA_FILL.name().toLowerCase(), type)) { + Set userSet = extAuthService.dataFillingIdByUser(userId).stream().collect(Collectors.toSet()); + Set roleSet = roles.stream().map(role -> extAuthService.dataFillingIdByRole(role.getId())) + .flatMap(Collection::stream).collect(Collectors.toSet()); + Set deptSet = extAuthService.dataFillingIdByDept(deptId).stream().collect(Collectors.toSet()); + result.addAll(userSet); + result.addAll(roleSet); + result.addAll(deptSet); + Arrays.stream(defaultDataFillingPermissions).forEach(item -> { + result.add(new AuthItem(item, ResourceAuthLevel.DATA_FILLING_LEVEL_MANAGE.getLevel())); + }); + return result; } return result; diff --git a/core/backend/src/main/java/io/dataease/controller/IndexController.java b/core/backend/src/main/java/io/dataease/controller/IndexController.java index 4eec795d31..98d16127a8 100644 --- a/core/backend/src/main/java/io/dataease/controller/IndexController.java +++ b/core/backend/src/main/java/io/dataease/controller/IndexController.java @@ -71,6 +71,10 @@ public class IndexController { if (StringUtils.isNotEmpty(fromLink)) { url = url + "&fromLink=" + fromLink; } + String ticket = request.getParameter("ticket"); + if (StringUtils.isNotEmpty(ticket)) { + url = url + "&ticket=" + ticket; + } response.sendRedirect(url); } catch (IOException e) { LogUtil.error(e.getMessage()); diff --git a/core/backend/src/main/java/io/dataease/controller/datafill/DataFillController.java b/core/backend/src/main/java/io/dataease/controller/datafill/DataFillController.java new file mode 100644 index 0000000000..902775d84c --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/datafill/DataFillController.java @@ -0,0 +1,177 @@ +package io.dataease.controller.datafill; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import io.dataease.commons.utils.AuthUtils; +import io.dataease.commons.utils.PageUtils; +import io.dataease.commons.utils.Pager; +import io.dataease.controller.ResultHolder; +import io.dataease.controller.request.datafill.*; +import io.dataease.controller.response.datafill.DataFillFormTableDataResponse; +import io.dataease.dto.datafill.DataFillCommitLogDTO; +import io.dataease.dto.datafill.DataFillFormDTO; +import io.dataease.dto.datafill.DataFillTaskDTO; +import io.dataease.dto.datafill.DataFillUserTaskDTO; +import io.dataease.plugins.common.base.domain.DataFillFormWithBLOBs; +import io.dataease.plugins.common.dto.datafill.ExtTableField; +import io.dataease.service.datafill.DataFillDataService; +import io.dataease.service.datafill.DataFillLogService; +import io.dataease.service.datafill.DataFillService; +import io.dataease.service.datafill.DataFillTaskService; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +@ApiIgnore +@RequestMapping("dataFilling") +@RestController +public class DataFillController { + + @Resource + private DataFillService dataFillService; + @Resource + private DataFillLogService dataFillLogService; + @Resource + private DataFillTaskService dataFillTaskService; + @Resource + private DataFillDataService dataFillDataService; + + + @ApiIgnore + @PostMapping("/form/save") + public ResultHolder saveForm(@RequestBody DataFillFormWithBLOBs dataFillForm) throws Exception { + return dataFillService.saveForm(dataFillForm); + } + + @ApiIgnore + @PostMapping("/form/update") + public ResultHolder updateForm(@RequestBody DataFillFormWithBLOBs dataFillForm) throws Exception { + return dataFillService.updateForm(dataFillForm); + } + + @PostMapping("/manage/form/{id}") + public DataFillFormDTO getWithPrivileges(@PathVariable String id) throws Exception { + return dataFillService.getWithPrivileges(id); + } + + @PostMapping("/form/get/{id}") + public DataFillFormWithBLOBs get(@PathVariable String id) throws Exception { + return dataFillService.get(id); + } + + @ApiIgnore + @PostMapping("/form/delete/{id}") + public void saveForm(@PathVariable String id) throws Exception { + dataFillService.deleteForm(id); + } + + @ApiOperation("查询树") + @PostMapping("/form/tree") + public List tree(@RequestBody DataFillFormRequest request) { + return dataFillService.tree(request); + } + + @ApiIgnore + @PostMapping("/form/{id}/tableData") + public DataFillFormTableDataResponse tableData(@PathVariable String id, @RequestBody DataFillFormTableDataRequest request) throws Exception { + request.setId(id); + return dataFillDataService.listData(request); + } + + @ApiIgnore + @PostMapping("/form/fields/{id}") + public List listFields(@PathVariable String id) throws Exception { + return dataFillService.listFields(id); + } + + @ApiIgnore + @PostMapping("/form/{formId}/delete/{id}") + public void deleteRowData(@PathVariable String formId, @PathVariable String id) throws Exception { + dataFillDataService.deleteRowData(formId, id); + } + + @ApiIgnore + @PostMapping("/form/{formId}/rowData/save") + public String newRowData(@PathVariable String formId, @RequestBody Map data) throws Exception { + return dataFillDataService.updateRowData(formId, null, data, true); + } + + @ApiIgnore + @PostMapping("/form/{formId}/rowData/save/{id}") + public String updateRowData(@PathVariable String formId, @PathVariable String id, @RequestBody Map data) throws Exception { + return dataFillDataService.updateRowData(formId, id, data, false); + } + + + @ApiIgnore + @PostMapping("/form/{formId}/commitLog/{goPage}/{pageSize}") + public Pager> commitLogs(@PathVariable String formId, @PathVariable int goPage, @PathVariable int pageSize, @RequestBody DataFillCommitLogSearchRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + List logs = dataFillLogService.commitLogs(formId, request); + + return PageUtils.setPageInfo(page, logs); + } + + @ApiIgnore + @PostMapping("/form/{formId}/task/{goPage}/{pageSize}") + public Pager> tasks(@PathVariable String formId, @PathVariable int goPage, @PathVariable int pageSize, @RequestBody DataFillTaskSearchRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + List tasks = dataFillTaskService.tasks(formId, request); + + return PageUtils.setPageInfo(page, tasks); + } + + @ApiIgnore + @PostMapping("/form/{formId}/task/save") + public void saveTask(@PathVariable String formId, @RequestBody DataFillTaskSearchRequest request) throws Exception { + + dataFillTaskService.saveTask(formId, request); + + } + + @ApiIgnore + @PostMapping("/form/task/{taskId}/delete") + public void deleteTask(@PathVariable Long taskId) { + + dataFillTaskService.deleteTask(taskId); + + } + + @ApiIgnore + @PostMapping("/form/task/{taskId}/enable") + public void enableTask(@PathVariable Long taskId) throws Exception { + + dataFillTaskService.enableTask(taskId); + + } + + @ApiIgnore + @PostMapping("/form/task/{taskId}/disable") + public void disableTask(@PathVariable Long taskId) throws Exception { + + dataFillTaskService.disableTask(taskId); + + } + + @ApiIgnore + @PostMapping("/myTask/{type}/{goPage}/{pageSize}") + public Pager> userTasks(@PathVariable String type, @PathVariable int goPage, @PathVariable int pageSize, @RequestBody DataFillUserTaskSearchRequest request) { + Long userId = AuthUtils.getUser().getUserId(); + Page page = PageHelper.startPage(goPage, pageSize, true); + List tasks = dataFillTaskService.userTasks(userId, type, request); + + return PageUtils.setPageInfo(page, tasks); + } + + + @ApiIgnore + @PostMapping("/myTask/fill/{taskId}") + public void userFillData(@PathVariable String taskId, @RequestBody Map data) throws Exception { + dataFillService.fillFormData(taskId, data); + } + +} diff --git a/core/backend/src/main/java/io/dataease/controller/handler/GlobalExceptionHandler.java b/core/backend/src/main/java/io/dataease/controller/handler/GlobalExceptionHandler.java index fcf37956f9..7a6839c874 100644 --- a/core/backend/src/main/java/io/dataease/controller/handler/GlobalExceptionHandler.java +++ b/core/backend/src/main/java/io/dataease/controller/handler/GlobalExceptionHandler.java @@ -2,7 +2,9 @@ package io.dataease.controller.handler; import io.dataease.controller.ResultHolder; import io.dataease.i18n.Translator; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authc.AuthenticationException; import org.slf4j.LoggerFactory; import org.springframework.boot.web.servlet.error.ErrorAttributes; import org.springframework.boot.web.servlet.error.ErrorController; @@ -49,7 +51,7 @@ public class GlobalExceptionHandler implements ErrorController { response.setStatus(code); String errorMessage = StringUtils.EMPTY; if (t != null) { - if (Logger.isDebugEnabled()) { + if (Logger.isDebugEnabled() && (ObjectUtils.isEmpty(t.getCause()) || !(t.getCause() instanceof AuthenticationException))) { Logger.error("Fail to proceed " + errorAttributeMap.get("path"), t); } errorMessage = t.getMessage(); diff --git a/core/backend/src/main/java/io/dataease/controller/panel/api/LinkApi.java b/core/backend/src/main/java/io/dataease/controller/panel/api/LinkApi.java index f6654d7d72..b43f21e5e6 100644 --- a/core/backend/src/main/java/io/dataease/controller/panel/api/LinkApi.java +++ b/core/backend/src/main/java/io/dataease/controller/panel/api/LinkApi.java @@ -84,4 +84,8 @@ public interface LinkApi { @ApiOperation("删除ticket") @PostMapping("/delTicket") void deleteTicket(@RequestBody TicketDelRequest request); + + @ApiOperation("切换是否必填ticket") + @PostMapping("/enableTicket") + void switchRequire(@RequestBody TicketSwitchRequest request); } diff --git a/core/backend/src/main/java/io/dataease/controller/panel/server/LinkServer.java b/core/backend/src/main/java/io/dataease/controller/panel/server/LinkServer.java index a88e6e7a1f..86b7a59b99 100644 --- a/core/backend/src/main/java/io/dataease/controller/panel/server/LinkServer.java +++ b/core/backend/src/main/java/io/dataease/controller/panel/server/LinkServer.java @@ -9,9 +9,11 @@ import io.dataease.controller.panel.api.LinkApi; import io.dataease.controller.request.chart.ChartExtRequest; import io.dataease.controller.request.panel.link.*; import io.dataease.dto.panel.link.GenerateDto; +import io.dataease.dto.panel.link.TicketDto; import io.dataease.dto.panel.link.ValidateDto; import io.dataease.plugins.common.base.domain.PanelGroupWithBLOBs; import io.dataease.plugins.common.base.domain.PanelLink; +import io.dataease.plugins.common.base.domain.PanelLinkMapping; import io.dataease.plugins.common.base.domain.PanelLinkTicket; import io.dataease.service.chart.ChartViewService; import io.dataease.service.panel.PanelLinkService; @@ -95,7 +97,8 @@ public class LinkServer implements LinkApi { dto.setValid(false); return dto; } - String mappingUuid = panelLinkService.getMappingUuid(one); + PanelLinkMapping mapping = panelLinkService.getMapping(one); + String mappingUuid = mapping.getUuid(); if (!StringUtils.equals(uuid, mappingUuid)) { dto.setValid(false); return dto; @@ -104,6 +107,10 @@ public class LinkServer implements LinkApi { dto.setEnablePwd(one.getEnablePwd()); dto.setPassPwd(panelLinkService.validateHeads(one)); dto.setExpire(panelLinkService.isExpire(one)); + + String ticketText = request.getTicket(); + TicketDto ticketDto = panelLinkService.validateTicket(ticketText, mapping); + dto.setTicket(ticketDto); return dto; } @@ -158,4 +165,9 @@ public class LinkServer implements LinkApi { public void deleteTicket(TicketDelRequest request) { panelLinkService.deleteTicket(request); } + + @Override + public void switchRequire(TicketSwitchRequest request) { + panelLinkService.switchRequire(request); + } } diff --git a/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillCommitLogSearchRequest.java b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillCommitLogSearchRequest.java new file mode 100644 index 0000000000..19f0a8d51e --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillCommitLogSearchRequest.java @@ -0,0 +1,18 @@ +package io.dataease.controller.request.datafill; + +import io.dataease.dto.datafill.DataFillCommitLogDTO; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + + +@Data +@Accessors(chain = true) +public class DataFillCommitLogSearchRequest extends DataFillCommitLogDTO { + + private static final long serialVersionUID = -1067572649791328116L; + + private List formIds; + +} diff --git a/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormRequest.java b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormRequest.java new file mode 100644 index 0000000000..3d922ee1ed --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormRequest.java @@ -0,0 +1,25 @@ +package io.dataease.controller.request.datafill; + +import io.dataease.plugins.common.base.domain.DataFillForm; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Set; + + +@Data +@Accessors(chain=true) +public class DataFillFormRequest extends DataFillForm { + + private static final long serialVersionUID = -6752223673862214909L; + + @ApiModelProperty("排序") + private String sort; + @ApiModelProperty("用户ID") + private String userId; + @ApiModelProperty("ID集合") + private Set ids; + @ApiModelProperty("排除的ID") + private String excludedId; +} diff --git a/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormTableDataRequest.java b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormTableDataRequest.java new file mode 100644 index 0000000000..ac4cf2a85e --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillFormTableDataRequest.java @@ -0,0 +1,19 @@ +package io.dataease.controller.request.datafill; + +import lombok.Data; +import lombok.experimental.Accessors; + + +@Data +@Accessors(chain=true) +public class DataFillFormTableDataRequest extends DataFillFormRequest { + + private static final long serialVersionUID = -314618516232771747L; + + private long currentPage; + + private long pageSize; + + private String primaryKeyValue; + +} diff --git a/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillTaskSearchRequest.java b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillTaskSearchRequest.java new file mode 100644 index 0000000000..0b5e4871ed --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillTaskSearchRequest.java @@ -0,0 +1,14 @@ +package io.dataease.controller.request.datafill; + +import io.dataease.dto.datafill.DataFillTaskDTO; +import lombok.Data; +import lombok.experimental.Accessors; + + +@Data +@Accessors(chain = true) +public class DataFillTaskSearchRequest extends DataFillTaskDTO { + + private static final long serialVersionUID = 5881604308639714955L; + +} diff --git a/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillUserTaskSearchRequest.java b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillUserTaskSearchRequest.java new file mode 100644 index 0000000000..7c170c46ad --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/datafill/DataFillUserTaskSearchRequest.java @@ -0,0 +1,14 @@ +package io.dataease.controller.request.datafill; + +import io.dataease.dto.datafill.DataFillUserTaskDTO; +import lombok.Data; +import lombok.experimental.Accessors; + + +@Data +@Accessors(chain = true) +public class DataFillUserTaskSearchRequest extends DataFillUserTaskDTO { + + private static final long serialVersionUID = 5881604308639714955L; + +} diff --git a/core/backend/src/main/java/io/dataease/controller/request/panel/link/LinkValidateRequest.java b/core/backend/src/main/java/io/dataease/controller/request/panel/link/LinkValidateRequest.java index 39ab661e36..f01f6091d9 100644 --- a/core/backend/src/main/java/io/dataease/controller/request/panel/link/LinkValidateRequest.java +++ b/core/backend/src/main/java/io/dataease/controller/request/panel/link/LinkValidateRequest.java @@ -9,4 +9,5 @@ public class LinkValidateRequest implements Serializable { private String link; private String user; + private String ticket; } diff --git a/core/backend/src/main/java/io/dataease/controller/request/panel/link/TicketSwitchRequest.java b/core/backend/src/main/java/io/dataease/controller/request/panel/link/TicketSwitchRequest.java new file mode 100644 index 0000000000..ff6727cbfc --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/request/panel/link/TicketSwitchRequest.java @@ -0,0 +1,13 @@ +package io.dataease.controller.request.panel.link; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class TicketSwitchRequest implements Serializable { + + private String resourceId; + + private Boolean require = false; +} diff --git a/core/backend/src/main/java/io/dataease/controller/response/datafill/DataFillFormTableDataResponse.java b/core/backend/src/main/java/io/dataease/controller/response/datafill/DataFillFormTableDataResponse.java new file mode 100644 index 0000000000..0f0b755e6d --- /dev/null +++ b/core/backend/src/main/java/io/dataease/controller/response/datafill/DataFillFormTableDataResponse.java @@ -0,0 +1,28 @@ +package io.dataease.controller.response.datafill; + +import io.dataease.plugins.common.dto.datafill.ExtTableField; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +@Data +@Accessors(chain = true) +public class DataFillFormTableDataResponse implements Serializable { + + private static final long serialVersionUID = -6463885075511811532L; + + private Object data; + + private List fields; + + private long total; + + private long currentPage; + + private long pageSize; + + private String key; + +} diff --git a/core/backend/src/main/java/io/dataease/dto/datafill/DataFillCommitLogDTO.java b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillCommitLogDTO.java new file mode 100644 index 0000000000..85fb8a6b1f --- /dev/null +++ b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillCommitLogDTO.java @@ -0,0 +1,18 @@ +package io.dataease.dto.datafill; + +import io.dataease.plugins.common.base.domain.DataFillCommitLog; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataFillCommitLogDTO extends DataFillCommitLog { + + private static final long serialVersionUID = 5324275156717345584L; + + private String commitByName; + + +} diff --git a/core/backend/src/main/java/io/dataease/dto/datafill/DataFillFormDTO.java b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillFormDTO.java new file mode 100644 index 0000000000..2bace84411 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillFormDTO.java @@ -0,0 +1,26 @@ +package io.dataease.dto.datafill; + +import io.dataease.plugins.common.base.domain.DataFillFormWithBLOBs; +import io.dataease.plugins.common.model.ITreeBase; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class DataFillFormDTO extends DataFillFormWithBLOBs implements ITreeBase { + + private static final long serialVersionUID = 1428065978308162738L; + + @ApiModelProperty("标签") + private String label; + @ApiModelProperty("子节点") + private List children; + @ApiModelProperty("权限") + private String privileges; + + private String creatorName; + private String datasourceName; + + +} diff --git a/core/backend/src/main/java/io/dataease/dto/datafill/DataFillTaskDTO.java b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillTaskDTO.java new file mode 100644 index 0000000000..17392bd4a3 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillTaskDTO.java @@ -0,0 +1,20 @@ +package io.dataease.dto.datafill; + +import io.dataease.plugins.common.base.domain.DataFillTaskWithBLOBs; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataFillTaskDTO extends DataFillTaskWithBLOBs { + + private static final long serialVersionUID = 3610753131867651856L; + + private String formName; + + private String creatorName; + + +} diff --git a/core/backend/src/main/java/io/dataease/dto/datafill/DataFillUserTaskDTO.java b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillUserTaskDTO.java new file mode 100644 index 0000000000..8a1c1c96f4 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/dto/datafill/DataFillUserTaskDTO.java @@ -0,0 +1,20 @@ +package io.dataease.dto.datafill; + +import io.dataease.plugins.common.base.domain.DataFillUserTask; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataFillUserTaskDTO extends DataFillUserTask { + + private static final long serialVersionUID = 3610753131867651856L; + + private String taskName; + private String formName; + private Long creator; + private String creatorName; + +} diff --git a/core/backend/src/main/java/io/dataease/dto/panel/link/TicketDto.java b/core/backend/src/main/java/io/dataease/dto/panel/link/TicketDto.java new file mode 100644 index 0000000000..e2deb6ee9b --- /dev/null +++ b/core/backend/src/main/java/io/dataease/dto/panel/link/TicketDto.java @@ -0,0 +1,15 @@ +package io.dataease.dto.panel.link; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class TicketDto implements Serializable { + + private boolean ticketValid; + + private boolean ticketExp; + + private String args; +} diff --git a/core/backend/src/main/java/io/dataease/dto/panel/link/ValidateDto.java b/core/backend/src/main/java/io/dataease/dto/panel/link/ValidateDto.java index 827bb012cd..c6671175ce 100644 --- a/core/backend/src/main/java/io/dataease/dto/panel/link/ValidateDto.java +++ b/core/backend/src/main/java/io/dataease/dto/panel/link/ValidateDto.java @@ -19,4 +19,6 @@ public class ValidateDto { private String resourceId; @ApiModelProperty("用户ID") private String userId; + + private TicketDto ticket; } diff --git a/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.java b/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.java new file mode 100644 index 0000000000..92595fc0e7 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.java @@ -0,0 +1,30 @@ +package io.dataease.ext; + +import io.dataease.controller.request.datafill.DataFillFormRequest; +import io.dataease.controller.request.datafill.DataFillTaskSearchRequest; +import io.dataease.dto.datafill.DataFillCommitLogDTO; +import io.dataease.dto.datafill.DataFillFormDTO; +import io.dataease.dto.datafill.DataFillTaskDTO; +import io.dataease.dto.datafill.DataFillUserTaskDTO; +import io.dataease.plugins.common.base.domain.DataFillTask; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +public interface ExtDataFillFormMapper { + List search(DataFillFormRequest request); + + Map searchChildrenIds(String id, String type); + + List selectLatestLogByFormDataIds(String formId, List dataIds); + + List selectDataFillLogs(String formId, String commitByName); + + List selectDataFillTasks(DataFillTaskSearchRequest request); + List selectActiveDataFillTasks(); + + List listTodoUserTask(long userId, Date current, String taskName); + List listFinishedUserTask(long userId, String taskName); + List listExpiredUserTask(long userId, Date current, String taskName); +} diff --git a/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.xml b/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.xml new file mode 100644 index 0000000000..a0ade02fbc --- /dev/null +++ b/core/backend/src/main/java/io/dataease/ext/ExtDataFillFormMapper.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/backend/src/main/java/io/dataease/ext/ExtSysLogMapper.xml b/core/backend/src/main/java/io/dataease/ext/ExtSysLogMapper.xml index 0a385b3cec..fbd52d7129 100644 --- a/core/backend/src/main/java/io/dataease/ext/ExtSysLogMapper.xml +++ b/core/backend/src/main/java/io/dataease/ext/ExtSysLogMapper.xml @@ -206,6 +206,21 @@ + + id, name + from data_fill_form + + id in + + #{id} + + ORDER BY FIELD(id, + + #{id} + + + + diff --git a/core/backend/src/main/java/io/dataease/job/sechedule/strategy/TaskHandler.java b/core/backend/src/main/java/io/dataease/job/sechedule/strategy/TaskHandler.java index fead202746..d79ac794ac 100644 --- a/core/backend/src/main/java/io/dataease/job/sechedule/strategy/TaskHandler.java +++ b/core/backend/src/main/java/io/dataease/job/sechedule/strategy/TaskHandler.java @@ -4,10 +4,11 @@ import io.dataease.commons.utils.CronUtils; import io.dataease.job.sechedule.ScheduleManager; import io.dataease.plugins.common.entity.GlobalTaskEntity; import org.apache.commons.lang3.ObjectUtils; -import org.quartz.*; +import org.quartz.JobDataMap; +import org.quartz.JobKey; +import org.quartz.TriggerKey; import org.springframework.beans.factory.InitializingBean; - import java.util.Date; public abstract class TaskHandler implements InitializingBean { diff --git a/core/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/DataFillTaskHandler.java b/core/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/DataFillTaskHandler.java new file mode 100644 index 0000000000..a872339b23 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/job/sechedule/strategy/impl/DataFillTaskHandler.java @@ -0,0 +1,184 @@ +package io.dataease.job.sechedule.strategy.impl; + +import io.dataease.auth.service.AuthUserService; +import io.dataease.commons.utils.CommonBeanFactory; +import io.dataease.commons.utils.CronUtils; +import io.dataease.service.datafill.DataFillTaskService; +import io.dataease.job.sechedule.ScheduleManager; +import io.dataease.job.sechedule.strategy.TaskHandler; +import io.dataease.plugins.common.base.domain.DataFillTaskWithBLOBs; +import io.dataease.plugins.common.entity.GlobalTaskEntity; +import io.dataease.plugins.common.util.SpringContextUtil; +import org.apache.commons.lang3.ObjectUtils; +import org.quartz.*; +import org.springframework.stereotype.Service; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +@Service("dataFillTaskHandler") +public class DataFillTaskHandler extends TaskHandler implements Job { + + + @Override + protected JobDataMap jobDataMap(GlobalTaskEntity taskEntity) { + JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.put("taskEntity", taskEntity); + + return jobDataMap; + } + + @Override + public void resetRunningInstance(Long taskId) { + + } + + @Override + protected Boolean taskIsRunning(Long taskId) { + return null; + } + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + // 插件没有加载 空转 + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) + return; + + JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); + GlobalTaskEntity taskEntity = (GlobalTaskEntity) jobDataMap.get("taskEntity"); + + ScheduleManager scheduleManager = SpringContextUtil.getBean(ScheduleManager.class); + + DataFillTaskService dataFillTaskService = SpringContextUtil.getBean(DataFillTaskService.class); + + DataFillTaskWithBLOBs task = dataFillTaskService.getTaskById(taskEntity.getTaskId()); + + try { + dataFillTaskService.createUserTasks(task, null); + + if (task.getRateType() == -1) { + //一次性任务执行完之后需要修改为停止 + dataFillTaskService.finishTask(task.getId()); + removeTask(scheduleManager, taskEntity); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void addTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) throws Exception { + + DataFillTaskService dataFillTaskService = SpringContextUtil.getBean(DataFillTaskService.class); + // 1。首先看看是否过期 + Long endTime = taskEntity.getEndTime(); + removeTask(scheduleManager, taskEntity); + if (CronUtils.taskExpire(endTime)) { // 过期了就删除任务 + dataFillTaskService.finishTask(taskEntity.getTaskId()); //状态置为已停止 + return; + } + if (!taskEntity.getStatus()) return; + JobKey jobKey = new JobKey("DATA_FILL_TASK_" + taskEntity.getTaskId().toString()); + TriggerKey triggerKey = new TriggerKey("DATA_FILL_TASK_" + taskEntity.getTaskId()); + Date start = new Date(taskEntity.getStartTime()); + Date end = null; + if (ObjectUtils.isNotEmpty(taskEntity.getEndTime())) { + end = new Date(taskEntity.getEndTime()); + } + Class executor = this.getClass(); + String cron = cron(taskEntity); + if (taskEntity.getRateType() == -1) { + long currentTriggerTime = System.currentTimeMillis() + 30 * 1000; //一次性的任务,确保下发成功,增加一点延时 + if (taskEntity.getStartTime() >= currentTriggerTime) { + currentTriggerTime = taskEntity.getStartTime(); + start = new Date(taskEntity.getStartTime() - 30 * 1000); + } + cron = cron(new Date(currentTriggerTime)); + } + scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, executor, cron, start, end, jobDataMap(taskEntity)); + } + + private static String cron(Date date) { + Calendar instance = Calendar.getInstance(); + instance.setTime(date); + + return instance.get(Calendar.SECOND) + " " + + instance.get(Calendar.MINUTE) + " " + + instance.get(Calendar.HOUR_OF_DAY) + " " + + instance.get(Calendar.DAY_OF_MONTH) + " " + + (instance.get(Calendar.MONTH) + 1) + " ? " + + instance.get(Calendar.YEAR); + } + + private static String cron(GlobalTaskEntity taskEntity) { + if (taskEntity.getRateType() == -1) { + return taskEntity.getRateVal(); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + Date date = null; + try { + date = sdf.parse(taskEntity.getRateVal()); + } catch (ParseException e) { + e.printStackTrace(); + } + java.util.Calendar instance = java.util.Calendar.getInstance(); + instance.setTime(date); + + if (taskEntity.getRateType() == 0) { + return instance.get(java.util.Calendar.SECOND) + " " + + instance.get(java.util.Calendar.MINUTE) + " " + + instance.get(java.util.Calendar.HOUR_OF_DAY) + " * * ?"; + } + if (taskEntity.getRateType() == 1) { + return instance.get(java.util.Calendar.SECOND) + " " + + instance.get(java.util.Calendar.MINUTE) + " " + + instance.get(java.util.Calendar.HOUR_OF_DAY) + " ? * " + + getWeekDayStr(instance.get(Calendar.DATE)); //这里是拿日当作周来保存的 + } + if (taskEntity.getRateType() == 2) { + return instance.get(java.util.Calendar.SECOND) + " " + + instance.get(java.util.Calendar.MINUTE) + " " + + instance.get(java.util.Calendar.HOUR_OF_DAY) + " " + + instance.get(Calendar.DATE) + " * ?"; + } + + return null; + } + + private static String getWeekDayStr(int day) { + switch (day) { + case 1: + return "MON"; + case 2: + return "TUE"; + case 3: + return "WED"; + case 4: + return "THU"; + case 5: + return "FRI"; + case 6: + return "SAT"; + case 7: + return "SUN"; + } + return "*"; + } + + @Override + public void removeTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) { + JobKey jobKey = new JobKey("DATA_FILL_TASK_" + taskEntity.getTaskId().toString()); + TriggerKey triggerKey = new TriggerKey("DATA_FILL_TASK_" + taskEntity.getTaskId()); + scheduleManager.removeJob(jobKey, triggerKey); + } + + @Override + public void executeTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) throws Exception { + JobKey jobKey = new JobKey("DATA_FILL_TASK_" + taskEntity.getTaskId().toString()); + scheduleManager.fireNow(jobKey); + } +} diff --git a/core/backend/src/main/java/io/dataease/listener/DataFillTaskStartListener.java b/core/backend/src/main/java/io/dataease/listener/DataFillTaskStartListener.java new file mode 100644 index 0000000000..4606418e85 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/listener/DataFillTaskStartListener.java @@ -0,0 +1,43 @@ +package io.dataease.listener; + +import io.dataease.auth.service.AuthUserService; +import io.dataease.service.datafill.DataFillTaskService; +import io.dataease.job.sechedule.ScheduleManager; +import io.dataease.job.sechedule.strategy.TaskHandler; +import io.dataease.job.sechedule.strategy.TaskStrategyFactory; +import io.dataease.plugins.common.entity.GlobalTaskEntity; +import io.dataease.plugins.common.util.SpringContextUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class DataFillTaskStartListener implements ApplicationListener { + + @Autowired + private AuthUserService authUserService; + + @Autowired + private ScheduleManager scheduleManager; + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + if (authUserService.pluginLoaded()) { + DataFillTaskService service = SpringContextUtil.getBean(DataFillTaskService.class); + + List tasks = service.listActiveTasksGlobalTaskEntity(); + tasks.stream().forEach(task -> { + TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(task.getTaskType()); + try { + taskHandler.resetRunningInstance(task.getTaskId()); + taskHandler.addTask(scheduleManager, task); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + } +} diff --git a/core/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java b/core/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java index 558e52c45a..a0f2e69173 100644 --- a/core/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java +++ b/core/backend/src/main/java/io/dataease/plugins/server/XOidcServer.java @@ -1,17 +1,27 @@ package io.dataease.plugins.server; +import io.dataease.commons.utils.LogUtil; +import io.dataease.plugins.common.exception.DataEaseException; import io.dataease.plugins.common.util.SpringContextUtil; import io.dataease.plugins.xpack.display.dto.response.SysSettingDto; import io.dataease.plugins.xpack.oidc.service.OidcXpackService; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import springfox.documentation.annotations.ApiIgnore; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; + @ApiIgnore @RequestMapping("/plugin/oidc") @RestController @@ -31,19 +41,19 @@ public class XOidcServer { oidcXpackService.save(settings); } - @PostMapping(value="/authInfo") + @PostMapping(value = "/authInfo") public Map authInfo() { OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class); Map result = new HashMap(); List oidcSettings = oidcXpackService.oidcSettings(); - + Map authParam = new HashMap<>(); authParam.put("response_type", "code"); authParam.put("state", "state"); - + oidcSettings.forEach(param -> { - if(StringUtils.isNotBlank(param.getParamKey())) { + if (StringUtils.isNotBlank(param.getParamKey())) { if (StringUtils.equals(param.getParamKey(), "oidc.authEndpoint")) { result.put("authEndpoint", param.getParamValue()); } @@ -53,10 +63,46 @@ public class XOidcServer { if (StringUtils.equals(param.getParamKey(), "oidc.clientId")) { authParam.put("client_id", param.getParamValue()); } + if (StringUtils.equals(param.getParamKey(), "oidc.pkce") && StringUtils.isNotBlank(param.getParamValue())) { + String pkceMethod = param.getParamValue(); + authParam.put("code_challenge_method", pkceMethod); + if (StringUtils.equalsIgnoreCase("S256", pkceMethod)) { + String verifier = generateVerifier(); + authParam.put("code_challenge", s256Challenge(verifier)); + authParam.put("state", verifier); + } else if (StringUtils.equalsIgnoreCase("plain", pkceMethod)) { + String verifier = generateVerifier(); + authParam.put("code_challenge", verifier); + authParam.put("state", verifier); + } else { + authParam.remove("code_challenge_method"); + } + } } - + }); result.put("authParam", authParam); return result; } + + private String generateVerifier() { + SecureRandom sr = new SecureRandom(); + byte[] code = new byte[32]; + sr.nextBytes(code); + return Base64.getUrlEncoder().withoutPadding().encodeToString(code); + } + + private String s256Challenge(String verifier) { + try { + byte[] bytes = verifier.getBytes(StandardCharsets.US_ASCII); + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(bytes, 0, bytes.length); + byte[] digest = md.digest(); + return org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(digest); + } catch (Exception e) { + LogUtil.error(e.getMessage()); + DataEaseException.throwException(e.getMessage()); + } + return null; + } } diff --git a/core/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java b/core/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java index 2f02c65665..dd12a8fd4a 100644 --- a/core/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java @@ -22,6 +22,7 @@ import io.dataease.plugins.datasource.provider.DefaultJdbcProvider; import io.dataease.plugins.datasource.provider.ExtendedJdbcClassLoader; import io.dataease.plugins.datasource.provider.ProviderFactory; import io.dataease.plugins.datasource.query.QueryProvider; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -76,6 +77,27 @@ public class JdbcProvider extends DefaultJdbcProvider { } } + public int execWithPreparedStatement(DatasourceRequest datasourceRequest) throws Exception { + JdbcConfiguration jdbcConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), JdbcConfiguration.class); + int queryTimeout = jdbcConfiguration.getQueryTimeout() > 0 ? jdbcConfiguration.getQueryTimeout() : 0; + try (Connection connection = getConnectionFromPool(datasourceRequest); PreparedStatement stat = getPreparedStatement(connection, queryTimeout, datasourceRequest.getQuery())) { + + if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) { + for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) { + stat.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType()); + } + } + + return stat.executeUpdate(); + + } catch (SQLException e) { + DataEaseException.throwException(e); + } catch (Exception e) { + DataEaseException.throwException(e); + } + return 0; + } + @Override public List getTableFields(DatasourceRequest datasourceRequest) throws Exception { @@ -110,6 +132,10 @@ public class JdbcProvider extends DefaultJdbcProvider { Set primaryKeySet = new HashSet<>(); while (primaryKeys.next()) { String tableName = primaryKeys.getString("TABLE_NAME"); + if (datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.mysql.name()) || datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.mariadb.name())) { + //这里因为旧版mysql驱动问题,需要特殊处理 + tableName = tableName.replaceAll("`", ""); + } String database; String schema = primaryKeys.getString("TABLE_SCHEM"); if (datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.pg.name()) || datasourceRequest.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.ck.name()) @@ -201,6 +227,7 @@ public class JdbcProvider extends DefaultJdbcProvider { } tableField.setRemarks(remarks); String dbType = resultSet.getString("TYPE_NAME").toUpperCase(); + tableField.setType(resultSet.getInt("DATA_TYPE")); tableField.setFieldType(dbType); if (dbType.equalsIgnoreCase("LONG")) { tableField.setFieldSize(65533); @@ -398,7 +425,16 @@ public class JdbcProvider extends DefaultJdbcProvider { List list = new LinkedList<>(); JdbcConfiguration jdbcConfiguration = new Gson().fromJson(dsr.getDatasource().getConfiguration(), JdbcConfiguration.class); int queryTimeout = jdbcConfiguration.getQueryTimeout() > 0 ? jdbcConfiguration.getQueryTimeout() : 0; - try (Connection connection = getConnectionFromPool(dsr); Statement stat = getStatement(connection, queryTimeout); ResultSet rs = stat.executeQuery(dsr.getQuery())) { + try (Connection connection = getConnectionFromPool(dsr); PreparedStatement stat = getPreparedStatement(connection, queryTimeout, dsr.getQuery())) { + + if (CollectionUtils.isNotEmpty(dsr.getTableFieldWithValues())) { + for (int i = 0; i < dsr.getTableFieldWithValues().size(); i++) { + stat.setObject(i + 1, dsr.getTableFieldWithValues().get(i).getValue(), dsr.getTableFieldWithValues().get(i).getType()); + } + } + + ResultSet rs = stat.executeQuery(); + list = getDataResult(rs, dsr); if (dsr.isPageable() && (dsr.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.sqlServer.name()) || dsr.getDatasource().getType().equalsIgnoreCase(DatasourceTypes.db2.name()))) { Integer realSize = dsr.getPage() * dsr.getPageSize() < list.size() ? dsr.getPage() * dsr.getPageSize() : list.size(); @@ -584,13 +620,13 @@ public class JdbcProvider extends DefaultJdbcProvider { jdbcClassLoader = extendedJdbcClassLoader; DeDriver driver = deDriverMapper.selectByPrimaryKey("default-" + datasourceRequest.getDatasource().getType()); - if(driver == null){ + if (driver == null) { for (DataSourceType value : SpringContextUtil.getApplicationContext().getBeansOfType(DataSourceType.class).values()) { if (value.getType().equalsIgnoreCase(datasourceRequest.getDatasource().getType())) { surpportVersions = value.getSurpportVersions(); } } - }else { + } else { surpportVersions = driver.getSurpportVersions(); } } else { diff --git a/core/backend/src/main/java/io/dataease/provider/engine/doris/DorisQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/engine/doris/DorisQueryProvider.java index 13b2c2f933..7b22212f9c 100644 --- a/core/backend/src/main/java/io/dataease/provider/engine/doris/DorisQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/engine/doris/DorisQueryProvider.java @@ -1437,7 +1437,7 @@ public class DorisQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java index e15e386923..50e6864457 100644 --- a/core/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java @@ -1379,7 +1379,7 @@ public class MysqlQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/ext/MysqlExtDDLProvider.java b/core/backend/src/main/java/io/dataease/provider/ext/MysqlExtDDLProvider.java new file mode 100644 index 0000000000..9758993090 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/provider/ext/MysqlExtDDLProvider.java @@ -0,0 +1,344 @@ +package io.dataease.provider.ext; + +import io.dataease.commons.utils.BeanUtils; +import io.dataease.plugins.common.dto.datafill.ExtIndexField; +import io.dataease.plugins.common.dto.datafill.ExtTableField; +import io.dataease.plugins.common.dto.datasource.TableField; +import io.dataease.plugins.common.request.datasource.DatasourceRequest; +import io.dataease.plugins.datasource.provider.DefaultExtDDLProvider; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +@Service("extMysqlDDLProvider") +public class MysqlExtDDLProvider extends DefaultExtDDLProvider { + + private static final String creatTableSql = + "CREATE TABLE `TABLE_NAME`" + + "Column_Fields" + " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;"; + + private static final String creatTableIndexSql = + "create index `INDEX_NAME` on `TABLE_NAME` (Column_Fields);"; + + private static final String dropTableSql = "DROP TABLE IF EXISTS `TABLE_NAME`"; + + @Override + public String dropTableSql(String table) { + return dropTableSql.replace("TABLE_NAME", table); + } + + @Override + public String createTableSql(String table, List formFields) { + //check inject + if (checkSqlInjection(table)) { + throw new RuntimeException("包含SQL注入的参数,请检查参数!"); + } + + List fields = convertTableFields(true, formFields); + String fieldSql = convertTableFieldsString(table, fields); + return creatTableSql.replace("TABLE_NAME", table).replace("Column_Fields", fieldSql); + } + + + @Override + public String searchSql(String table, List formFields, String whereSql, long limit, long offset) { + String baseSql = "SELECT $Column_Fields$ FROM `$TABLE_NAME$` $WHERE_SQL$ LIMIT $OFFSET_COUNT$, $LIMIT_COUNT$ ;"; + baseSql = baseSql.replace("$TABLE_NAME$", table) + .replace("$OFFSET_COUNT$", Long.toString(offset)) + .replace("$LIMIT_COUNT$", Long.toString(limit)); + if (StringUtils.isBlank(whereSql)) { + baseSql = baseSql.replace("$WHERE_SQL$", ""); + } else { + baseSql = baseSql.replace("$WHERE_SQL$", whereSql); + } + baseSql = baseSql.replace("$Column_Fields$", convertSearchFields(formFields)); + return baseSql; + } + + @Override + public String whereSql(String tableName, List searchFields) { + StringBuilder builder = new StringBuilder("WHERE 1 = 1 "); + for (TableField searchField : searchFields) { + //目前只考虑等于 + builder.append("AND $Column_Field$ = ? ".replace("$Column_Field$", searchField.getFieldName())); + } + return builder.toString(); + } + + @Override + public String countSql(String table, List formFields, String whereSql) { + String baseSql = "SELECT COUNT(1) FROM `$TABLE_NAME$` $WHERE_SQL$ ;"; + baseSql = baseSql.replace("$TABLE_NAME$", table); + if (StringUtils.isBlank(whereSql)) { + baseSql = baseSql.replace("$WHERE_SQL$", ""); + } else { + baseSql = baseSql.replace("$WHERE_SQL$", whereSql); + } + return baseSql; + } + + private String convertSearchFields(List formFields) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < formFields.size(); i++) { + TableField f = formFields.get(i); + if (StringUtils.equalsAnyIgnoreCase(f.getFieldType(), "datetime")) { + //特殊处理,全部使用统一格式输出 + builder.append("DATE_FORMAT(`").append(f.getFieldName()).append("`,'%Y-%m-%d %H:%i:%S')"); + } else { + builder.append("`").append(f.getFieldName()).append("`"); + } + if (i < formFields.size() - 1) { + builder.append(", "); + } + } + return builder.toString(); + } + + private List convertTableFields(boolean create, List formFields) { + List list = new ArrayList<>(); + if (create) { + list.add( + ExtTableField.TableField.builder() + .columnName("id") + .comment("ID") + .primaryKey(true) + .type(ExtTableField.BaseType.nvarchar) + .size(128) + .build() + ); + } + + for (ExtTableField formField : formFields) { + ExtTableField.TableField.TableFieldBuilder fieldBuilder = ExtTableField.TableField.builder() + .columnName(formField.getSettings().getMapping().getColumnName()) + .type(formField.getSettings().getMapping().getType()) + .comment(formField.getSettings().getName()) + .required(formField.getSettings().isRequired()); + if (StringUtils.equalsIgnoreCase(formField.getType(), "dateRange")) { + ExtTableField.TableField f1 = fieldBuilder + .columnName(formField.getSettings().getMapping().getColumnName1()) + .comment(formField.getSettings().getName() + " start") + .build(); + list.add(f1); + + ExtTableField.TableField f2 = BeanUtils.copyBean(new ExtTableField.TableField(), f1); + f2.setColumnName(formField.getSettings().getMapping().getColumnName2()); + f2.setComment(formField.getSettings().getName() + " end"); + list.add(f2); + } else { + list.add(fieldBuilder.build()); + } + } + + return list; + } + + @Override + public String deleteDataByIdSql(String table, DatasourceRequest.TableFieldWithValue pk) { + String deleteSql = "DELETE FROM `$TABLE_NAME$` WHERE `$PRIMARY_KEY$` = ?;"; + return deleteSql.replace("$TABLE_NAME$", table) + .replace("$PRIMARY_KEY$", pk.getFiledName()); + } + + private String convertFields(List fields) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < fields.size(); i++) { + DatasourceRequest.TableFieldWithValue f = fields.get(i); + builder.append("`").append(f.getFiledName()).append("`"); + if (i < fields.size() - 1) { + builder.append(", "); + } + } + + return builder.toString(); + } + + private String convertValueFields(List fields) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < fields.size(); i++) { + DatasourceRequest.TableFieldWithValue f = fields.get(i); + builder.append("?"); + if (i < fields.size() - 1) { + builder.append(", "); + } + } + + return builder.toString(); + } + + @Override + public String insertDataSql(String tableName, List fields) { + String sql = "INSERT INTO `$TABLE_NAME$`($Column_Fields$) VALUES ($Value_Fields$);"; + return sql.replace("$TABLE_NAME$", tableName) + .replace("$Column_Fields$", convertFields(fields)) + .replace("$Value_Fields$", convertValueFields(fields)); + } + + private String convertUpdateFields(List fields) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < fields.size(); i++) { + DatasourceRequest.TableFieldWithValue f = fields.get(i); + builder.append("`").append(f.getFiledName()).append("` = ?"); + if (i < fields.size() - 1) { + builder.append(", "); + } + } + + return builder.toString(); + } + + @Override + public String updateDataByIdSql(String tableName, List fields, DatasourceRequest.TableFieldWithValue pk) { + String sql = "UPDATE `$TABLE_NAME$` SET $Column_Fields$ WHERE `$PRIMARY_KEY$` = ?;"; + return sql.replace("$TABLE_NAME$", tableName) + .replace("$Column_Fields$", convertUpdateFields(fields)) + .replace("$PRIMARY_KEY$", pk.getFiledName()); + } + + @Override + public String checkUniqueValueSql(String tableName, DatasourceRequest.TableFieldWithValue field, DatasourceRequest.TableFieldWithValue pk) { + String sql = "SELECT COUNT(1) FROM `$TABLE_NAME$` WHERE `$Column_Field$` = ? $PRIMARY_KEY_CONDITION$;"; + + StringBuilder pkCondition = new StringBuilder(); + if (pk != null) { + pkCondition.append("AND `").append(pk.getFiledName()).append("` != ?"); + } + + return sql.replace("$TABLE_NAME$", tableName) + .replace("$Column_Field$", field.getFiledName()) + .replace("$PRIMARY_KEY_CONDITION$", pkCondition.toString()); + } + + private String convertTableFieldsString(String table, List fields) { + StringBuilder str = new StringBuilder(); + + str.append("(\n"); + + ExtTableField.TableField primaryKeyField = null; + for (ExtTableField.TableField field : fields) { + if (field.isPrimaryKey()) { + primaryKeyField = field; + } + + //check inject + if (checkSqlInjection(field.getColumnName())) { + throw new RuntimeException("包含SQL注入的参数,请检查参数!"); + } + + //column name + str.append("`").append(field.getColumnName()).append("` "); + //type + switch (field.getType()) { + case nvarchar: + str.append("NVARCHAR("); + if (field.getSize() != null && field.getSize() > 0) { + str.append(field.getSize()); + } else { + str.append(256); + } + str.append(") "); + break; + case number: + str.append("BIGINT("); + if (field.getSize() != null && field.getSize() > 0) { + str.append(field.getSize()); + } else { + str.append(20); + } + str.append(") "); + break; + case decimal: + str.append("DECIMAL("); + if (field.getSize() != null && field.getSize() > 0) { + str.append(field.getSize()); + } else { + str.append(20); + } + str.append(","); + if (field.getAccuracy() != null && field.getAccuracy() >= 0) { + str.append(field.getAccuracy()); + } else { + str.append(4); + } + str.append(") "); + break; + case datetime: + str.append("DATETIME "); + break; + default: + str.append("LONGTEXT "); + break; + } + + //必填 + if (field.isRequired()) { + str.append("NOT NULL "); + } + + //comment + str.append("COMMENT '").append(field.getComment()).append("' "); + + //换行 + str.append(",\n"); + + } + + if (primaryKeyField != null) { + str.append("constraint ") + .append(table) + .append("_pk ") + .append("PRIMARY KEY (") + .append("`") + .append(primaryKeyField.getColumnName()) + .append("`)"); + } + + str.append("\n)\n"); + + return str.toString(); + } + + @Override + public List createTableIndexSql(String table, List indexFields) { + List list = new ArrayList<>(); + for (ExtIndexField indexField : indexFields) { + String c = convertTableIndexSql(table, indexField); + if (StringUtils.isNotEmpty(c)) { + list.add(c); + } + } + return list; + } + + private String convertTableIndexSql(String table, ExtIndexField indexField) { + StringBuilder column = new StringBuilder(); + if (CollectionUtils.isEmpty(indexField.getColumns())) { + return null; + } + + //check inject + if (checkSqlInjection(table) || checkSqlInjection(indexField.getName())) { + throw new RuntimeException("包含SQL注入的参数,请检查参数!"); + } + + int count = 0; + for (ExtIndexField.ColumnSetting indexFieldColumn : indexField.getColumns()) { + count++; + column.append("`").append(indexFieldColumn.getColumn()).append("` "); + if (StringUtils.equalsIgnoreCase(indexFieldColumn.getOrder(), "asc")) { + column.append("asc"); + } else if (StringUtils.equalsIgnoreCase(indexFieldColumn.getOrder(), "desc")) { + column.append("desc"); + } + if (count < indexField.getColumns().size()) { + column.append(", "); + } + } + + return creatTableIndexSql.replace("TABLE_NAME", table).replace("INDEX_NAME", indexField.getName()).replace("Column_Fields", column.toString()); + } +} diff --git a/core/backend/src/main/java/io/dataease/provider/query/ck/CKQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/ck/CKQueryProvider.java index a75fb8e006..f7cd5d8111 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/ck/CKQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/ck/CKQueryProvider.java @@ -1480,7 +1480,7 @@ public class CKQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/db2/Db2QueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/db2/Db2QueryProvider.java index b5d1bb8c3a..2dd9ea9ce1 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/db2/Db2QueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/db2/Db2QueryProvider.java @@ -1476,7 +1476,7 @@ public class Db2QueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/es/EsQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/es/EsQueryProvider.java index 7b5e2f579b..90de48bbaf 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/es/EsQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/es/EsQueryProvider.java @@ -1403,7 +1403,7 @@ public class EsQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "UCASE(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/hive/HiveQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/hive/HiveQueryProvider.java index cef882d2df..c5bbb6fbea 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/hive/HiveQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/hive/HiveQueryProvider.java @@ -1360,7 +1360,7 @@ public class HiveQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java index 854c5cb5db..3950fac6a3 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java @@ -1380,7 +1380,7 @@ public class ImpalaQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java index 04dcd4c24f..324a71fcdf 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java @@ -1235,7 +1235,7 @@ public class MongoQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java index 2b8f03a8d5..74fe391f29 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/mysql/MysqlQueryProvider.java @@ -1444,7 +1444,7 @@ public class MysqlQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/oracle/OracleQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/oracle/OracleQueryProvider.java index 5e6e02dbf4..dfcc5ccbbe 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/oracle/OracleQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/oracle/OracleQueryProvider.java @@ -1549,7 +1549,7 @@ public class OracleQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/pg/PgQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/pg/PgQueryProvider.java index acb6a7c212..a18e0cc6f7 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/pg/PgQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/pg/PgQueryProvider.java @@ -1400,7 +1400,7 @@ public class PgQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/redshift/RedshiftQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/redshift/RedshiftQueryProvider.java index c9cad1148c..78c4ef1355 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/redshift/RedshiftQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/redshift/RedshiftQueryProvider.java @@ -1386,7 +1386,7 @@ public class RedshiftQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == 1) { diff --git a/core/backend/src/main/java/io/dataease/provider/query/sqlserver/SqlserverQueryProvider.java b/core/backend/src/main/java/io/dataease/provider/query/sqlserver/SqlserverQueryProvider.java index dcc63f3a5a..37b0e78a00 100644 --- a/core/backend/src/main/java/io/dataease/provider/query/sqlserver/SqlserverQueryProvider.java +++ b/core/backend/src/main/java/io/dataease/provider/query/sqlserver/SqlserverQueryProvider.java @@ -1532,7 +1532,7 @@ public class SqlserverQueryProvider extends QueryProvider { } } else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) { String keyword = value.get(0).toUpperCase(); - whereValue = "'%" + keyword + "%'"; + whereValue = formatLikeValue(keyword); whereName = "upper(" + whereName + ")"; } else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) { if (request.getDatasetTableField().getDeType() == DeTypeConstants.DE_TIME) { diff --git a/core/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/core/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index 75fece5654..27d0fe943e 100644 --- a/core/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/core/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -731,7 +731,11 @@ public class ChartViewService { } if (chartExtRequest.getPageSize() == null) { String pageSize = (String) mapSize.get("tablePageSize"); - chartExtRequest.setPageSize(Math.min(Long.parseLong(pageSize), view.getResultCount().longValue())); + if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { + chartExtRequest.setPageSize(Math.min(Long.parseLong(pageSize), view.getResultCount().longValue())); + } else { + chartExtRequest.setPageSize(Long.parseLong(pageSize)); + } } } else { if (StringUtils.equalsIgnoreCase(view.getResultMode(), "custom")) { @@ -1856,7 +1860,7 @@ public class ChartViewService { } Date date = simpleDateFormat.parse(cTime); calendar.setTime(date); - calendar.add(Calendar.DAY_OF_YEAR,6);// 加6天用一周最后一天计算周,可避免跨年的问题 + calendar.add(Calendar.DAY_OF_YEAR, 6);// 加6天用一周最后一天计算周,可避免跨年的问题 calendar.add(Calendar.WEEK_OF_YEAR, -1); lastTime = simpleDateFormat.format(calendar.getTime()); } diff --git a/core/backend/src/main/java/io/dataease/service/datafill/DataFillDataService.java b/core/backend/src/main/java/io/dataease/service/datafill/DataFillDataService.java new file mode 100644 index 0000000000..de9a4067b0 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/service/datafill/DataFillDataService.java @@ -0,0 +1,406 @@ +package io.dataease.service.datafill; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import io.dataease.auth.service.AuthUserService; +import io.dataease.commons.utils.CommonBeanFactory; +import io.dataease.controller.request.datafill.DataFillFormTableDataRequest; +import io.dataease.controller.response.datafill.DataFillFormTableDataResponse; +import io.dataease.dto.datafill.DataFillCommitLogDTO; +import io.dataease.ext.ExtDataFillFormMapper; +import io.dataease.plugins.common.base.domain.DataFillFormWithBLOBs; +import io.dataease.plugins.common.base.domain.Datasource; +import io.dataease.plugins.common.base.mapper.DataFillFormMapper; +import io.dataease.plugins.common.dto.datafill.ExtTableField; +import io.dataease.plugins.common.dto.datasource.TableField; +import io.dataease.plugins.common.exception.DataEaseException; +import io.dataease.plugins.common.request.datasource.DatasourceRequest; +import io.dataease.plugins.datasource.provider.ExtDDLProvider; +import io.dataease.plugins.datasource.provider.Provider; +import io.dataease.plugins.datasource.provider.ProviderFactory; +import io.dataease.provider.datasource.JdbcProvider; +import io.dataease.service.datasource.DatasourceService; +import io.dataease.service.sys.SysAuthService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.pentaho.di.core.util.UUIDUtil; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Transactional(rollbackFor = Exception.class) +public class DataFillDataService { + + @Resource + private Environment env; + @Resource + private DataFillFormMapper dataFillFormMapper; + @Resource + private ExtDataFillFormMapper extDataFillFormMapper; + @Resource + private DatasourceService datasource; + @Resource + private SysAuthService sysAuthService; + + @Resource + private DataFillLogService dataFillLogService; + + + private final static Gson gson = new Gson(); + + + public DataFillFormTableDataResponse listData(DataFillFormTableDataRequest searchRequest) throws Exception { + + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(searchRequest.getId()); + + if (StringUtils.equals(dataFillForm.getNodeType(), "folder")) { + return null; + } + List fields = gson.fromJson(dataFillForm.getForms(), new TypeToken>() { + }.getType()); + + Datasource ds = datasource.get(dataFillForm.getDatasource()); + Provider datasourceProvider = ProviderFactory.getProvider(ds.getType()); + + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(ds); + datasourceRequest.setTable(dataFillForm.getTableName()); + List tableFields = datasourceProvider.getTableFields(datasourceRequest); + Map extTableFieldTypeMap = new HashMap<>(); + Map tableFieldMap = new HashMap<>(); + List searchFields = new ArrayList<>(); + + String key = ""; + TableField pk = null; + + for (TableField tableField : tableFields) { + if (tableField.isPrimaryKey()) { + //先把ID放进来 + searchFields.add(tableField); + key = tableField.getFieldName(); + pk = tableField; + } + tableFieldMap.put(tableField.getFieldName(), tableField); + } + + //核对一下字段 + for (ExtTableField field : fields) { + if (StringUtils.equalsIgnoreCase(field.getType(), "dateRange")) { + String name1 = field.getSettings().getMapping().getColumnName1(); + extTableFieldTypeMap.put(name1, field.getSettings().getMapping().getType()); + TableField f1 = tableFieldMap.get(name1); + if (f1 != null) { + //调整类型,给后面解析字段用 + f1.setFieldType(field.getSettings().getMapping().getType().name()); + searchFields.add(f1); + } + String name2 = field.getSettings().getMapping().getColumnName2(); + extTableFieldTypeMap.put(name2, field.getSettings().getMapping().getType()); + TableField f2 = tableFieldMap.get(name2); + if (f2 != null) { + //调整类型,给后面解析字段用 + f2.setFieldType(field.getSettings().getMapping().getType().name()); + searchFields.add(f2); + } + } else { + String name = field.getSettings().getMapping().getColumnName(); + extTableFieldTypeMap.put(name, field.getSettings().getMapping().getType()); + TableField f = tableFieldMap.get(field.getSettings().getMapping().getColumnName()); + if (f != null) { + //调整类型,给后面解析字段用 + f.setFieldType(field.getSettings().getMapping().getType().name()); + searchFields.add(f); + } + } + } + + ExtDDLProvider extDDLProvider = ProviderFactory.gerExtDDLProvider(ds.getType()); + + String whereSql = ""; + if (StringUtils.isNoneBlank(searchRequest.getPrimaryKeyValue())) { + whereSql = extDDLProvider.whereSql(dataFillForm.getTableName(), List.of(pk)); + } + + String countSql = extDDLProvider.countSql(dataFillForm.getTableName(), searchFields, whereSql); + if (StringUtils.isNoneBlank(searchRequest.getPrimaryKeyValue())) { + datasourceRequest.setTableFieldWithValues(List.of(new DatasourceRequest.TableFieldWithValue() + .setValue(searchRequest.getPrimaryKeyValue()) + .setFiledName(pk.getFieldName()) + .setTypeName(pk.getFieldType()) + .setType(pk.getType()))); + } + datasourceRequest.setQuery(countSql); + List countData = datasourceProvider.getData(datasourceRequest); + long count = NumberUtils.toLong(countData.get(0)[0]); + + String searchSql = extDDLProvider.searchSql(dataFillForm.getTableName(), searchFields, whereSql, searchRequest.getPageSize(), (searchRequest.getCurrentPage() - 1) * searchRequest.getPageSize()); + datasourceRequest.setQuery(searchSql); + + List data2 = datasourceProvider.getData(datasourceRequest); + List> result = new ArrayList<>(); + List> resultList = new ArrayList<>(); + + List ids = new ArrayList<>(); + + for (String[] strings : data2) { + Map object = new HashMap<>(); + for (int i = 0; i < searchFields.size(); i++) { + TableField f = searchFields.get(i); + String name = f.getFieldName(); + String data = strings[i]; + if (data == null) { + object.put(name, null); + continue; + } + + if (StringUtils.equals(key, name)) { + ids.add(strings[i]); + } + + ExtTableField.BaseType extFieldType = extTableFieldTypeMap.get(name); + if (extFieldType != null) { + switch (extFieldType) { + case number: + object.put(name, NumberUtils.toLong(strings[i])); + break; + case decimal: + object.put(name, new BigDecimal(strings[i])); + break; + case datetime: + SimpleDateFormat sdf = new SimpleDateFormat(extDDLProvider.DEFAULT_DATE_FORMAT_STR); + object.put(name, sdf.parse(strings[i])); + break; + default: + object.put(name, strings[i]); + break; + } + } else { + object.put(name, strings[i]); + } + } + result.add(object); + } + + + List list = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(ids)) { + list = extDataFillFormMapper.selectLatestLogByFormDataIds(dataFillForm.getId(), ids); + } + Map logMap = list.stream().collect(Collectors.toMap(log -> log.getFormId() + "__" + log.getDataId(), log -> log)); + + for (Map object : result) { + Map temp = new HashMap<>(); + temp.put("data", object); + temp.put("logInfo", logMap.get(dataFillForm.getId() + "__" + object.get(key))); + + resultList.add(temp); + } + + + return new DataFillFormTableDataResponse() + .setKey(key) + .setData(resultList) + .setFields(fields) + .setTotal(count) + .setPageSize(searchRequest.getPageSize()) + .setCurrentPage(searchRequest.getCurrentPage()); + } + + + public void deleteRowData(String formId, String id) throws Exception { + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(formId); + + if (StringUtils.equals(dataFillForm.getNodeType(), "folder")) { + return; + } + Datasource ds = datasource.get(dataFillForm.getDatasource()); + + ExtDDLProvider extDDLProvider = ProviderFactory.gerExtDDLProvider(ds.getType()); + + Provider datasourceProvider = ProviderFactory.getProvider(ds.getType()); + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(ds); + datasourceRequest.setTable(dataFillForm.getTableName()); + List tableFields = datasourceProvider.getTableFields(datasourceRequest).stream().filter(TableField::isPrimaryKey).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(tableFields)) { + throw new RuntimeException("没有主键"); + } + TableField key = tableFields.get(0); + + DatasourceRequest.TableFieldWithValue pk = new DatasourceRequest.TableFieldWithValue() + .setValue(id) //todo 有可能是数字 + .setFiledName(key.getFieldName()) + .setTypeName(key.getFieldType()) + .setType(key.getType()); + + String deleteSql = extDDLProvider.deleteDataByIdSql(dataFillForm.getTableName(), pk); + + datasourceRequest.setQuery(deleteSql); + datasourceRequest.setTableFieldWithValues(List.of(pk)); + + JdbcProvider jdbcProvider = CommonBeanFactory.getBean(JdbcProvider.class); + jdbcProvider.execWithPreparedStatement(datasourceRequest); + + dataFillLogService.saveCommitOperation(DataFillLogService.COMMIT_OPERATE_DELETE, dataFillForm.getId(), id); + + } + + public String updateRowData(String formId, String rowId, Map data, boolean insert) throws Exception { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + if (rowId == null) { + insert = true; + //先默认主键是uuid + rowId = UUIDUtil.getUUIDAsString(); + } + + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(formId); + + List fields = gson.fromJson(dataFillForm.getForms(), new TypeToken>() { + }.getType()); + + Datasource ds = datasource.get(dataFillForm.getDatasource()); + Provider datasourceProvider = ProviderFactory.getProvider(ds.getType()); + + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(ds); + datasourceRequest.setTable(dataFillForm.getTableName()); + List tableFields = datasourceProvider.getTableFields(datasourceRequest); + + Map tableFieldMap = new HashMap<>(); + + List searchFields = new ArrayList<>(); + List uniqueFields = new ArrayList<>(); + Map extTableFields = new HashMap<>(); + + DatasourceRequest.TableFieldWithValue pk = null; + for (TableField tableField : tableFields) { + if (tableField.isPrimaryKey()) { + pk = new DatasourceRequest.TableFieldWithValue() + .setValue(rowId) + .setFiledName(tableField.getFieldName()) + .setTypeName(tableField.getFieldType()) + .setType(tableField.getType()); + if (insert) { + searchFields.add(pk); + } + continue; + } + tableFieldMap.put(tableField.getFieldName(), tableField); + } + + for (ExtTableField field : fields) { + if (StringUtils.equalsIgnoreCase(field.getType(), "dateRange")) { + String name1 = field.getSettings().getMapping().getColumnName1(); + String name2 = field.getSettings().getMapping().getColumnName2(); + if (tableFieldMap.containsKey(name1) && data.containsKey(name1) && data.get(name1) != null) { + DatasourceRequest.TableFieldWithValue value1 = new DatasourceRequest.TableFieldWithValue() + .setValue(new java.sql.Date((long) data.get(name1))) + .setFiledName(name1) + .setTypeName(tableFieldMap.get(name1).getFieldType()) + .setType(tableFieldMap.get(name1).getType()); + searchFields.add(value1); + extTableFields.put(name1, field); + } + if (tableFieldMap.containsKey(name2) && data.containsKey(name2) && data.get(name2) != null) { + DatasourceRequest.TableFieldWithValue value2 = new DatasourceRequest.TableFieldWithValue() + .setValue(new java.sql.Date((long) data.get(name2))) + .setFiledName(name2) + .setTypeName(tableFieldMap.get(name2).getFieldType()) + .setType(tableFieldMap.get(name2).getType()); + searchFields.add(value2); + extTableFields.put(name2, field); + } + } else { + String name = field.getSettings().getMapping().getColumnName(); + if (tableFieldMap.containsKey(name) && data.containsKey(name) && data.get(name) != null) { + DatasourceRequest.TableFieldWithValue value = new DatasourceRequest.TableFieldWithValue() + .setValue(data.get(name)) + .setFiledName(name) + .setTypeName(tableFieldMap.get(name).getFieldType()) + .setType(tableFieldMap.get(name).getType()); + + if (StringUtils.equalsIgnoreCase(field.getType(), "date")) { + value.setValue(new java.sql.Date((long) data.get(name))); + } + searchFields.add(value); + + extTableFields.put(name, field); + + // 关于unique的字段判断 + if (field.getSettings().isUnique()) { + + uniqueFields.add(value); + } + } + } + } + + ExtDDLProvider extDDLProvider = ProviderFactory.gerExtDDLProvider(ds.getType()); + + if (CollectionUtils.isNotEmpty(uniqueFields)) { + for (DatasourceRequest.TableFieldWithValue uniqueField : uniqueFields) { + + String sql = extDDLProvider.checkUniqueValueSql(dataFillForm.getTableName(), uniqueField, insert ? null : pk); + datasourceRequest.setQuery(sql); + List fs = new ArrayList<>(); + fs.add(uniqueField); + if (!insert) { + fs.add(pk); + } + datasourceRequest.setTableFieldWithValues(fs); + List countData = datasourceProvider.getData(datasourceRequest); + long count = NumberUtils.toLong(countData.get(0)[0]); + + if (count > 0) { + DataEaseException.throwException(extTableFields.get(uniqueField.getFiledName()).getSettings().getName() + " 值不能重复"); + } + } + } + + String sql = insert ? + extDDLProvider.insertDataSql(dataFillForm.getTableName(), searchFields) : + extDDLProvider.updateDataByIdSql(dataFillForm.getTableName(), searchFields, pk); + datasourceRequest.setQuery(sql); + + boolean skip = false; + if (!insert && CollectionUtils.isEmpty(searchFields)) { + //DataEaseException.throwException("没有修改"); + skip = true; + } + + JdbcProvider jdbcProvider = CommonBeanFactory.getBean(JdbcProvider.class); + + // 主键在最后传进去 + if (!insert) { + searchFields.add(pk); + } + datasourceRequest.setTableFieldWithValues(searchFields); + + if (!skip) { + int result = jdbcProvider.execWithPreparedStatement(datasourceRequest); + } + + if (insert) { + dataFillLogService.saveCommitOperation(DataFillLogService.COMMIT_OPERATE_INSERT, dataFillForm.getId(), rowId); + } else { + dataFillLogService.saveCommitOperation(DataFillLogService.COMMIT_OPERATE_UPDATE, dataFillForm.getId(), rowId); + } + + return rowId; + } + +} diff --git a/core/backend/src/main/java/io/dataease/service/datafill/DataFillLogService.java b/core/backend/src/main/java/io/dataease/service/datafill/DataFillLogService.java new file mode 100644 index 0000000000..f14db1fe68 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/service/datafill/DataFillLogService.java @@ -0,0 +1,51 @@ +package io.dataease.service.datafill; + +import io.dataease.commons.utils.AuthUtils; +import io.dataease.controller.request.datafill.DataFillCommitLogSearchRequest; +import io.dataease.dto.datafill.DataFillCommitLogDTO; +import io.dataease.ext.ExtDataFillFormMapper; +import io.dataease.plugins.common.base.domain.DataFillCommitLog; +import io.dataease.plugins.common.base.mapper.DataFillCommitLogMapper; +import org.pentaho.di.core.util.UUIDUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +@Service +@Transactional(rollbackFor = Exception.class) +public class DataFillLogService { + + @Resource + private ExtDataFillFormMapper extDataFillFormMapper; + + @Resource + private DataFillCommitLogMapper dataFillCommitLogMapper; + + + public static final String COMMIT_OPERATE_INSERT = "INSERT"; + public static final String COMMIT_OPERATE_UPDATE = "UPDATE"; + public static final String COMMIT_OPERATE_DELETE = "DELETE"; + + + public List commitLogs(String formId, DataFillCommitLogSearchRequest request) { + + + return extDataFillFormMapper.selectDataFillLogs(formId, request.getCommitByName()); + + } + + public void saveCommitOperation(String operate, String formId, String dataId) { + DataFillCommitLog log = new DataFillCommitLog(); + log.setId(UUIDUtil.getUUIDAsString()); + log.setFormId(formId); + log.setDataId(dataId); + log.setCommitBy(AuthUtils.getUser().getUsername()); + log.setOperate(operate); + log.setCommitTime(new Date()); + + dataFillCommitLogMapper.insertSelective(log); + } +} diff --git a/core/backend/src/main/java/io/dataease/service/datafill/DataFillService.java b/core/backend/src/main/java/io/dataease/service/datafill/DataFillService.java new file mode 100644 index 0000000000..745c1eeb95 --- /dev/null +++ b/core/backend/src/main/java/io/dataease/service/datafill/DataFillService.java @@ -0,0 +1,334 @@ +package io.dataease.service.datafill; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import io.dataease.auth.annotation.DeCleaner; +import io.dataease.auth.service.AuthUserService; +import io.dataease.commons.constants.*; +import io.dataease.commons.utils.*; +import io.dataease.controller.ResultHolder; +import io.dataease.controller.request.datafill.DataFillFormRequest; +import io.dataease.dto.DatasourceDTO; +import io.dataease.dto.datafill.DataFillFormDTO; +import io.dataease.ext.ExtDataFillFormMapper; +import io.dataease.i18n.Translator; +import io.dataease.listener.util.CacheUtils; +import io.dataease.plugins.common.base.domain.*; +import io.dataease.plugins.common.base.mapper.DataFillFormMapper; +import io.dataease.plugins.common.base.mapper.DataFillUserTaskMapper; +import io.dataease.plugins.common.base.mapper.SysUserMapper; +import io.dataease.plugins.common.dto.datafill.ExtIndexField; +import io.dataease.plugins.common.dto.datafill.ExtTableField; +import io.dataease.plugins.common.dto.datasource.TableField; +import io.dataease.plugins.common.exception.DataEaseException; +import io.dataease.plugins.common.request.datasource.DatasourceRequest; +import io.dataease.plugins.datasource.provider.ExtDDLProvider; +import io.dataease.plugins.datasource.provider.Provider; +import io.dataease.plugins.datasource.provider.ProviderFactory; +import io.dataease.provider.datasource.JdbcProvider; +import io.dataease.service.datasource.DatasourceService; +import io.dataease.service.sys.SysAuthService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.pentaho.di.core.util.UUIDUtil; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Transactional(rollbackFor = Exception.class) +public class DataFillService { + + @Resource + private Environment env; + @Resource + private DataFillFormMapper dataFillFormMapper; + @Resource + private ExtDataFillFormMapper extDataFillFormMapper; + @Resource + private DatasourceService datasource; + @Resource + private SysAuthService sysAuthService; + @Resource + private SysUserMapper sysUserMapper; + @Resource + private DataFillTaskService dataFillTaskService; + @Resource + private DataFillDataService dataFillDataService; + @Resource + private DataFillUserTaskMapper dataFillUserTaskMapper; + + + private final static Gson gson = new Gson(); + + + @DeCleaner(value = DePermissionType.DATA_FILL, key = "pid") + public ResultHolder saveForm(DataFillFormWithBLOBs dataFillForm) throws Exception { + + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + String uuid = UUIDUtil.getUUID().toString(); + + dataFillForm.setId(uuid); + + checkName(uuid, dataFillForm.getName(), dataFillForm.getPid(), dataFillForm.getLevel(), dataFillForm.getNodeType(), DataFillConstants.OPT_TYPE_INSERT); + + if (!StringUtils.equals(dataFillForm.getNodeType(), "folder")) { + List fields = gson.fromJson(dataFillForm.getForms(), new TypeToken>() { + }.getType()); + + List indexes = new ArrayList<>(); + if (dataFillForm.getCreateIndex()) { + indexes = gson.fromJson(dataFillForm.getTableIndexes(), new TypeToken>() { + }.getType()); + } + + DatasourceDTO datasourceDTO = datasource.getDataSourceDetails(dataFillForm.getDatasource()); + + datasourceDTO.setConfiguration(new String(java.util.Base64.getDecoder().decode(datasourceDTO.getConfiguration()))); + + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(datasourceDTO); + datasourceRequest.setQuery("SELECT VERSION()"); + + JdbcProvider jdbcProvider = CommonBeanFactory.getBean(JdbcProvider.class); + String version = jdbcProvider.getData(datasourceRequest).get(0)[0]; + + //拼sql + ExtDDLProvider extDDLProvider = ProviderFactory.gerExtDDLProvider(datasourceDTO.getType()); + String sql = extDDLProvider.createTableSql(dataFillForm.getTableName(), fields); + //创建表 + datasourceRequest.setQuery(sql); + jdbcProvider.exec(datasourceRequest); + + if (dataFillForm.getCreateIndex()) { + try { + List sqls = extDDLProvider.createTableIndexSql(dataFillForm.getTableName(), indexes); + + for (String indexSql : sqls) { + datasourceRequest.setQuery(indexSql); + jdbcProvider.exec(datasourceRequest); + } + } catch (Exception e) { + // 执行到这里说明表已经建成功了,创建index出错,那就需要回滚删除创建的表 + datasourceRequest.setQuery(extDDLProvider.dropTableSql(dataFillForm.getTableName())); + jdbcProvider.exec(datasourceRequest); + + throw e; + } + + } + } + + dataFillForm.setCreateBy(AuthUtils.getUser().getUsername()); + dataFillForm.setUpdateBy(AuthUtils.getUser().getUsername()); + Date current = new Date(); + dataFillForm.setCreateTime(current); + dataFillForm.setUpdateTime(current); + + dataFillFormMapper.insertSelective(dataFillForm); + + // 清理权限缓存,应该不需要 + //clearPermissionCache(); + + DeLogUtils.save(SysLogConstants.OPERATE_TYPE.CREATE, SysLogConstants.SOURCE_TYPE.DATA_FILL_FORM, dataFillForm.getId(), dataFillForm.getPid(), null, null); + + sysAuthService.copyAuth(uuid, SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING); + + + return ResultHolder.success(uuid); + } + + @DeCleaner(value = DePermissionType.DATA_FILL, key = "pid") + public ResultHolder updateForm(DataFillFormWithBLOBs dataFillForm) { + + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + Assert.notNull(dataFillForm.getId(), "id cannot be null"); + + dataFillForm.setUpdateTime(new Date()); + dataFillFormMapper.updateByPrimaryKeySelective(dataFillForm); + + DeLogUtils.save(SysLogConstants.OPERATE_TYPE.MODIFY, SysLogConstants.SOURCE_TYPE.DATA_FILL_FORM, dataFillForm.getId(), dataFillForm.getPid(), null, null); + + return ResultHolder.success(dataFillForm.getId()); + } + + private void checkName(String id, String name, String pid, int level, String nodeType, String optType) { + DataFillFormExample example = new DataFillFormExample(); + if (DataFillConstants.OPT_TYPE_INSERT.equalsIgnoreCase(optType)) { + example.createCriteria().andPidEqualTo(pid).andNameEqualTo(name).andNodeTypeEqualTo(nodeType); + } else if (DataFillConstants.OPT_TYPE_UPDATE.equalsIgnoreCase(optType)) { + example.createCriteria().andPidEqualTo(pid).andNameEqualTo(name).andIdNotEqualTo(id).andNodeTypeEqualTo(nodeType); + } + + List checkResult = dataFillFormMapper.selectByExample(example); + if (CollectionUtils.isNotEmpty(checkResult)) { + DataEaseException.throwException(DataFillConstants.DATA_FILL_NODE_TYPE_DATA_FILL.equals(nodeType) ? Translator.get("I18N_DATA_FILL_FORM_EXIST") : Translator.get("I18N_FOlDER_EXIST")); + } + } + + public List tree(DataFillFormRequest request) { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + String userId = String.valueOf(AuthUtils.getUser().getUserId()); + request.setUserId(userId); + List list = extDataFillFormMapper.search(request); + return TreeUtils.mergeTree(list); + + } + + public DataFillFormWithBLOBs get(String id) { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + Assert.notNull(id, "id cannot be null"); + return dataFillFormMapper.selectByPrimaryKey(id); + } + + public DataFillFormDTO getWithPrivileges(String id) { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + Assert.notNull(id, "id cannot be null"); + String userId = String.valueOf(AuthUtils.getUser().getUserId()); + DataFillFormRequest request = new DataFillFormRequest(); + request.setUserId(userId); + request.setId(id); + List list = extDataFillFormMapper.search(request); + if (CollectionUtils.isEmpty(list)) { + return null; + } + DataFillFormDTO base = list.stream().filter(dto -> StringUtils.equals(dto.getId(), id)).collect(Collectors.toList()).get(0); + DataFillFormDTO result = new DataFillFormDTO(); + + BeanUtils.copyBean(result, get(id)); + + result.setPrivileges(base.getPrivileges()); + + SysUserExample userExample = new SysUserExample(); + userExample.createCriteria().andUsernameEqualTo(result.getCreateBy()); + List sysUsers = sysUserMapper.selectByExample(userExample); + if (CollectionUtils.isNotEmpty(sysUsers)) { + result.setCreatorName(sysUsers.get(0).getNickName()); + } + + Datasource d = datasource.get(result.getDatasource()); + if (d != null) { + result.setDatasourceName(d.getName()); + } + + return result; + } + + public void deleteForm(String id) throws Exception { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + Assert.notNull(id, "id cannot be null"); + sysAuthService.checkTreeNoManageCount(SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING, id); + + Map stringStringMap = extDataFillFormMapper.searchChildrenIds(id, SysAuthConstants.AUTH_SOURCE_TYPE_DATA_FILLING); + String[] split = stringStringMap.get("ids").split(","); + + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(id); + + List ids = new ArrayList<>(); + for (String dsId : split) { + if (StringUtils.isNotEmpty(dsId)) { + ids.add(dsId); + } + } + if (CollectionUtils.isNotEmpty(ids)) { + DataFillFormExample example = new DataFillFormExample(); + example.createCriteria().andIdIn(ids); + dataFillFormMapper.deleteByExample(example); + } + + DeLogUtils.save(SysLogConstants.OPERATE_TYPE.DELETE, SysLogConstants.SOURCE_TYPE.DATA_FILL_FORM, dataFillForm.getId(), dataFillForm.getPid(), null, null); + + dataFillTaskService.deleteTaskByFormId(id); + } + + public List listFields(String id) throws Exception { + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(id); + + if (StringUtils.equals(dataFillForm.getNodeType(), "folder")) { + return null; + } + return gson.fromJson(dataFillForm.getForms(), new TypeToken>() { + }.getType()); + } + + + public void fillFormData(String userTaskId, Map data) throws Exception { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + DataFillUserTask task = dataFillUserTaskMapper.selectByPrimaryKey(userTaskId); + + if (task == null) { + DataEaseException.throwException("任务不存在"); + } + + if (!AuthUtils.getUser().getUserId().equals(task.getUser())) { + DataEaseException.throwException("当前用户非任务用户"); + } + + if (task.getEndTime() != null) { + if (task.getEndTime().getTime() < System.currentTimeMillis()) { + DataEaseException.throwException("已经超过了任务截止时间"); + } + } + + String formId = task.getFormId(); + + String rowId = null; + if (StringUtils.isNotBlank(task.getValueId())) { + rowId = task.getValueId(); + } else { + DataFillFormWithBLOBs dataFillForm = dataFillFormMapper.selectByPrimaryKey(formId); + + Datasource ds = datasource.get(dataFillForm.getDatasource()); + Provider datasourceProvider = ProviderFactory.getProvider(ds.getType()); + + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(ds); + datasourceRequest.setTable(dataFillForm.getTableName()); + List tableFields = datasourceProvider.getTableFields(datasourceRequest); + + for (TableField tableField : tableFields) { + if (tableField.isPrimaryKey()) { + rowId = (String) data.get(tableField.getFieldName()); + break; + } + } + } + + rowId = dataFillDataService.updateRowData(formId, rowId, data, rowId == null); + + task.setValueId(rowId); + task.setFinishTime(new Date()); + + dataFillUserTaskMapper.updateByPrimaryKeySelective(task); + } + +} diff --git a/core/backend/src/main/java/io/dataease/service/datafill/DataFillTaskService.java b/core/backend/src/main/java/io/dataease/service/datafill/DataFillTaskService.java new file mode 100644 index 0000000000..96a0f4a93e --- /dev/null +++ b/core/backend/src/main/java/io/dataease/service/datafill/DataFillTaskService.java @@ -0,0 +1,259 @@ +package io.dataease.service.datafill; + +import io.dataease.auth.service.AuthUserService; +import io.dataease.commons.model.AuthURD; +import io.dataease.commons.utils.AuthUtils; +import io.dataease.commons.utils.CommonBeanFactory; +import io.dataease.controller.request.datafill.DataFillTaskSearchRequest; +import io.dataease.controller.request.datafill.DataFillUserTaskSearchRequest; +import io.dataease.dto.datafill.DataFillTaskDTO; +import io.dataease.dto.datafill.DataFillUserTaskDTO; +import io.dataease.ext.ExtDataFillFormMapper; +import io.dataease.job.sechedule.ScheduleManager; +import io.dataease.job.sechedule.strategy.TaskHandler; +import io.dataease.job.sechedule.strategy.TaskStrategyFactory; +import io.dataease.plugins.common.base.domain.*; +import io.dataease.plugins.common.base.mapper.DataFillTaskMapper; +import io.dataease.plugins.common.base.mapper.DataFillUserTaskMapper; +import io.dataease.plugins.common.base.mapper.SysUserMapper; +import io.dataease.plugins.common.entity.GlobalTaskEntity; +import io.dataease.plugins.common.exception.DataEaseException; +import org.apache.commons.lang3.StringUtils; +import org.pentaho.di.core.util.UUIDUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Transactional(rollbackFor = Exception.class) +public class DataFillTaskService { + + @Resource + private ExtDataFillFormMapper extDataFillFormMapper; + + @Resource + private DataFillTaskMapper dataFillTaskMapper; + @Resource + private DataFillUserTaskMapper dataFillUserTaskMapper; + + @Resource + private SysUserMapper sysUserMapper; + + @Resource + private ScheduleManager scheduleManager; + + + public List tasks(String formId, DataFillTaskSearchRequest request) { + request.setFormId(formId); + return extDataFillFormMapper.selectDataFillTasks(request); + } + + private List listActiveTasks() { + return extDataFillFormMapper.selectActiveDataFillTasks(); + } + + public List listActiveTasksGlobalTaskEntity() { + List list = new ArrayList<>(); + List tasks = dataFillTaskMapper.selectByExample(null); + for (DataFillTask task : tasks) { + list.add(getGlobalTaskEntity(task)); + } + return list; + } + + private GlobalTaskEntity getGlobalTaskEntity(DataFillTask task) { + GlobalTaskEntity entity = new GlobalTaskEntity() + .setTaskId(task.getId()) + .setTaskName(task.getName()) + .setRateType(task.getRateType()) + .setRateVal(task.getRateVal()) + .setStatus(task.getStatus()) + .setTaskType("dataFillTaskHandler") + .setCreator(task.getCreator()); + if (task.getRateType() == -1) { + entity.setStartTime(task.getPublishStartTime() == null ? null : task.getPublishStartTime().getTime()); + entity.setEndTime(task.getPublishEndTime() == null ? null : task.getPublishEndTime().getTime()); + } else { + entity.setStartTime(task.getStartTime() == null ? null : task.getStartTime().getTime()); + entity.setEndTime(task.getEndTime() == null ? null : task.getEndTime().getTime()); + } + return entity; + } + + public void saveTask(String formId, DataFillTaskSearchRequest request) throws Exception { + if (!CommonBeanFactory.getBean(AuthUserService.class).pluginLoaded()) { + DataEaseException.throwException("invalid"); + } + + request.setCreator(AuthUtils.getUser().getUserId()); + boolean insert = false; + if (request.getId() == null) { + insert = true; + request.setFormId(formId); + } + + if (insert) { + dataFillTaskMapper.insertSelective(request); + } else { + dataFillTaskMapper.updateByPrimaryKeySelective(request); + } + + DataFillTaskWithBLOBs task = dataFillTaskMapper.selectByPrimaryKey(request.getId()); + + + GlobalTaskEntity entity = getGlobalTaskEntity(task); + TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(entity.getTaskType()); + taskHandler.addTask(scheduleManager, entity); + + } + + public DataFillTaskWithBLOBs getTaskById(Long id) { + return dataFillTaskMapper.selectByPrimaryKey(id); + } + + public void finishTask(Long id) { + DataFillTaskWithBLOBs task = new DataFillTaskWithBLOBs(); + task.setId(id); + task.setStatus(false); + dataFillTaskMapper.updateByPrimaryKeySelective(task); + } + + public void deleteTaskByFormId(String formId) { + DataFillTaskExample example = new DataFillTaskExample(); + example.createCriteria().andFormIdEqualTo(formId); + for (DataFillTask dataFillTask : dataFillTaskMapper.selectByExample(example)) { + deleteTask(dataFillTask.getId()); + } + } + + public void deleteTask(Long id) { + + try { + GlobalTaskEntity entity = getGlobalTaskEntity(dataFillTaskMapper.selectByPrimaryKey(id)); + TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(entity.getTaskType()); + taskHandler.removeTask(scheduleManager, entity); + } catch (Exception e) { + e.printStackTrace(); + } + + dataFillTaskMapper.deleteByPrimaryKey(id); + + DataFillUserTaskExample example = new DataFillUserTaskExample(); + example.createCriteria().andTaskIdEqualTo(id); + dataFillUserTaskMapper.deleteByExample(example); + + } + + public void enableTask(Long taskId) throws Exception { + DataFillTask task = dataFillTaskMapper.selectByPrimaryKey(taskId); + DataFillTaskSearchRequest request = new DataFillTaskSearchRequest(); + request.setId(taskId); + request.setStatus(true); + saveTask(task.getFormId(), request); + } + + public void disableTask(Long taskId) throws Exception { + DataFillTask task = dataFillTaskMapper.selectByPrimaryKey(taskId); + DataFillTaskSearchRequest request = new DataFillTaskSearchRequest(); + request.setId(taskId); + request.setStatus(false); + saveTask(task.getFormId(), request); + } + + public void createUserTasks(DataFillTaskWithBLOBs dataFillTask, String valueId) throws Exception { + String reciUsers = dataFillTask.getReciUsers(); + List accountSet = new ArrayList<>(); + if (StringUtils.isNotBlank(reciUsers)) { + accountSet.addAll(Arrays.stream(reciUsers.split(",")).collect(Collectors.toSet())); + } + List sysUsers = new ArrayList<>(); + if (!accountSet.isEmpty()) { + SysUserExample example = new SysUserExample(); + example.createCriteria().andUsernameIn(accountSet); + sysUsers = sysUserMapper.selectByExample(example); + } + + + String roleList = dataFillTask.getRoleList(); + String orgList = dataFillTask.getOrgList(); + AuthURD authURD = new AuthURD(); + if (StringUtils.isNotBlank(roleList)) { + authURD.setRoleIds(Arrays.stream(roleList.split(",")).map(Long::parseLong).collect(Collectors.toList())); + } + if (StringUtils.isNotBlank(orgList)) { + authURD.setDeptIds(Arrays.stream(orgList.split(",")).map(Long::parseLong).collect(Collectors.toList())); + } + Set ids = AuthUtils.userIdsByURD(authURD); + + for (SysUser sysUser : sysUsers) { + ids.add(sysUser.getUserId()); + } + + Date startTime = null; + Date endTime = null; + + if (dataFillTask.getRateType() == -1) { + startTime = dataFillTask.getPublishStartTime(); + endTime = dataFillTask.getPublishEndTime(); + } else { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date val = sdf.parse(dataFillTask.getRateVal()); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(val); + + Calendar current = Calendar.getInstance(); + calendar.set(Calendar.YEAR, current.get(Calendar.YEAR)); + calendar.set(Calendar.MONTH, current.get(Calendar.MONTH)); + calendar.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH)); + + startTime = calendar.getTime(); + + if (dataFillTask.getPublishRangeTimeType() == -1) { + calendar.add(Calendar.HOUR_OF_DAY, dataFillTask.getPublishRangeTime()); + } else if (dataFillTask.getPublishRangeTimeType() == 0) { + calendar.add(Calendar.DAY_OF_MONTH, dataFillTask.getPublishRangeTime()); + } else if (dataFillTask.getPublishRangeTimeType() == 1) { + calendar.add(Calendar.WEEK_OF_YEAR, dataFillTask.getPublishRangeTime()); + } else if (dataFillTask.getPublishRangeTimeType() == 2) { + calendar.add(Calendar.MONTH, dataFillTask.getPublishRangeTime()); + } + endTime = calendar.getTime(); + } + + for (Long id : ids) { + DataFillUserTask task = new DataFillUserTask(); + task.setId(UUIDUtil.getUUIDAsString()); + task.setTaskId(dataFillTask.getId()); + task.setFormId(dataFillTask.getFormId()); + task.setUser(id); + task.setStartTime(startTime); + task.setEndTime(endTime); + task.setValueId(valueId); + + dataFillUserTaskMapper.insertSelective(task); + } + + } + + + public List userTasks(Long userId, String type, DataFillUserTaskSearchRequest request) { + List list = new ArrayList<>(); + + String taskName = StringUtils.isNotBlank(request.getTaskName()) ? request.getTaskName() : null; + + if (StringUtils.equalsIgnoreCase(type, "finished")) { + list = extDataFillFormMapper.listFinishedUserTask(userId, taskName); + } else if (StringUtils.equalsIgnoreCase(type, "expired")) { + list = extDataFillFormMapper.listExpiredUserTask(userId, new Date(), taskName); + } else { + list = extDataFillFormMapper.listTodoUserTask(userId, new Date(), taskName); + } + + return list; + + } +} diff --git a/core/backend/src/main/java/io/dataease/service/decatch/DeCatchProcess.java b/core/backend/src/main/java/io/dataease/service/decatch/DeCatchProcess.java index 1d1d549e92..e6603d90d5 100644 --- a/core/backend/src/main/java/io/dataease/service/decatch/DeCatchProcess.java +++ b/core/backend/src/main/java/io/dataease/service/decatch/DeCatchProcess.java @@ -62,6 +62,18 @@ public class DeCatchProcess { cleanCacheParent(resourceId.toString(), "link"); }); } + public void cleanDataFiling(Object pid) { + CurrentUserDto user = AuthUtils.getUser(); + CacheUtils.remove(AuthConstants.USER_DATA_FILL_NAME, "user" + user.getUserId()); + CacheUtils.remove(AuthConstants.DEPT_DATA_FILL_NAME, "dept" + user.getDeptId()); + user.getRoles().forEach(role -> { + CacheUtils.remove(AuthConstants.ROLE_DATA_FILL_NAME, "role" + role.getId()); + }); + + Optional.ofNullable(pid).ifPresent(resourceId -> { + cleanCacheParent(resourceId.toString(), "data_fill"); + }); + } private void cleanCacheParent(String pid, String type) { if (StringUtils.isBlank(pid) || StringUtils.isBlank(type)) { diff --git a/core/backend/src/main/java/io/dataease/service/panel/PanelLinkService.java b/core/backend/src/main/java/io/dataease/service/panel/PanelLinkService.java index 82cd185411..28ec8bde3d 100644 --- a/core/backend/src/main/java/io/dataease/service/panel/PanelLinkService.java +++ b/core/backend/src/main/java/io/dataease/service/panel/PanelLinkService.java @@ -11,6 +11,7 @@ import io.dataease.commons.utils.ServletUtils; import io.dataease.controller.request.panel.link.*; import io.dataease.dto.panel.PanelGroupDTO; import io.dataease.dto.panel.link.GenerateDto; +import io.dataease.dto.panel.link.TicketDto; import io.dataease.ext.ExtPanelGroupMapper; import io.dataease.ext.ExtPanelLinkMapper; import io.dataease.plugins.common.base.domain.*; @@ -128,13 +129,13 @@ public class PanelLinkService { } } - public String getMappingUuid(PanelLink link) { + public PanelLinkMapping getMapping(PanelLink link) { String resourceId = link.getResourceId(); Long userId = link.getUserId(); PanelLinkMappingExample example = new PanelLinkMappingExample(); example.createCriteria().andResourceIdEqualTo(resourceId).andUserIdEqualTo(userId); List mappings = panelLinkMappingMapper.selectByExample(example); - if (CollectionUtils.isNotEmpty(mappings)) return mappings.get(0).getUuid(); + if (CollectionUtils.isNotEmpty(mappings)) return mappings.get(0); return null; } @@ -291,8 +292,12 @@ public class PanelLinkService { PanelLinkTicketExample example = new PanelLinkTicketExample(); example.createCriteria().andTicketEqualTo(ticket); if (creator.isGenerateNew()) { + ticketEntity.setAccessTime(null); ticketEntity.setTicket(CodingUtil.shortUuid()); } + ticketEntity.setArgs(creator.getArgs()); + ticketEntity.setExp(creator.getExp()); + ticketEntity.setUuid(creator.getUuid()); panelLinkTicketMapper.updateByExample(ticketEntity, example); return ticketEntity.getTicket(); } @@ -317,7 +322,15 @@ public class PanelLinkService { panelLinkTicketMapper.deleteByExample(example); } - + public void switchRequire(TicketSwitchRequest request) { + String resourceId = request.getResourceId(); + Boolean require = request.getRequire(); + PanelLinkMappingExample example = new PanelLinkMappingExample(); + example.createCriteria().andResourceIdEqualTo(resourceId).andUserIdEqualTo(AuthUtils.getUser().getUserId()); + PanelLinkMapping mapping = new PanelLinkMapping(); + mapping.setRequireTicket(require); + panelLinkMappingMapper.updateByExampleSelective(mapping, example); + } public PanelLinkTicket getByTicket(String ticket) { PanelLinkTicketExample example = new PanelLinkTicketExample(); @@ -354,4 +367,37 @@ public class PanelLinkService { PanelLink one = findOne(resourceId, userId); return convertDto(one, uuid, mapping.getRequireTicket()).getUri(); } + + public TicketDto validateTicket(String ticket, PanelLinkMapping mapping) { + String uuid = mapping.getUuid(); + TicketDto ticketDto = new TicketDto(); + if (StringUtils.isBlank(ticket)) { + ticketDto.setTicketValid(!mapping.getRequireTicket()); + return ticketDto; + } + PanelLinkTicketExample example = new PanelLinkTicketExample(); + example.createCriteria().andTicketEqualTo(ticket).andUuidEqualTo(uuid); + List tickets = panelLinkTicketMapper.selectByExample(example); + if (CollectionUtils.isEmpty(tickets)) { + ticketDto.setTicketValid(false); + return ticketDto; + } + PanelLinkTicket linkTicket = tickets.get(0); + ticketDto.setTicketValid(true); + ticketDto.setArgs(linkTicket.getArgs()); + Long accessTime = linkTicket.getAccessTime(); + long now = System.currentTimeMillis(); + if (ObjectUtils.isEmpty(accessTime)) { + accessTime = now; + ticketDto.setTicketExp(false); + linkTicket.setAccessTime(accessTime); + panelLinkTicketMapper.updateByPrimaryKey(linkTicket); + return ticketDto; + } + Long exp = linkTicket.getExp(); + long expTime = exp * 60L * 1000L; + long time = now - accessTime; + ticketDto.setTicketExp(time > expTime); + return ticketDto; + } } diff --git a/core/backend/src/main/resources/application.properties b/core/backend/src/main/resources/application.properties index 1683cb9987..866b9e1adb 100644 --- a/core/backend/src/main/resources/application.properties +++ b/core/backend/src/main/resources/application.properties @@ -81,6 +81,7 @@ server.servlet.context-parameters.configurationStrategy=SYSTEM_PROPERTIES server.servlet.session.cookie.http-only=true server.servlet.session.tracking-modes=cookie spring.jackson.parser.allow-numeric-leading-zeros=true +logging.level.org.apache.shiro=OFF diff --git a/core/backend/src/main/resources/db/migration/V62__1.18.18.sql b/core/backend/src/main/resources/db/migration/V62__1.18.18.sql index 4d2f74ea56..0deb306377 100644 --- a/core/backend/src/main/resources/db/migration/V62__1.18.18.sql +++ b/core/backend/src/main/resources/db/migration/V62__1.18.18.sql @@ -4,11 +4,12 @@ DROP TABLE IF EXISTS `panel_link_ticket`; CREATE TABLE `panel_link_ticket` ( - `id` bigint NOT NULL AUTO_INCREMENT, - `uuid` varchar(255) NOT NULL, - `ticket` varchar(255) NOT NULL, - `exp` bigint DEFAULT NULL, - `args` varchar(255) DEFAULT NULL, + `id` bigint NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) NOT NULL, + `ticket` varchar(255) NOT NULL, + `exp` bigint DEFAULT NULL, + `args` varchar(255) DEFAULT NULL, + `access_time` bigint DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE = InnoDB AUTO_INCREMENT = 1; diff --git a/core/backend/src/main/resources/db/migration/V63__1.18.18-data-fill.sql b/core/backend/src/main/resources/db/migration/V63__1.18.18-data-fill.sql new file mode 100644 index 0000000000..ac15281721 --- /dev/null +++ b/core/backend/src/main/resources/db/migration/V63__1.18.18-data-fill.sql @@ -0,0 +1,310 @@ +DROP TABLE IF EXISTS `data_fill_form`; +create table data_fill_form +( + id varchar(50) not null comment '主键ID' + primary key, + name varchar(255) null comment '名称', + pid varchar(255) null comment '父级ID', + level int(10) null comment '层级', + node_type varchar(255) null comment 'folder/panel 目录或文件夹', + table_name varchar(255) null comment '表名', + datasource varchar(255) null comment '数据源', + forms longtext null comment '表单内容', + create_index tinyint(1) default 0 null comment '是否创建索引', + table_indexes longtext null comment '索引', + create_by varchar(255) null comment '创建人', + create_time datetime default current_timestamp() null comment '创建时间', + update_by varchar(255) null comment '更新人', + update_time datetime default current_timestamp() null comment '更新时间' +) + comment '数据填报表单'; + +CREATE TRIGGER `delete_auth_data_fill_form` + AFTER DELETE + ON `data_fill_form` + FOR EACH ROW select delete_auth_source(OLD.id, 'data_fill') + into @ee; + + +DROP VIEW IF EXISTS `v_auth_model`; +CREATE ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `v_auth_model` AS +SELECT `sys_user`.`user_id` AS `id`, + concat(`sys_user`.`nick_name`, '(', `sys_user`.`username`, ')') AS `name`, + `sys_user`.`username` AS `label`, + '0' AS `pid`, + 'leaf' AS `node_type`, + 'user' AS `model_type`, + 'user' AS `model_inner_type`, + 'target' AS `auth_type`, + `sys_user`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `sys_user` +WHERE (`sys_user`.`is_admin` <> 1) +UNION ALL +SELECT `sys_role`.`role_id` AS `id`, + `sys_role`.`name` AS `name`, + `sys_role`.`name` AS `label`, + '0' AS `pid`, + 'leaf' AS `node_type`, + 'role' AS `model_type`, + 'role' AS `model_inner_type`, + 'target' AS `auth_type`, + `sys_role`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `sys_role` +UNION ALL +SELECT `sys_dept`.`dept_id` AS `id`, + `sys_dept`.`name` AS `name`, + `sys_dept`.`name` AS `label`, + ( + cast(`sys_dept`.`pid` AS CHAR charset utf8mb4) COLLATE utf8mb4_general_ci + ) AS `pid`, + IF + ((`sys_dept`.`sub_count` = 0), 'leaf', 'spine') AS `node_type`, + 'dept' AS `model_type`, + 'dept' AS `model_inner_type`, + 'target' AS `auth_type`, + `sys_dept`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `sys_dept` +UNION ALL +SELECT `datasource`.`id` AS `id`, + `datasource`.`name` AS `NAME`, + `datasource`.`name` AS `label`, + '0' AS `pid`, + 'leaf' AS `node_type`, + 'link' AS `model_type`, + `datasource`.`type` AS `model_inner_type`, + 'source' AS `auth_type`, + `datasource`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `datasource` +UNION ALL +SELECT `dataset_group`.`id` AS `id`, + `dataset_group`.`name` AS `NAME`, + `dataset_group`.`name` AS `label`, + IF + (isnull(`dataset_group`.`pid`), '0', `dataset_group`.`pid`) AS `pid`, + 'spine' AS `node_type`, + 'dataset' AS `model_type`, + `dataset_group`.`type` AS `model_inner_type`, + 'source' AS `auth_type`, + `dataset_group`.`create_by` AS `create_by`, + `dataset_group`.`level` AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `dataset_group` +UNION ALL +SELECT `data_fill_form`.`id` AS `id`, + `data_fill_form`.`name` AS `NAME`, + `data_fill_form`.`name` AS `label`, + ( + CASE + `data_fill_form`.`id` + WHEN 'data_fill_list' THEN + '0' + WHEN 'default_data_fill' THEN + '0' + ELSE `data_fill_form`.`pid` + END + ) AS `pid`, + IF + ((`data_fill_form`.`node_type` = 'folder'), 'spine', 'leaf') AS `node_type`, + 'data_fill' AS `model_type`, + 'form' AS `model_inner_type`, + 'source' AS `auth_type`, + `data_fill_form`.`create_by` AS `create_by`, + `data_fill_form`.`level` AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `data_fill_form` +UNION ALL +SELECT `dataset_table`.`id` AS `id`, + `dataset_table`.`name` AS `NAME`, + `dataset_table`.`name` AS `label`, + `dataset_table`.`scene_id` AS `pid`, + 'leaf' AS `node_type`, + 'dataset' AS `model_type`, + `dataset_table`.`type` AS `model_inner_type`, + 'source' AS `auth_type`, + `dataset_table`.`create_by` AS `create_by`, + 0 AS `level`, + `dataset_table`.`mode` AS `mode`, + `dataset_table`.`data_source_id` AS `data_source_id` +FROM `dataset_table` +UNION ALL +SELECT `panel_group`.`id` AS `id`, + `panel_group`.`name` AS `NAME`, + `panel_group`.`name` AS `label`, + ( + CASE + `panel_group`.`id` + WHEN 'panel_list' THEN + '0' + WHEN 'default_panel' THEN + '0' + ELSE `panel_group`.`pid` + END + ) AS `pid`, + IF + ((`panel_group`.`node_type` = 'folder'), 'spine', 'leaf') AS `node_type`, + 'panel' AS `model_type`, + `panel_group`.`panel_type` AS `model_inner_type`, + 'source' AS `auth_type`, + `panel_group`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `panel_group` +UNION ALL +SELECT `sys_menu`.`menu_id` AS `menu_id`, + `sys_menu`.`title` AS `name`, + `sys_menu`.`title` AS `label`, + `sys_menu`.`pid` AS `pid`, + IF + ((`sys_menu`.`sub_count` > 0), 'spine', 'leaf') AS `node_type`, + 'menu' AS `model_type`, + ( + CASE + `sys_menu`.`type` + WHEN 0 THEN + 'folder' + WHEN 1 THEN + 'menu' + WHEN 2 THEN + 'button' + END + ) AS `model_inner_type`, + 'source' AS `auth_type`, + `sys_menu`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `sys_menu` +WHERE (( + `sys_menu`.`i_frame` <> 1 + ) + OR isnull(`sys_menu`.`i_frame`)) +UNION ALL +SELECT `plugin_sys_menu`.`menu_id` AS `menu_id`, + `plugin_sys_menu`.`title` AS `name`, + `plugin_sys_menu`.`title` AS `label`, + `plugin_sys_menu`.`pid` AS `pid`, + IF + ((`plugin_sys_menu`.`sub_count` > 0), 'spine', 'leaf') AS `node_type`, + 'menu' AS `model_type`, + ( + CASE + `plugin_sys_menu`.`type` + WHEN 0 THEN + 'folder' + WHEN 1 THEN + 'menu' + WHEN 2 THEN + 'button' + END + ) AS `model_inner_type`, + 'source' AS `auth_type`, + `plugin_sys_menu`.`create_by` AS `create_by`, + 0 AS `level`, + 0 AS `mode`, + '0' AS `data_source_id` +FROM `plugin_sys_menu` +WHERE (( + `plugin_sys_menu`.`i_frame` <> 1 + ) + OR isnull(`plugin_sys_menu`.`i_frame`)); + + +INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, + `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, + `copy_id`) +VALUES ('data_fill_grant', 'data_fill', 'i18n_auth_grant', 15, 0, 'grant', '基础权限-授权', 'system', NULL, NULL, NULL, + NULL); +INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, + `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, + `copy_id`) +VALUES ('data_fill_manage', 'data_fill', 'i18n_auth_manage', 3, 0, 'manage', '基础权限-管理', 'system', NULL, NULL, + NULL, NULL); +INSERT INTO `sys_auth_detail` (`id`, `auth_id`, `privilege_name`, `privilege_type`, `privilege_value`, + `privilege_extend`, `remark`, `create_user`, `create_time`, `update_time`, `copy_from`, + `copy_id`) +VALUES ('data_fill_use', 'data_fill', 'i18n_auth_use', 1, 0, 'use', '基础权限-使用', 'system', NULL, NULL, NULL, NULL); + + + +DROP TABLE IF EXISTS `data_fill_commit_log`; +create table data_fill_commit_log +( + id varchar(50) not null + primary key, + form_id varchar(50) not null, + data_id varchar(255) null, + operate varchar(50) not null, + commit_by varchar(255) not null, + commit_time datetime default current_timestamp() null +); + +create index data_fill_commit_log_form_id_index + on data_fill_commit_log (form_id); + + +DROP TABLE IF EXISTS `data_fill_task`; +create table data_fill_task +( + id bigint auto_increment comment '任务ID' + primary key, + name varchar(255) not null comment '任务名称', + form_id varchar(100) not null comment '任务ID', + start_time datetime null comment '开始时间', + end_time datetime null comment '结束时间', + rate_type int(10) not null comment '频率方式', + rate_val varchar(255) null comment '频率值', + publish_start_time datetime null, + publish_end_time datetime null, + publish_range_time_type int null, + publish_range_time int null, + creator bigint not null comment '创建者ID', + create_time datetime default current_timestamp() null comment '创建时间', + status tinyint(1) default 1 null comment '运行状态', + reci_users longtext null comment '接收人账号', + role_list longtext null comment '收件角色', + org_list longtext null comment '收件组织' +) + comment '数据填报任务'; + +create index data_fill_task_form_id_index + on data_fill_task (form_id); + + +DROP TABLE IF EXISTS `data_fill_user_task`; +create table data_fill_user_task +( + id varchar(50) not null comment 'ID' + primary key, + task_id bigint not null comment '任务ID', + form_id varchar(100) not null comment '表单ID', + value_id varchar(100) null comment '表内值ID', + user bigint not null comment '用户ID', + start_time datetime null comment '开始时间', + end_time datetime null comment '结束时间', + finish_time datetime null comment '完成时间' +) + comment '数据填报用户任务'; + +create index data_fill_user_task_form_id_index + on data_fill_user_task (form_id); + +create index data_fill_user_task_task_id_index + on data_fill_user_task (task_id); + + + diff --git a/core/backend/src/main/resources/i18n/messages_en_US.properties b/core/backend/src/main/resources/i18n/messages_en_US.properties index 7648cb59c8..75475a6cbc 100644 --- a/core/backend/src/main/resources/i18n/messages_en_US.properties +++ b/core/backend/src/main/resources/i18n/messages_en_US.properties @@ -173,6 +173,7 @@ SOURCE_TYPE_DRIVER_FILE=DRIVER FILE SOURCE_TYPE_MENU=MENU SOURCE_TYPE_LINK=PUBLIC LINK SOURCE_TYPE_APIKEY=APIKEY +SOURCE_TYPE_DATA_FILL_FORM=DATA FILL FORM I18N_OPERATE_TYPE=Operation type I18N_DETAIL=Operation details I18N_USER=Operator @@ -237,6 +238,7 @@ I18N_DS_INVALID=Datasource is invalid I18N_DS_INVALID_TABLE=Datasource has invalid tables I18N_ACCOUNT_LOCKED=Account\u3010%s\u3011is locked(Please contact the administrator to unlock or try again in %s minutes) I18N_PANEL_EXIST=The current panel name already exists under this directory +I18N_DATA_FILL_FORM_EXIST=The current data filling form name already exists under this directory I18N_FOlDER_EXIST=The name already exists under this directory I18N_DATASET_GROUP_EXIST=The current dataset grouping name already exists under this directory I18N_NOT_JAR=File is not jar! diff --git a/core/backend/src/main/resources/i18n/messages_zh_CN.properties b/core/backend/src/main/resources/i18n/messages_zh_CN.properties index 5a01acb2cf..d696368181 100644 --- a/core/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/core/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -94,7 +94,7 @@ i18n_sql_delete_not_matching=\u589E\u91CF\u5220\u9664 SQL \u7684\u6570\u636E\u52 i18n_cst_ds_tb_or_field_deleted=\u81EA\u5B9A\u4E49\u6570\u636E\u96C6\u6240\u5173\u8054\u6570\u636E\u88AB\u5220\u9664\u6216\u5B57\u6BB5\u53D1\u751F\u53D8\u5316\uFF0C\u65E0\u6CD5\u6B63\u5E38\u663E\u793A i18n_no_all_delete_privilege_folder=\u8BE5\u76EE\u5F55\u4E0B\u5B58\u5728\u6CA1\u6709\u7BA1\u7406\u6743\u9650\u6216\u67E5\u770B\u6743\u9650\u7684\u8D44\u6E90\uFF0C\u65E0\u6CD5\u5220\u9664 i18n_excel_field_repeat=\u5B58\u5728\u91CD\u590D\u5B57\u6BB5\uFF1A -i18n_dont_contain_key=\u5f53\u524d\u7684sql\u4e0d\u5305\u542b\u8fd9\u4e2a\u952e\uff1a +i18n_dont_contain_key=\u5F53\u524D\u7684sql\u4E0D\u5305\u542B\u8FD9\u4E2A\u952E\uFF1A i18n_schema_is_empty=\u6570\u636E\u5E93 Schema \u4E3A\u7A7A \u7AD9\u5185\u6D88\u606F=\u6D88\u606F\u4E2D\u5FC3 \u6240\u6709\u6D88\u606F=\u6240\u6709\u6D88\u606F @@ -173,6 +173,7 @@ SOURCE_TYPE_DRIVER_FILE=\u9A71\u52A8\u6587\u4EF6 SOURCE_TYPE_MENU=\u83DC\u5355 SOURCE_TYPE_LINK=\u516C\u5171\u94FE\u63A5 SOURCE_TYPE_APIKEY=APIKEY +SOURCE_TYPE_DATA_FILL_FORM=\u6570\u636E\u586B\u62A5\u8868\u5355 I18N_OPERATE_TYPE=\u64CD\u4F5C\u7C7B\u578B I18N_DETAIL=\u64CD\u4F5C\u8BE6\u60C5 I18N_USER=\u64CD\u4F5C\u4EBA @@ -237,6 +238,7 @@ I18N_DS_INVALID=\u6570\u636E\u6E90\u65E0\u6548 I18N_DS_INVALID_TABLE=\u6570\u636E\u6E90\u4E2D\u6709\u65E0\u6548\u7684\u8868 I18N_ACCOUNT_LOCKED=\u8D26\u53F7\u3010%s\u3011\u5DF2\u9501\u5B9A(\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u89E3\u9501\u6216%s\u5206\u949F\u540E\u91CD\u8BD5) I18N_PANEL_EXIST=\u5F53\u524D\u4EEA\u8868\u677F\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 +I18N_DATA_FILL_FORM_EXIST=\u5F53\u524D\u6570\u636E\u586B\u62A5\u8868\u5355\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 I18N_FOlDER_EXIST=\u5F53\u524D\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 I18N_DATASET_GROUP_EXIST=\u5F53\u524D\u6570\u636E\u96C6\u5206\u7EC4\u540D\u79F0\u5728\u8BE5\u76EE\u5F55\u4E0B\u9762\u5DF2\u7ECF\u5B58\u5728 I18N_NOT_JAR=\u6587\u4EF6\u4E0D\u662F jar \u5305! @@ -268,6 +270,6 @@ I18N_PANEL_PDF_TEMPLATE_WITH_PARAMS=\u9ED8\u8BA4\u6A21\u677F(\u52A0\u4EEA\u8868\ I18N_PANEL_PDF_TEMPLATE_ONLY_PIC=\u9ED8\u8BA4\u6A21\u677F(\u53EA\u622A\u56FE) I18n_name_cant_empty=\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01 I18n_del_admin_tips=\u7981\u6B62\u5220\u9664admin\u8D26\u53F7 -I18N_NO_DRIVER_PERMISSION=\u6ca1\u6709\u6743\u9650\uff01 +I18N_NO_DRIVER_PERMISSION=\u6CA1\u6709\u6743\u9650\uFF01 i18n_field_circular_error=\u5B57\u6BB5\u89E3\u6790\u9519\u8BEF\uFF0C\u53EF\u80FD\u539F\u56E0\uFF1A\u5B57\u6BB5\u5DF2\u5220\u9664\u3001\u8BA1\u7B97\u5B57\u6BB5\u5F15\u7528\u5C42\u7EA7\u8FC7\u6DF1\u3001\u5B58\u5728\u5FAA\u73AF\u5F15\u7528\u7B49\uFF0C\u8BF7\u68C0\u67E5\u8868\u8282\u70B9\u548C\u5B57\u6BB5\u5E76\u91CD\u65B0\u7F16\u8F91\u3002 i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u73AF\u5F15\u7528 diff --git a/core/backend/src/main/resources/i18n/messages_zh_TW.properties b/core/backend/src/main/resources/i18n/messages_zh_TW.properties index 07f7382d4d..41fbad72ba 100644 --- a/core/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/core/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -94,7 +94,7 @@ i18n_sql_delete_not_matching=\u589E\u91CF\u522A\u9664 sql \u7684\u6578\u64DA\u52 i18n_cst_ds_tb_or_field_deleted=\u81EA\u5B9A\u7FA9\u6578\u64DA\u96C6\u6240\u95DC\u806F\u6578\u64DA\u88AB\u522A\u9664\u6216\u5B57\u6BB5\u767C\u751F\u8B8A\u5316\uFF0C\u7121\u6CD5\u6B63\u5E38\u986F\u793A i18n_no_all_delete_privilege_folder=\u8A72\u76EE\u9304\u4E0B\u5B58\u5728\u6C92\u6709\u7BA1\u7406\u6B0A\u9650\u6216\u67E5\u770B\u6B0A\u9650\u7684\u8CC7\u6E90\uFF0C\u7121\u6CD5\u522A\u9664 i18n_excel_field_repeat=\u5B58\u5728\u91CD\u5FA9\u5B57\u6BB5\uFF1A -i18n_dont_contain_key=\u7576\u524d\u7684sql\u4e0d\u5305\u542b\u9019\u500b\u9375\uff1a +i18n_dont_contain_key=\u7576\u524D\u7684sql\u4E0D\u5305\u542B\u9019\u500B\u9375\uFF1A i18n_schema_is_empty=\u6578\u64DA\u5EAB Schema \u70BA\u7A7A \u7AD9\u5185\u6D88\u606F=\u6D88\u606F\u4E2D\u5FC3 \u6240\u6709\u6D88\u606F=\u6240\u6709\u6D88\u606F @@ -173,6 +173,7 @@ SOURCE_TYPE_DRIVER_FILE=\u9A45\u52D5\u6587\u4EF6 SOURCE_TYPE_MENU=\u83DC\u55AE SOURCE_TYPE_LINK=\u516C\u5171\u93C8\u63A5 SOURCE_TYPE_APIKEY=APIKEY +SOURCE_TYPE_DATA_FILL_FORM=\u6578\u64DA\u586B\u5831\u8868\u55AE I18N_DRIVER_NOT_DELETE=\u4F7F\u7528\u4E2D\u7684\u9A45\u52D5\u4E0D\u5141\u8A31\u5220\u9664 I18N_DRIVER_REPEAT_NAME=\u540D\u7A31\u91CD\u8907 I18N_DRIVER_NOT_FOUND=\u672A\u627E\u5230\u9A45\u52D5 @@ -233,6 +234,7 @@ I18N_DS_INVALID=\u6578\u64DA\u6E90\u7121\u6548 I18N_DS_INVALID_TABLE=\u6578\u64DA\u6E90\u4E2D\u6709\u7121\u6548\u7684\u8868 I18N_ACCOUNT_LOCKED=\u8CEC\u865F\u3010%s\u3011\u5DF2\u9396\u5B9A(\u8ACB\u806F\u7CFB\u7BA1\u7406\u54E1\u89E3\u9396\u6216%s\u5206\u9418\u5F8C\u91CD\u8A66) I18N_PANEL_EXIST=\u7576\u524D\u5100\u9336\u95C6\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 +I18N_DATA_FILL_FORM_EXIST=\u7576\u524D\u6578\u64DA\u586B\u5831\u8868\u55AE\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 I18N_FOlDER_EXIST=\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 I18N_DATASET_GROUP_EXIST=\u7576\u524D\u6578\u64DA\u96C6\u5206\u7D44\u540D\u7A31\u5728\u8A72\u76EE\u9304\u4E0B\u9762\u5DF2\u7D93\u5B58\u5728 I18N_NOT_JAR=\u6587\u4EF6\u4E0D\u662F jar \u5305! @@ -274,6 +276,6 @@ I18N_PANEL_PDF_TEMPLATE_ONLY_PIC=\u9ED8\u8A8D\u6A21\u677F(\u53EA\u622A\u5716) \u8FB9\u684610=\u908A\u6846 10 I18n_name_cant_empty=\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A\uFF01 I18n_del_admin_tips=\u7981\u6B62\u522A\u9664admin\u8CEC\u865F -I18N_NO_DRIVER_PERMISSION=\u6c92\u6709\u8a31\u53ef\u6b0a\uff01 +I18N_NO_DRIVER_PERMISSION=\u6C92\u6709\u8A31\u53EF\u6B0A\uFF01 i18n_field_circular_error=\u5B57\u6BB5\u89E3\u6790\u932F\u8AA4\uFF0C\u53EF\u80FD\u539F\u56E0\uFF1A\u5B57\u6BB5\u5DF2\u522A\u9664\u3001\u8A08\u7B97\u5B57\u6BB5\u5F15\u7528\u5C64\u7D1A\u904E\u6DF1\u3001\u5B58\u5728\u5FAA\u74B0\u5F15\u7528\u7B49\uFF0C\u8ACB\u6AA2\u67E5\u8868\u7BC0\u9EDE\u548C\u5B57\u6BB5\u4E26\u91CD\u65B0\u7DE8\u8F2F\u3002 i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u74B0\u5F15\u7528 diff --git a/core/frontend/package.json b/core/frontend/package.json index 7ad64a112a..3bd7935ce3 100644 --- a/core/frontend/package.json +++ b/core/frontend/package.json @@ -74,6 +74,7 @@ "svgo": "1.2.2", "tinymce": "^5.8.2", "umy-ui": "^1.1.6", + "uuid": "^9.0.1", "vant": "^2.13.2", "vue": "2.6.10", "vue-clipboard2": "0.3.1", diff --git a/core/frontend/public/link.html b/core/frontend/public/link.html index 2bdb7b338c..635a6d4f8d 100644 --- a/core/frontend/public/link.html +++ b/core/frontend/public/link.html @@ -34,6 +34,7 @@ const terminal = getQueryVariable('terminal') const attachParams = getQueryVariable('attachParams') const fromLink = getQueryVariable('fromLink') + const ticket = getQueryVariable('ticket') const baseUrl = window.location.pathname.replace('link.html', '') let url = baseUrl + "#/delink?link=" + encodeURIComponent(link) if (terminal) { @@ -48,6 +49,9 @@ if (fromLink) { url += '&fromLink=' + fromLink } + if (ticket) { + url += '&ticket=' + ticket + } window.location.href = url diff --git a/core/frontend/src/api/link/index.js b/core/frontend/src/api/link/index.js index 16a1adf659..87256278d1 100644 --- a/core/frontend/src/api/link/index.js +++ b/core/frontend/src/api/link/index.js @@ -50,6 +50,14 @@ export function switchEnablePwd(data) { }) } +export function switchEnableTicket(data) { + return request({ + url: 'api/link/enableTicket', + method: 'post', + data + }) +} + export function viewLinkLog(data) { return request({ url: 'api/link/viewLog', diff --git a/core/frontend/src/components/canvas/components/editor/Preview.vue b/core/frontend/src/components/canvas/components/editor/Preview.vue index a47e9c757f..e95a517e29 100644 --- a/core/frontend/src/components/canvas/components/editor/Preview.vue +++ b/core/frontend/src/components/canvas/components/editor/Preview.vue @@ -313,7 +313,7 @@ export default { scaleWidth: '100', scaleHeight: '100', timer: null, - componentDataShow: null, + componentDataShow: [], mainWidth: '100%', mainHeight: '100%', searchCount: 0, diff --git a/core/frontend/src/components/canvas/customComponent/UserView.vue b/core/frontend/src/components/canvas/customComponent/UserView.vue index 5854d1fafa..904fe21254 100644 --- a/core/frontend/src/components/canvas/customComponent/UserView.vue +++ b/core/frontend/src/components/canvas/customComponent/UserView.vue @@ -946,6 +946,7 @@ export default { } if (this.isFirstLoad) { this.element.filters = this.filter.filter?.length ? JSON.parse(JSON.stringify(this.filter.filter)) : [] + this.$store.commit('setViewInitFilter', this.element) } method(id, this.panelInfo.id, requestInfo).then(response => { try { diff --git a/core/frontend/src/icons/svg/de-icon-copy.svg b/core/frontend/src/icons/svg/de-icon-copy.svg new file mode 100644 index 0000000000..65d5576757 --- /dev/null +++ b/core/frontend/src/icons/svg/de-icon-copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/frontend/src/icons/svg/de-icon-info.svg b/core/frontend/src/icons/svg/de-icon-info.svg new file mode 100644 index 0000000000..ddf29892a7 --- /dev/null +++ b/core/frontend/src/icons/svg/de-icon-info.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/core/frontend/src/icons/svg/icon_calendar_outlined.svg b/core/frontend/src/icons/svg/icon_calendar_outlined.svg index c9ed63f2de..273fceaae1 100644 --- a/core/frontend/src/icons/svg/icon_calendar_outlined.svg +++ b/core/frontend/src/icons/svg/icon_calendar_outlined.svg @@ -1,4 +1,4 @@ - - + + diff --git a/core/frontend/src/icons/svg/icon_copy_outlined.svg b/core/frontend/src/icons/svg/icon_copy_outlined.svg new file mode 100644 index 0000000000..c33dda87c2 --- /dev/null +++ b/core/frontend/src/icons/svg/icon_copy_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/frontend/src/icons/svg/icon_delete-trash_outlined.svg b/core/frontend/src/icons/svg/icon_delete-trash_outlined.svg new file mode 100644 index 0000000000..b2b5d3deda --- /dev/null +++ b/core/frontend/src/icons/svg/icon_delete-trash_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/frontend/src/icons/svg/icon_down_outlined.svg b/core/frontend/src/icons/svg/icon_down_outlined.svg new file mode 100644 index 0000000000..c44e1e87fa --- /dev/null +++ b/core/frontend/src/icons/svg/icon_down_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/frontend/src/icons/svg/icon_multi-line_outlined.svg b/core/frontend/src/icons/svg/icon_multi-line_outlined.svg new file mode 100644 index 0000000000..24c4b1cc2c --- /dev/null +++ b/core/frontend/src/icons/svg/icon_multi-line_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/core/frontend/src/icons/svg/icon_radio_outlined.svg b/core/frontend/src/icons/svg/icon_radio_outlined.svg new file mode 100644 index 0000000000..2206cec10f --- /dev/null +++ b/core/frontend/src/icons/svg/icon_radio_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/core/frontend/src/icons/svg/icon_single-line_outlined.svg b/core/frontend/src/icons/svg/icon_single-line_outlined.svg new file mode 100644 index 0000000000..5cd8e7b53d --- /dev/null +++ b/core/frontend/src/icons/svg/icon_single-line_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/core/frontend/src/icons/svg/icon_todo_outlined.svg b/core/frontend/src/icons/svg/icon_todo_outlined.svg new file mode 100644 index 0000000000..633b9b1ece --- /dev/null +++ b/core/frontend/src/icons/svg/icon_todo_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/frontend/src/lang/en.js b/core/frontend/src/lang/en.js index 80d44e924f..211246d5d6 100644 --- a/core/frontend/src/lang/en.js +++ b/core/frontend/src/lang/en.js @@ -169,6 +169,16 @@ export default { default_login: 'Normal' }, commons: { + component: { + input: 'Input', + textarea: 'Textarea', + select: 'Select', + radio: 'Radio', + checkbox: 'Checkbox', + date: 'Date Picker', + dateRange: 'Date Range Picker', + add_component_hint: 'Click or drag the component on the left to add a field' + }, consanguinity: 'Consanguinity', collapse_navigation: 'Collapse navigation', operate_cancelled: 'Operation cancelled', @@ -579,6 +589,27 @@ export default { logic_filter: 'Condition Filter', enum_filter: 'Enum Filter' }, + data_fill: { + form: { + confirm_delete: 'Confirm delete? (The tables created in database will not be deleted)', + list: 'Form List', + record: 'Fill Record', + task_manage: 'Task Manage', + form_name: 'Form Name', + datasource: 'Datasource', + table: 'Table', + creator: 'Creator', + createTime: 'Create Time' + }, + data: { + confirm_delete: 'Confirm delete?' + }, + task: { + confirm_enable: 'Confirm enable task?', + confirm_disable: 'Confirm disable task?' + }, + on_the_left: 'Please select a form on the left' + }, detabs: { custom_sort: 'Custom Sort', eidttitle: 'Edit Title', @@ -1470,7 +1501,7 @@ export default { line_type_dotted: 'Dotted', value_can_not_empty: 'Value can not be empty', value_error: 'Value illegal', - threshold: 'Threshold', + threshold: 'Conditional styles', threshold_range: 'Range', gauge_threshold_format_error: 'Format Error', total_cfg: 'Total Config', @@ -1660,7 +1691,8 @@ export default { regression_pow: 'Power law', regression_loess: 'LOESS', regression_algo: 'Algorithm', - trend_line: 'Trend Line' + trend_line: 'Trend Line', + field_enum: 'Enumeration values' }, dataset: { scope_edit: 'Effective only when editing', @@ -2848,9 +2880,14 @@ export default { chart_data_range: 'View data range', panel_format: 'Panel format', simple_repeat: 'Simple repeat', + single_task: 'Single task', once_a_day: 'Once a day', once_a_week: 'Once a week', once_a_month: 'Once a month', + hour: 'Hour', + day: 'Day', + week: 'Week', + month: 'Month', complex_repeat: 'Complex repeat', pixel_tip: 'Please code custom pixel(such as 2560 * 1600) or select', task_type: 'Task type', diff --git a/core/frontend/src/lang/tw.js b/core/frontend/src/lang/tw.js index 29a8ee5cc3..56fec1cdde 100644 --- a/core/frontend/src/lang/tw.js +++ b/core/frontend/src/lang/tw.js @@ -169,6 +169,16 @@ export default { default_login: '普通登錄' }, commons: { + component: { + input: '單行輸入', + textarea: '多行輸入', + select: '下拉框', + radio: '單選', + checkbox: '多選框', + date: '日期', + dateRange: '時間范圍', + add_component_hint: '點擊或拖拽左側組件添加字段' + }, consanguinity: '血緣關係', collapse_navigation: '收起導航', operate_cancelled: '已取消操作', @@ -579,6 +589,27 @@ export default { logic_filter: '條件篩選', enum_filter: '枚舉篩選' }, + data_fill: { + form: { + confirm_delete: '確認刪除?(不會刪除已創建的數據庫表)', + list: '表單數據', + record: '提交記錄', + task_manage: '任務管理', + form_name: '表單名稱', + datasource: '數據源', + table: '數據庫表', + creator: '創建人', + createTime: '創建時間' + }, + data: { + confirm_delete: '確認刪除?' + }, + task: { + confirm_enable: '確認啟動任務?(單次任務會新建下發任務)', + confirm_disable: '確認停止任務?' + }, + on_the_left: '請在左側選擇表單' + }, detabs: { custom_sort: '自定義排序', eidttitle: '編輯標題', @@ -1468,7 +1499,7 @@ export default { line_type_dotted: '點', value_can_not_empty: '值不能為空', value_error: '值必須為數值', - threshold: '閾值', + threshold: '條件樣式', threshold_range: '閾值區間', gauge_threshold_format_error: '格式錯誤', total_cfg: '總計配置', @@ -1652,7 +1683,8 @@ export default { regression_pow: '冪函數', regression_loess: '局部加權', regression_algo: '算法', - trend_line: '趨勢線' + trend_line: '趨勢線', + field_enum: '枚舉值' }, dataset: { scope_edit: '僅編輯時生效', @@ -2840,9 +2872,14 @@ export default { chart_data_range: '視圖數據範圍', panel_format: '儀表板格式', simple_repeat: '簡單重複', + single_task: '單次任務', once_a_day: '每天', once_a_week: '每周', once_a_month: '每月', + hour: '小時', + day: '天', + week: '周', + month: '月', complex_repeat: '複雜重複', pixel_tip: '可直接輸入分辨率(例如:2560 * 1600)或者選擇', task_type: '任務類型', diff --git a/core/frontend/src/lang/zh.js b/core/frontend/src/lang/zh.js index 5d7f34c70a..0183894693 100644 --- a/core/frontend/src/lang/zh.js +++ b/core/frontend/src/lang/zh.js @@ -169,6 +169,16 @@ export default { default_login: '普通登录' }, commons: { + component: { + input: '单行输入', + textarea: '多行输入', + select: '下拉框', + radio: '单选', + checkbox: '多选框', + date: '日期', + dateRange: '时间范围', + add_component_hint: '点击或拖拽左侧组件添加字段' + }, consanguinity: '血缘关系', collapse_navigation: '收起导航', operate_cancelled: '已取消操作', @@ -578,6 +588,27 @@ export default { logic_filter: '条件筛选', enum_filter: '枚举筛选' }, + data_fill: { + form: { + confirm_delete: '确认删除?(不会删除已创建的数据库表)', + list: '表单数据', + record: '提交记录', + task_manage: '任务管理', + form_name: '表单名称', + datasource: '数据源', + table: '数据库表', + creator: '创建人', + createTime: '创建时间' + }, + data: { + confirm_delete: '确认删除?' + }, + task: { + confirm_enable: '确认启动任务?(单次任务会新建下发任务)', + confirm_disable: '确认停止任务?' + }, + on_the_left: '请在左侧选择表单' + }, detabs: { custom_sort: '自定义排序', eidttitle: '编辑标题', @@ -1468,7 +1499,7 @@ export default { line_type_dotted: '点', value_can_not_empty: '值不能为空', value_error: '值必须为数值', - threshold: '阈值', + threshold: '条件样式', threshold_range: '阈值区间', gauge_threshold_format_error: '格式错误', total_cfg: '总计配置', @@ -1652,7 +1683,8 @@ export default { regression_pow: '幂函数', regression_loess: '局部加权', regression_algo: '算法', - trend_line: '趋势线' + trend_line: '趋势线', + field_enum: '枚举值' }, dataset: { scope_edit: '仅编辑时生效', @@ -2843,9 +2875,14 @@ export default { chart_data_range: '视图数据范围', panel_format: '仪表板格式', simple_repeat: '简单重复', + single_task: '单次任务', once_a_day: '每天', once_a_week: '每周', once_a_month: '每月', + hour: '小时', + day: '天', + week: '周', + month: '月', complex_repeat: '复杂重复', pixel_tip: '可直接输入自定义分辨率(例如:2560 * 1600)或选择', task_type: '任务类型', diff --git a/core/frontend/src/layout/index.vue b/core/frontend/src/layout/index.vue index 8c29996218..82e5b27667 100644 --- a/core/frontend/src/layout/index.vue +++ b/core/frontend/src/layout/index.vue @@ -13,7 +13,7 @@ -1 && (this.componentName === 'PanelEdit' || this.componentName === 'ChartEdit') + const path = this.$route.path + return (path.indexOf('panel') > -1 && (this.componentName === 'PanelEdit' || this.componentName === 'ChartEdit')) || (path.indexOf('/data-filling/create') > -1) + }, + showSideBar() { + return !this.sidebar.hide && this.$route.path.indexOf('data-filling') === -1 }, mainStyle() { if (this.fullHeightFlag) { @@ -154,20 +156,13 @@ export default { bus.$emit('sys-logout') }, panelSwitchComponent(c) { + console.log(c) this.componentName = c.name }, handleClickOutside() { this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) - }, - doNotNoti() { - this.buttonDisable = true - removePwdTips().then(res => { - this.showTips = false - this.buttonDisable = false - }).catch(e => { - this.buttonDisable = false - }) } + } } diff --git a/core/frontend/src/settings.js b/core/frontend/src/settings.js index 191d0e01f2..0e829ce793 100644 --- a/core/frontend/src/settings.js +++ b/core/frontend/src/settings.js @@ -1,5 +1,6 @@ module.exports = { TokenKey: 'Authorization', + TokenExpKey: 'de-login-login-exp', RefreshTokenKey: 'refreshauthorization', LinkTokenKey: 'LINK-PWD-TOKEN', title: 'DataEase', diff --git a/core/frontend/src/store/index.js b/core/frontend/src/store/index.js index 433c78b878..32d675aa4d 100644 --- a/core/frontend/src/store/index.js +++ b/core/frontend/src/store/index.js @@ -938,6 +938,15 @@ const data = { if (state.lastValidFilters[id]) { delete state.lastValidFilters[id] } + }, + setViewInitFilter(state, viewInfo) { + if (viewInfo) { + state.componentData.forEach(component => { + if (viewInfo.id === component.id) { + component.filters = viewInfo.filters + } + }) + } } }, modules: { diff --git a/core/frontend/src/store/modules/user.js b/core/frontend/src/store/modules/user.js index 4bb201dd3e..66f806c407 100644 --- a/core/frontend/src/store/modules/user.js +++ b/core/frontend/src/store/modules/user.js @@ -1,5 +1,5 @@ import { login, logout, deLogout, getInfo, getUIinfo, languageApi } from '@/api/user' -import { getToken, setToken, removeToken, setSysUI } from '@/utils/auth' +import { getToken, setToken, removeToken, setSysUI, setTokenExp } from '@/utils/auth' import { resetRouter } from '@/router' import { format } from '@/utils/formatUi' import { getLanguage } from '@/lang/index' @@ -82,6 +82,7 @@ const actions = { commit('SET_TOKEN', data.token) commit('SET_LOGIN_MSG', null) setToken(data.token) + setTokenExp(data.expireTime) let passwordModified = true if (Object.prototype.hasOwnProperty.call(data, 'passwordModified')) { passwordModified = data.passwordModified diff --git a/core/frontend/src/styles/index.scss b/core/frontend/src/styles/index.scss index 4ed359da40..67f019cbd9 100644 --- a/core/frontend/src/styles/index.scss +++ b/core/frontend/src/styles/index.scss @@ -861,7 +861,6 @@ div:focus { height: 24px !important; line-height: 24px !important; margin-bottom: 9px !important; - font-size: 16px !important; } } diff --git a/core/frontend/src/utils/auth.js b/core/frontend/src/utils/auth.js index 680a502d86..15e0ffa8f3 100644 --- a/core/frontend/src/utils/auth.js +++ b/core/frontend/src/utils/auth.js @@ -2,6 +2,7 @@ import Cookies from 'js-cookie' import Config from '@/settings' import store from '@/store' const TokenKey = Config.TokenKey +const TokenExpKey = Config.TokenExpKey const IdTokenKey = Config.IdTokenKey @@ -22,11 +23,26 @@ export function getToken() { export function setToken(token) { return Cookies.set(TokenKey, token) } +export function setTokenExp(exp) { + if (exp) { + return Cookies.set(TokenExpKey, exp) + } + return null +} + +export function tokenExp() { + const exp = Cookies.get(TokenExpKey) + if (exp && exp > 3000) { + return new Date().getTime() > (exp - 3000) + } + return false +} export function removeToken() { Cookies.remove(casSessionKey) Cookies.remove(IdTokenKey) Cookies.remove(AccessTokenKey) + Cookies.remove(TokenExpKey) return Cookies.remove(TokenKey) } diff --git a/core/frontend/src/utils/request.js b/core/frontend/src/utils/request.js index 9f4224a2e4..5bc5f02ba0 100644 --- a/core/frontend/src/utils/request.js +++ b/core/frontend/src/utils/request.js @@ -1,7 +1,7 @@ import axios from 'axios' import store from '@/store' import { $alert, $error } from './message' -import { getToken, getIdToken, setToken } from '@/utils/auth' +import { getToken, getIdToken, setToken, tokenExp } from '@/utils/auth' import Config from '@/settings' import i18n from '@/lang' import { tryShowLoading, tryHideLoading } from './loading' @@ -56,7 +56,6 @@ service.interceptors.request.use( if (idToken) { config.headers[Config.IdTokenKey] = idToken } - if (store.getters.token) { config.headers[TokenKey] = getToken() } @@ -74,7 +73,26 @@ service.interceptors.request.use( config.headers['Accept-Language'] = lang } config.loading && tryShowLoading(store.getters.currentPath) - + if (config.headers[TokenKey]) { + const logoutApiList = ['/api/auth/deLogout', '/api/auth/logout'] + if (tokenExp() && !logoutApiList.includes(config.url)) { + config['expCancel'] = null + config.cancelToken = new CancelToken(function executor(c) { + config['expCancel'] = c + }) + const message = i18n.t('login.expires') + $alert(message, () => { + store.dispatch('user/logout').then(() => { + location.reload() + }) + }, { + confirmButtonText: i18n.t('login.re_login'), + showClose: false + }) + config.expCancel('login.expires') + return config + } + } config.cancelToken = new CancelToken(function executor(c) { Vue.prototype.$currentHttpRequestList.set(config.url, c) }) @@ -104,10 +122,12 @@ service.interceptors.response.use(response => { } return response.data }, error => { - const config = error.response && error.response.config || error.config + let config = error.response && error.response.config || error.config const headers = error.response && error.response.headers || error.response || config && config.headers - config.loading && tryHideLoading(store.getters.currentPath) - + config?.loading && tryHideLoading(store.getters.currentPath) + if (!config && !headers && error.code === 'ERR_CANCELED' && error.message === 'login.expires') { + config = { hideMsg: true } + } let msg = '' if (error.response) { @@ -119,7 +139,7 @@ service.interceptors.response.use(response => { if (msg.length > 600) { msg = msg.slice(0, 600) } - !config.hideMsg && (!headers['authentication-status']) && !msg?.startsWith('MultiLoginError') && $error(msg) + !config?.hideMsg && (!headers['authentication-status']) && !msg?.startsWith('MultiLoginError') && $error(msg) return Promise.reject(config.url === '/dataset/table/sqlPreview' ? msg : error) }) const checkDownError = response => { diff --git a/core/frontend/src/utils/validate.js b/core/frontend/src/utils/validate.js index 576f91d20c..ded763ccf6 100644 --- a/core/frontend/src/utils/validate.js +++ b/core/frontend/src/utils/validate.js @@ -20,3 +20,4 @@ export function validUsername(str) { } export const PHONE_REGEX = '^1[3|4|5|7|8][0-9]{9}$' +export const EMAIL_REGEX = '^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$' diff --git a/core/frontend/src/views/background/index.vue b/core/frontend/src/views/background/index.vue index 5f09dd7895..4321d6c761 100644 --- a/core/frontend/src/views/background/index.vue +++ b/core/frontend/src/views/background/index.vue @@ -236,7 +236,7 @@ -