初始化

This commit is contained in:
2026-03-11 19:32:37 +08:00
commit 5708f80091
904 changed files with 68154 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package com.njcn.rdms.module.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 项目的启动类
*
* @author hongawen
*/
@SpringBootApplication
public class SystemServerApplication {
public static void main(String[] args) {
SpringApplication.run(SystemServerApplication.class, args);
}
}

View File

@@ -0,0 +1,25 @@
package com.njcn.rdms.module.system.api.config;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.dal.dataobject.config.ConfigDO;
import com.njcn.rdms.module.system.service.config.ConfigService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class ConfigApiImpl implements ConfigApi {
@Resource
private ConfigService configService;
@Override
public CommonResult<String> getConfigValueByKey(String key) {
ConfigDO config = configService.getConfigByKey(key);
return success(config != null ? config.getValue() : null);
}
}

View File

@@ -0,0 +1,49 @@
package com.njcn.rdms.module.system.api.dept;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.service.dept.DeptService;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class DeptApiImpl implements DeptApi {
@Resource
private DeptService deptService;
@Override
public CommonResult<DeptRespDTO> getDept(Long id) {
DeptDO dept = deptService.getDept(id);
return success(BeanUtils.toBean(dept, DeptRespDTO.class));
}
@Override
public CommonResult<List<DeptRespDTO>> getDeptList(Collection<Long> ids) {
List<DeptDO> depts = deptService.getDeptList(ids);
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
}
@Override
public CommonResult<Boolean> validateDeptList(Collection<Long> ids) {
deptService.validateDeptList(ids);
return success(true);
}
@Override
public CommonResult<List<DeptRespDTO>> getChildDeptList(Long id) {
List<DeptDO> depts = deptService.getChildDeptList(id);
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
}
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.system.api.dept;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.api.dept.dto.PostRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.dept.PostDO;
import com.njcn.rdms.module.system.service.dept.PostService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class PostApiImpl implements PostApi {
@Resource
private PostService postService;
@Override
public CommonResult<Boolean> validPostList(Collection<Long> ids) {
postService.validatePostList(ids);
return success(true);
}
@Override
public CommonResult<List<PostRespDTO>> getPostList(Collection<Long> ids) {
List<PostDO> list = postService.getPostList(ids);
return success(BeanUtils.toBean(list, PostRespDTO.class));
}
}

View File

@@ -0,0 +1,38 @@
package com.njcn.rdms.module.system.api.dict;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.common.biz.system.dict.dto.DictDataRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.dict.DictDataDO;
import com.njcn.rdms.module.system.service.dict.DictDataService;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@Primary // 由于 DictDataCommonApi 的存在,必须声明为 @Primary Bean
public class DictDataApiImpl implements DictDataApi {
@Resource
private DictDataService dictDataService;
@Override
public CommonResult<Boolean> validateDictDataList(String dictType, Collection<String> values) {
dictDataService.validateDictDataList(dictType, values);
return success(true);
}
@Override
public CommonResult<List<DictDataRespDTO>> getDictDataList(String dictType) {
List<DictDataDO> list = dictDataService.getDictDataListByDictType(dictType);
return success(BeanUtils.toBean(list, DictDataRespDTO.class));
}
}

View File

@@ -0,0 +1,30 @@
package com.njcn.rdms.module.system.api.file;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.file.dto.FileCreateReqDTO;
import com.njcn.rdms.module.system.service.file.FileService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class FileApiImpl implements FileApi {
@Resource
private FileService fileService;
@Override
public CommonResult<String> createFile(FileCreateReqDTO createReqDTO) {
return success(fileService.createFile(createReqDTO.getContent(), createReqDTO.getName(),
createReqDTO.getDirectory(), createReqDTO.getType()));
}
@Override
public CommonResult<String> presignGetUrl(String url, Integer expirationSeconds) {
return success(fileService.presignGetUrl(url, expirationSeconds));
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.logger.ApiAccessLogService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class ApiAccessLogApiImpl implements ApiAccessLogCommonApi {
@Resource
private ApiAccessLogService apiAccessLogService;
@Override
public CommonResult<Boolean> createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {
apiAccessLogService.createApiAccessLog(createDTO);
return success(true);
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.logger.ApiErrorLogService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class ApiErrorLogApiImpl implements ApiErrorLogCommonApi {
@Resource
private ApiErrorLogService apiErrorLogService;
@Override
public CommonResult<Boolean> createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) {
apiErrorLogService.createApiErrorLog(createDTO);
return success(true);
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.logger.dto.LoginLogCreateReqDTO;
import com.njcn.rdms.module.system.service.logger.LoginLogService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class LoginLogApiImpl implements LoginLogApi {
@Resource
private LoginLogService loginLogService;
@Override
public CommonResult<Boolean> createLoginLog(LoginLogCreateReqDTO reqDTO) {
loginLogService.createLoginLog(reqDTO);
return success(true);
}
}

View File

@@ -0,0 +1,38 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.common.biz.system.logger.dto.OperateLogCreateReqDTO;
import com.njcn.rdms.module.system.api.logger.dto.OperateLogPageReqDTO;
import com.njcn.rdms.module.system.api.logger.dto.OperateLogRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.logger.OperateLogDO;
import com.njcn.rdms.module.system.service.logger.OperateLogService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@Primary // 由于 OperateLogCommonApi 的存在,必须声明为 @Primary Bean
public class OperateLogApiImpl implements OperateLogApi {
@Resource
private OperateLogService operateLogService;
@Override
public CommonResult<Boolean> createOperateLog(OperateLogCreateReqDTO createReqDTO) {
operateLogService.createOperateLog(createReqDTO);
return success(true);
}
@Override
public CommonResult<PageResult<OperateLogRespDTO>> getOperateLogPage(OperateLogPageReqDTO pageReqDTO) {
PageResult<OperateLogDO> operateLogPage = operateLogService.getOperateLogPage(pageReqDTO);
return success(BeanUtils.toBean(operateLogPage, OperateLogRespDTO.class));
}
}

View File

@@ -0,0 +1,33 @@
package com.njcn.rdms.module.system.api.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import com.njcn.rdms.module.system.service.mail.MailSendService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class MailSendApiImpl implements MailSendApi {
@Resource
private MailSendService mailSendService;
@Override
public CommonResult<Long> sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
return success(mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()));
}
@Override
public CommonResult<Long> sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
return success(mailSendService.sendSingleMailToMember(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()));
}
}

View File

@@ -0,0 +1,32 @@
package com.njcn.rdms.module.system.api.notify;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import com.njcn.rdms.module.system.service.notify.NotifySendService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class NotifyMessageSendApiImpl implements NotifyMessageSendApi {
@Resource
private NotifySendService notifySendService;
@Override
public CommonResult<Long> sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) {
return success(notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
}
@Override
public CommonResult<Long> sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) {
return success(notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
}
}

View File

@@ -0,0 +1,51 @@
package com.njcn.rdms.module.system.api.oauth2;
import com.njcn.rdms.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import com.njcn.rdms.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.njcn.rdms.module.system.service.oauth2.OAuth2TokenService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class OAuth2TokenApiImpl implements OAuth2TokenCommonApi {
@Resource
private OAuth2TokenService oauth2TokenService;
@Override
public CommonResult<OAuth2AccessTokenRespDTO> createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
}
@Override
// 访问令牌校验时,无需传递租户编号;主要解决上传文件的场景,前端不会传递 tenant-id
public CommonResult<OAuth2AccessTokenCheckRespDTO> checkAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken);
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class));
}
@Override
public CommonResult<OAuth2AccessTokenRespDTO> removeAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
}
@Override
public CommonResult<OAuth2AccessTokenRespDTO> refreshAccessToken(String refreshToken, String clientId) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class));
}
}

View File

@@ -0,0 +1,39 @@
package com.njcn.rdms.module.system.api.permission;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.permission.PermissionService;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.Set;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@Primary // 由于 PermissionCommonApi 的存在,必须声明为 @Primary Bean
public class PermissionApiImpl implements PermissionApi {
@Resource
private PermissionService permissionService;
@Override
public CommonResult<Set<Long>> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
return success(permissionService.getUserRoleIdListByRoleId(roleIds));
}
@Override
public CommonResult<Boolean> hasAnyPermissions(Long userId, String... permissions) {
return success(permissionService.hasAnyPermissions(userId, permissions));
}
@Override
public CommonResult<Boolean> hasAnyRoles(Long userId, String... roles) {
return success(permissionService.hasAnyRoles(userId, roles));
}
}

View File

@@ -0,0 +1,25 @@
package com.njcn.rdms.module.system.api.permission;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.permission.RoleService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.Collection;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class RoleApiImpl implements RoleApi {
@Resource
private RoleService roleService;
@Override
public CommonResult<Boolean> validRoleList(Collection<Long> ids) {
roleService.validateRoleList(ids);
return success(true);
}
}

View File

@@ -0,0 +1,91 @@
package com.njcn.rdms.module.system.api.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.service.dept.DeptService;
import com.njcn.rdms.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertSet;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class AdminUserApiImpl implements AdminUserApi {
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@Override
public CommonResult<AdminUserRespDTO> getUser(Long id) {
AdminUserDO user = userService.getUser(id);
return success(BeanUtils.toBean(user, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserListBySubordinate(Long id) {
// 1.1 获取用户负责的部门
AdminUserDO user = userService.getUser(id);
if (user == null) {
return success(Collections.emptyList());
}
ArrayList<Long> deptIds = new ArrayList<>();
DeptDO dept = deptService.getDept(user.getDeptId());
if (dept == null) {
return success(Collections.emptyList());
}
if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人
return success(Collections.emptyList());
}
deptIds.add(dept.getId());
// 1.2 获取所有子部门
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
if (CollUtil.isNotEmpty(childDeptList)) {
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
}
// 2. 获取部门对应的用户信息
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserList(Collection<Long> ids) {
List<AdminUserDO> users = userService.getUserList(ids);
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserListByDeptIds(Collection<Long> deptIds) {
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
}
@Override
public CommonResult<List<AdminUserRespDTO>> getUserListByPostIds(Collection<Long> postIds) {
List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
return success(BeanUtils.toBean(users, AdminUserRespDTO.class));
}
@Override
public CommonResult<Boolean> validateUserList(Collection<Long> ids) {
userService.validateUserList(ids);
return success(true);
}
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.system.api.websocket;
import cn.hutool.core.util.StrUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.websocket.core.sender.WebSocketMessageSender;
import com.njcn.rdms.module.system.api.websocket.dto.WebSocketSendReqDTO;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class WebSocketSenderApiImpl implements WebSocketSenderApi {
@Resource
private WebSocketMessageSender webSocketMessageSender;
@Override
public CommonResult<Boolean> send(WebSocketSendReqDTO message) {
if (StrUtil.isNotEmpty(message.getSessionId())) {
webSocketMessageSender.send(message.getSessionId(),
message.getMessageType(), message.getMessageContent());
} else if (message.getUserType() != null && message.getUserId() != null) {
webSocketMessageSender.send(message.getUserType(), message.getUserId(),
message.getMessageType(), message.getMessageContent());
} else if (message.getUserType() != null) {
webSocketMessageSender.send(message.getUserType(),
message.getMessageType(), message.getMessageContent());
}
return success(true);
}
}

View File

@@ -0,0 +1,51 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenantId}}
tag: Yunai.local
{
"username": "admin",
"password": "admin123",
"uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
### 请求 /login 接口【加密 AES】 => 成功
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenantId}}
tag: Yunai.local
X-API-ENCRYPT: true
WvSX9MOrenyGfBhEM0g1/hHgq8ocktMZ9OwAJ6MOG5FUrzYF/rG5JF1eMptQM1wT73VgDS05l/37WeRtad+JrqChAul/sR/SdOsUKqjBhvvQx1JVhzxr6s8uUP67aKTSZ6Psv7O32ELxXrzSaQvG5CInzz3w6sLtbNNLd1kXe6Q=
### 请求 /login 接口【加密 RSA】 => 成功
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenantId}}
tag: Yunai.local
X-API-ENCRYPT: true
e7QZTork9ZV5CmgZvSd+cHZk3xdUxKtowLM02kOha+gxHK2H/daU8nVBYS3+bwuDRy5abf+Pz1QJJGVAEd27wwrXBmupOOA/bhpuzzDwcRuJRD+z+YgiNoEXFDRHERxPYlPqAe9zAHtihD0ceub1AjybQsEsROew4C3Q602XYW0=
### 请求 /login 接口 => 成功(无验证码)
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenantId}}
{
"username": "admin",
"password": "admin123"
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/system/auth/get-permission-info
Authorization: Bearer {{token}}
tenant-id: {{adminTenantId}}
### 请求 /list-menus 接口 => 成功
GET {{baseUrl}}/system/list-menus
Authorization: Bearer {{token}}
#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a
tenant-id: {{adminTenantId}}

View File

@@ -0,0 +1,119 @@
package com.njcn.rdms.module.system.controller.admin.auth;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.security.config.SecurityProperties;
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.system.controller.admin.auth.vo.*;
import com.njcn.rdms.module.system.convert.auth.AuthConvert;
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.enums.logger.LoginLogTypeEnum;
import com.njcn.rdms.module.system.service.auth.AdminAuthService;
import com.njcn.rdms.module.system.service.permission.MenuService;
import com.njcn.rdms.module.system.service.permission.PermissionService;
import com.njcn.rdms.module.system.service.permission.RoleService;
import com.njcn.rdms.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertSet;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {
@Resource
private AdminAuthService authService;
@Resource
private AdminUserService userService;
@Resource
private RoleService roleService;
@Resource
private MenuService menuService;
@Resource
private PermissionService permissionService;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
}
@PostMapping("/logout")
@PermitAll
@Operation(summary = "登出系统")
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = SecurityFrameworkUtils.obtainAuthorization(request,
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
return success(true);
}
@PostMapping("/refresh-token")
@PermitAll
@Operation(summary = "刷新令牌")
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
// 1.1 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return success(null);
}
// 1.2 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
if (CollUtil.isEmpty(roleIds)) {
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = menuService.getMenuList(menuIds);
menuList = menuService.filterDisableMenus(menuList);
// 2. 拼接结果返回
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
}
@PostMapping("/register")
@PermitAll
@Operation(summary = "注册用户")
public CommonResult<AuthLoginRespVO> register(@RequestBody @Valid AuthRegisterReqVO registerReqVO) {
return success(authService.register(registerReqVO));
}
}

View File

@@ -0,0 +1,31 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
@Schema(description = "管理后台 - 账号密码登录 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginReqVO extends CaptchaVerificationReqVO {
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 30, message = "账号长度为 4-30 位")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "账号格式为数字以及字母")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@@ -0,0 +1,30 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 登录 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginRespVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long userId;
@Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy")
private String accessToken;
@Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice")
private String refreshToken;
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime expiresTime;
}

View File

@@ -0,0 +1,53 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthMenuRespVO {
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private Long id;
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String name;
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
private String path;
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
private String component;
@Schema(description = "组件名", example = "SystemUser")
private String componentName;
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
private String icon;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean visible;
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean keepAlive;
@Schema(description = "是否总是显示", example = "false")
private Boolean alwaysShow;
/**
* 子路由
*/
private List<AuthMenuRespVO> children;
}

View File

@@ -0,0 +1,102 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
@Schema(description = "管理后台 - 登录用户的权限信息 Response VO额外包括用户信息和角色列表")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthPermissionInfoRespVO {
@Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED)
private UserVO user;
@Schema(description = "角色标识数组", requiredMode = Schema.RequiredMode.REQUIRED)
private Set<String> roles;
@Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED)
private Set<String> permissions;
@Schema(description = "菜单树", requiredMode = Schema.RequiredMode.REQUIRED)
private List<MenuVO> menus;
@Schema(description = "用户信息 VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class UserVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
private String nickname;
@Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
private String avatar;
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private Long deptId;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
private String username;
@Schema(description = "用户邮箱", example = "rdms@iocoder.cn")
private String email;
}
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class MenuVO {
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private Long id;
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String name;
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
private String path;
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
private String component;
@Schema(description = "组件名", example = "SystemUser")
private String componentName;
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
private String icon;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean visible;
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean keepAlive;
@Schema(description = "是否总是显示", example = "false")
private Boolean alwaysShow;
/**
* 子路由
*/
private List<MenuVO> children;
}
}

View File

@@ -0,0 +1,31 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
@Schema(description = "管理后台 - Register Request VO")
@Data
public class AuthRegisterReqVO extends CaptchaVerificationReqVO {
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotBlank(message = "用户账号不能为空")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
private String username;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@NotBlank(message = "用户昵称不能为空")
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符")
private String nickname;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@@ -0,0 +1,22 @@
package com.njcn.rdms.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
@Schema(description = "管理后台 - 验证码 Request VO")
@Data
public class CaptchaVerificationReqVO {
// ========== 图片验证码相关 ==========
@Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED,
example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String captchaVerification;
/**
* 开启验证码的 Group
*/
public interface CodeEnableGroup {
}
}

View File

@@ -0,0 +1,55 @@
package com.njcn.rdms.module.system.controller.admin.captcha;
import cn.hutool.core.util.StrUtil;
import com.njcn.rdms.framework.common.util.servlet.ServletUtils;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
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;
@Tag(name = "管理后台 - 验证码")
@RestController("adminCaptchaController")
@RequestMapping("/system/captcha")
public class CaptchaController {
@Resource
private CaptchaService captchaService;
@PostMapping({"/get"})
@Operation(summary = "获得验证码")
@PermitAll
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
assert request.getRemoteHost() != null;
data.setBrowserInfo(getRemoteId(request));
return captchaService.get(data);
}
@PostMapping("/check")
@Operation(summary = "校验验证码")
@PermitAll
public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
data.setBrowserInfo(getRemoteId(request));
return captchaService.check(data);
}
public static String getRemoteId(HttpServletRequest request) {
String ip = ServletUtils.getClientIP(request);
String ua = request.getHeader("user-agent");
if (StrUtil.isNotBlank(ip)) {
return ip + ua;
}
return request.getRemoteAddr() + ua;
}
}

View File

@@ -0,0 +1,160 @@
package com.njcn.rdms.module.system.controller.admin.codegen;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenCreateListReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenDetailRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenPreviewRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenUpdateReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import com.njcn.rdms.module.system.convert.codegen.CodegenConvert;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenColumnDO;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenTableDO;
import com.njcn.rdms.module.system.service.codegen.CodegenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname;
import static com.njcn.rdms.module.system.framework.file.core.utils.FileTypeUtils.writeAttachment;
@Tag(name = "管理后台 - 代码生成器")
@RestController
@RequestMapping("/infra/codegen")
@Validated
public class CodegenController {
@Resource
private CodegenService codegenService;
@GetMapping("/db/table/list")
@Operation(summary = "获得数据库自带的表定义列表", description = "会过滤掉已经导入 Codegen 的表")
@Parameters({
@Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1"),
@Parameter(name = "name", description = "表名,模糊匹配", example = "rdms"),
@Parameter(name = "comment", description = "描述,模糊匹配", example = "灿能")
})
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<List<DatabaseTableRespVO>> getDatabaseTableList(
@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId,
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "comment", required = false) String comment) {
return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment));
}
@GetMapping("/table/list")
@Operation(summary = "获得表定义列表")
@Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
}
@GetMapping("/table/page")
@Operation(summary = "获得表定义分页")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
}
@GetMapping("/detail")
@Operation(summary = "获得表和字段的明细")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
CodegenTableDO table = codegenService.getCodegenTable(tableId);
List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
// 拼装返回
return success(CodegenConvert.INSTANCE.convert(table, columns));
}
@Operation(summary = "基于数据库的表结构,创建代码生成器的表和字段定义")
@PostMapping("/create-list")
@PreAuthorize("@ss.hasPermission('infra:codegen:create')")
public CommonResult<List<Long>> createCodegenList(@Valid @RequestBody CodegenCreateListReqVO reqVO) {
return success(codegenService.createCodegenList(getLoginUserNickname(), reqVO));
}
@Operation(summary = "更新数据库的表和字段定义")
@PutMapping("/update")
@PreAuthorize("@ss.hasPermission('infra:codegen:update')")
public CommonResult<Boolean> updateCodegen(@Valid @RequestBody CodegenUpdateReqVO updateReqVO) {
codegenService.updateCodegen(updateReqVO);
return success(true);
}
@Operation(summary = "基于数据库的表结构,同步数据库的表和字段定义")
@PutMapping("/sync-from-db")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:update')")
public CommonResult<Boolean> syncCodegenFromDB(@RequestParam("tableId") Long tableId) {
codegenService.syncCodegenFromDB(tableId);
return success(true);
}
@Operation(summary = "删除数据库的表和字段定义")
@DeleteMapping("/delete")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:delete')")
public CommonResult<Boolean> deleteCodegen(@RequestParam("tableId") Long tableId) {
codegenService.deleteCodegen(tableId);
return success(true);
}
@Operation(summary = "批量删除数据库的表和字段定义")
@DeleteMapping("/delete-list")
@Parameter(name = "tableIds", description = "表编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:codegen:delete')")
public CommonResult<Boolean> deleteCodegenList(@RequestParam("tableIds") List<Long> tableIds) {
codegenService.deleteCodegenList(tableIds);
return success(true);
}
@Operation(summary = "预览生成代码")
@GetMapping("/preview")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:preview')")
public CommonResult<List<CodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
Map<String, String> codes = codegenService.generationCodes(tableId);
return success(CodegenConvert.INSTANCE.convert(codes));
}
@Operation(summary = "下载生成代码")
@GetMapping("/download")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:download')")
public void downloadCodegen(@RequestParam("tableId") Long tableId,
HttpServletResponse response) throws IOException {
// 生成代码
Map<String, String> codes = codegenService.generationCodes(tableId);
// 构建 zip 包
String[] paths = codes.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipUtil.zip(outputStream, paths, ins);
// 输出
writeAttachment(response, "codegen.zip", outputStream.toByteArray());
}
}

View File

@@ -0,0 +1,21 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO")
@Data
public class CodegenCreateListReqVO {
@Schema(description = "数据源配置的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "数据源配置的编号不能为空")
private Long dataSourceConfigId;
@Schema(description = "表名数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
@NotNull(message = "表名数组不能为空")
private List<String> tableNames;
}

View File

@@ -0,0 +1,20 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 代码生成表和字段的明细 Response VO")
@Data
public class CodegenDetailRespVO {
@Schema(description = "表定义")
private CodegenTableRespVO table;
@Schema(description = "字段定义")
private List<CodegenColumnRespVO> columns;
}

View File

@@ -0,0 +1,16 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成预览 Response VO注意每个文件都是一个该对象")
@Data
public class CodegenPreviewRespVO {
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "java/com.njcn.rdms/adminserver/modules/system/controller/test/SysTestDemoController.java")
private String filePath;
@Schema(description = "代码", requiredMode = Schema.RequiredMode.REQUIRED, example = "Hello World")
private String code;
}

View File

@@ -0,0 +1,24 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 代码生成表和字段的修改 Request VO")
@Data
public class CodegenUpdateReqVO {
@Valid // 校验内嵌的字段
@NotNull(message = "表定义不能为空")
private CodegenTableSaveReqVO table;
@Valid // 校验内嵌的字段
@NotNull(message = "字段定义不能为空")
private List<CodegenColumnSaveReqVO> columns;
}

View File

@@ -0,0 +1,69 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.column;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成字段定义 Response VO")
@Data
public class CodegenColumnRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long tableId;
@Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
private String columnName;
@Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
private String dataType;
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
private String columnComment;
@Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean nullable;
@Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean primaryKey;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer ordinalPosition;
@Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
private String javaType;
@Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
private String javaField;
@Schema(description = "字典类型", example = "sys_gender")
private String dictType;
@Schema(description = "数据示例", example = "1024")
private String example;
@Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean createOperation;
@Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean updateOperation;
@Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperation;
@Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
private String listOperationCondition;
@Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperationResult;
@Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
private String htmlType;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,80 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.column;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
@Data
public class CodegenColumnSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "表编号不能为空")
private Long tableId;
@Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
@NotNull(message = "字段名不能为空")
private String columnName;
@Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
@NotNull(message = "字段类型不能为空")
private String dataType;
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
@NotNull(message = "字段描述不能为空")
private String columnComment;
@Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否允许为空不能为空")
private Boolean nullable;
@Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
@NotNull(message = "是否主键不能为空")
private Boolean primaryKey;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@NotNull(message = "排序不能为空")
private Integer ordinalPosition;
@Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
@NotNull(message = "Java 属性类型不能为空")
private String javaType;
@Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
@NotNull(message = "Java 属性名不能为空")
private String javaField;
@Schema(description = "字典类型", example = "sys_gender")
private String dictType;
@Schema(description = "数据示例", example = "1024")
private String example;
@Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 Create 创建操作的字段不能为空")
private Boolean createOperation;
@Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
@NotNull(message = "是否为 Update 更新操作的字段不能为空")
private Boolean updateOperation;
@Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 List 查询操作的字段不能为空")
private Boolean listOperation;
@Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
@NotNull(message = "List 查询操作的条件类型不能为空")
private String listOperationCondition;
@Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 List 查询操作的返回字段不能为空")
private Boolean listOperationResult;
@Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
@NotNull(message = "显示类型不能为空")
private String htmlType;
}

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 表定义分页 Request VO")
@Data
public class CodegenTablePageReqVO extends PageParam {
@Schema(description = "表名称,模糊匹配", example = "rdms")
private String tableName;
@Schema(description = "表描述,模糊匹配", example = "灿能")
private String tableComment;
@Schema(description = "实体,模糊匹配", example = "Rdms")
private String className;
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,72 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成表定义 Response VO")
@Data
public class CodegenTableRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer scene;
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
private String tableName;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String tableComment;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
private String moduleName;
@Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
private String businessName;
@Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
private String className;
@Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
private String classComment;
@Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
private String author;
@Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer templateType;
@Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer frontType;
@Schema(description = "父菜单编号", example = "1024")
private Long parentMenuId;
@Schema(description = "主表的编号", example = "2048")
private Long masterTableId;
@Schema(description = "子表关联主表的字段编号", example = "4096")
private Long subJoinColumnId;
@Schema(description = "主表与子表是否一对多", example = "4096")
private Boolean subJoinMany;
@Schema(description = "树表的父字段编号", example = "8192")
private Long treeParentColumnId;
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Integer dataSourceConfigId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,99 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.njcn.rdms.module.system.enums.codegen.CodegenSceneEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenTemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
@Data
public class CodegenTableSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "导入类型不能为空")
private Integer scene;
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotNull(message = "表名称不能为空")
private String tableName;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@NotNull(message = "表描述不能为空")
private String tableComment;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
@NotNull(message = "模块名不能为空")
private String moduleName;
@Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
@NotNull(message = "业务名不能为空")
private String businessName;
@Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
@NotNull(message = "类名称不能为空")
private String className;
@Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
@NotNull(message = "类描述不能为空")
private String classComment;
@Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
@NotNull(message = "作者不能为空")
private String author;
@Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "模板类型不能为空")
private Integer templateType;
@Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "前端类型不能为空")
private Integer frontType;
@Schema(description = "父菜单编号", example = "1024")
private Long parentMenuId;
@Schema(description = "主表的编号", example = "2048")
private Long masterTableId;
@Schema(description = "子表关联主表的字段编号", example = "4096")
private Long subJoinColumnId;
@Schema(description = "主表与子表是否一对多", example = "4096")
private Boolean subJoinMany;
@Schema(description = "树表的父字段编号", example = "8192")
private Long treeParentColumnId;
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
@JsonIgnore
public boolean isParentMenuIdValid() {
// 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
|| getParentMenuId() != null;
}
@AssertTrue(message = "关联的父表信息不全")
@JsonIgnore
public boolean isSubValid() {
return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
|| (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
}
@AssertTrue(message = "关联的树表信息不全")
@JsonIgnore
public boolean isTreeValid() {
return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
|| (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
}
}

View File

@@ -0,0 +1,16 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 数据库的表定义 Response VO")
@Data
public class DatabaseTableRespVO {
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yuanma")
private String name;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
private String comment;
}

View File

@@ -0,0 +1,117 @@
package com.njcn.rdms.module.system.controller.admin.config;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.config.vo.ConfigPageReqVO;
import com.njcn.rdms.module.system.controller.admin.config.vo.ConfigRespVO;
import com.njcn.rdms.module.system.controller.admin.config.vo.ConfigSaveReqVO;
import com.njcn.rdms.module.system.convert.config.ConfigConvert;
import com.njcn.rdms.module.system.dal.dataobject.config.ConfigDO;
import com.njcn.rdms.module.system.enums.ErrorCodeConstants;
import com.njcn.rdms.module.system.service.config.ConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 参数配置")
@RestController
@RequestMapping("/infra/config")
@Validated
public class ConfigController {
@Resource
private ConfigService configService;
@PostMapping("/create")
@Operation(summary = "创建参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:create')")
public CommonResult<Long> createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) {
return success(configService.createConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:update')")
public CommonResult<Boolean> updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) {
configService.updateConfig(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
configService.deleteConfig(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除参数配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
public CommonResult<Boolean> deleteConfigList(@RequestParam("ids") List<Long> ids) {
configService.deleteConfigList(ids);
return success(true);
}
@GetMapping(value = "/get")
@Operation(summary = "获得参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
public CommonResult<ConfigRespVO> getConfig(@RequestParam("id") Long id) {
return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id)));
}
@GetMapping(value = "/get-value-by-key")
@Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端")
@Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username")
public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
ConfigDO config = configService.getConfigByKey(key);
if (config == null) {
return success(null);
}
if (!config.getVisible()) {
throw exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE);
}
return success(config.getValue());
}
@GetMapping("/page")
@Operation(summary = "获取参数配置分页")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
public CommonResult<PageResult<ConfigRespVO>> getConfigPage(@Valid ConfigPageReqVO pageReqVO) {
PageResult<ConfigDO> page = configService.getConfigPage(pageReqVO);
return success(ConfigConvert.INSTANCE.convertPage(page));
}
@GetMapping("/export-excel")
@Operation(summary = "导出参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportConfig(ConfigPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ConfigDO> list = configService.getConfigPage(exportReqVO).getList();
// 输出
ExcelUtils.write(response, "参数配置.xls", "数据", ConfigRespVO.class,
ConfigConvert.INSTANCE.convertList(list));
}
}

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.system.controller.admin.config.vo;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 参数配置分页 Request VO")
@Data
public class ConfigPageReqVO extends PageParam {
@Schema(description = "数据源名称,模糊匹配", example = "名称")
private String name;
@Schema(description = "参数键名,模糊匹配", example = "yunai.db.username")
private String key;
@Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1")
private Integer type;
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,56 @@
package com.njcn.rdms.module.system.controller.admin.config.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 参数配置信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ConfigRespVO {
@Schema(description = "参数配置序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("参数配置序号")
private Long id;
@Schema(description = "参数分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz")
@ExcelProperty("参数分类")
private String category;
@Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名")
@ExcelProperty("参数名称")
private String name;
@Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username")
@ExcelProperty("参数键名")
private String key;
@Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("参数键值")
private String value;
@Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "参数类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.CONFIG_TYPE)
private Integer type;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@ExcelProperty(value = "是否可见", converter = DictConvert.class)
@DictFormat(DictTypeConstants.BOOLEAN_STRING)
private Boolean visible;
@Schema(description = "备注", example = "备注一下很帅气!")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.system.controller.admin.config.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 参数配置创建/修改 Request VO")
@Data
public class ConfigSaveReqVO {
@Schema(description = "参数配置序号", example = "1024")
private Long id;
@Schema(description = "参数分组", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz")
@NotEmpty(message = "参数分组不能为空")
@Size(max = 50, message = "参数名称不能超过 50 个字符")
private String category;
@Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名")
@NotBlank(message = "参数名称不能为空")
@Size(max = 100, message = "参数名称不能超过 100 个字符")
private String name;
@Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username")
@NotBlank(message = "参数键名长度不能为空")
@Size(max = 100, message = "参数键名长度不能超过 100 个字符")
private String key;
@Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotBlank(message = "参数键值不能为空")
@Size(max = 500, message = "参数键值长度不能超过 500 个字符")
private String value;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否可见不能为空")
private Boolean visible;
@Schema(description = "备注", example = "备注一下很帅气!")
private String remark;
}

View File

@@ -0,0 +1,81 @@
package com.njcn.rdms.module.system.controller.admin.db;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.db.vo.DataSourceConfigRespVO;
import com.njcn.rdms.module.system.controller.admin.db.vo.DataSourceConfigSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.db.DataSourceConfigDO;
import com.njcn.rdms.module.system.service.db.DataSourceConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 数据源配置")
@RestController
@RequestMapping("/infra/data-source-config")
@Validated
public class DataSourceConfigController {
@Resource
private DataSourceConfigService dataSourceConfigService;
@PostMapping("/create")
@Operation(summary = "创建数据源配置")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:create')")
public CommonResult<Long> createDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO createReqVO) {
return success(dataSourceConfigService.createDataSourceConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新数据源配置")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:update')")
public CommonResult<Boolean> updateDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO updateReqVO) {
dataSourceConfigService.updateDataSourceConfig(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除数据源配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')")
public CommonResult<Boolean> deleteDataSourceConfig(@RequestParam("id") Long id) {
dataSourceConfigService.deleteDataSourceConfig(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除数据源配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')")
public CommonResult<Boolean> deleteDataSourceConfigList(@RequestParam("ids") List<Long> ids) {
dataSourceConfigService.deleteDataSourceConfigList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得数据源配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:query')")
public CommonResult<DataSourceConfigRespVO> getDataSourceConfig(@RequestParam("id") Long id) {
DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(id);
return success(BeanUtils.toBean(config, DataSourceConfigRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得数据源配置列表")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:query')")
public CommonResult<List<DataSourceConfigRespVO>> getDataSourceConfigList() {
List<DataSourceConfigDO> list = dataSourceConfigService.getDataSourceConfigList();
return success(BeanUtils.toBean(list, DataSourceConfigRespVO.class));
}
}

View File

@@ -0,0 +1,27 @@
package com.njcn.rdms.module.system.controller.admin.db.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 数据源配置 Response VO")
@Data
public class DataSourceConfigRespVO {
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
private String name;
@Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro")
private String url;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root")
private String username;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,30 @@
package com.njcn.rdms.module.system.controller.admin.db.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 数据源配置创建/修改 Request VO")
@Data
public class DataSourceConfigSaveReqVO {
@Schema(description = "主键编号", example = "1024")
private Long id;
@Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
@NotNull(message = "数据源名称不能为空")
private String name;
@Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro")
@NotNull(message = "数据源连接不能为空")
private String url;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root")
@NotNull(message = "用户名不能为空")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotNull(message = "密码不能为空")
private String password;
}

View File

@@ -0,0 +1,93 @@
package com.njcn.rdms.module.system.controller.admin.dept;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.dept.DeptRespVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.service.dept.DeptService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 部门")
@RestController
@RequestMapping("/system/dept")
@Validated
public class DeptController {
@Resource
private DeptService deptService;
@PostMapping("create")
@Operation(summary = "创建部门")
@PreAuthorize("@ss.hasPermission('system:dept:create')")
public CommonResult<Long> createDept(@Valid @RequestBody DeptSaveReqVO createReqVO) {
Long deptId = deptService.createDept(createReqVO);
return success(deptId);
}
@PutMapping("update")
@Operation(summary = "更新部门")
@PreAuthorize("@ss.hasPermission('system:dept:update')")
public CommonResult<Boolean> updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) {
deptService.updateDept(updateReqVO);
return success(true);
}
@DeleteMapping("delete")
@Operation(summary = "删除部门")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
public CommonResult<Boolean> deleteDept(@RequestParam("id") Long id) {
deptService.deleteDept(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除部门")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
public CommonResult<Boolean> deleteDeptList(@RequestParam("ids") List<Long> ids) {
deptService.deleteDeptList(ids);
return success(true);
}
@GetMapping("/list")
@Operation(summary = "获取部门列表")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<List<DeptRespVO>> getDeptList(DeptListReqVO reqVO) {
List<DeptDO> list = deptService.getDeptList(reqVO);
return success(BeanUtils.toBean(list, DeptRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "/simple-list"})
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
public CommonResult<List<DeptSimpleRespVO>> getSimpleDeptList() {
List<DeptDO> list = deptService.getDeptList(
new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<DeptRespVO> getDept(@RequestParam("id") Long id) {
DeptDO dept = deptService.getDept(id);
return success(BeanUtils.toBean(dept, DeptRespVO.class));
}
}

View File

@@ -0,0 +1,114 @@
package com.njcn.rdms.module.system.controller.admin.dept;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostRespVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.dept.PostDO;
import com.njcn.rdms.module.system.service.dept.PostService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 岗位")
@RestController
@RequestMapping("/system/post")
@Validated
public class PostController {
@Resource
private PostService postService;
@PostMapping("/create")
@Operation(summary = "创建岗位")
@PreAuthorize("@ss.hasPermission('system:post:create')")
public CommonResult<Long> createPost(@Valid @RequestBody PostSaveReqVO createReqVO) {
Long postId = postService.createPost(createReqVO);
return success(postId);
}
@PutMapping("/update")
@Operation(summary = "修改岗位")
@PreAuthorize("@ss.hasPermission('system:post:update')")
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
postService.updatePost(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除岗位")
@PreAuthorize("@ss.hasPermission('system:post:delete')")
public CommonResult<Boolean> deletePost(@RequestParam("id") Long id) {
postService.deletePost(id);
return success(true);
}
@DeleteMapping("delete-list")
@Operation(summary = "批量删除岗位")
@PreAuthorize("@ss.hasPermission('system:post:delete')")
public CommonResult<Boolean> deletePostList(@RequestParam("ids") List<Long> ids) {
postService.deletePostList(ids);
return success(true);
}
@GetMapping(value = "/get")
@Operation(summary = "获得岗位信息")
@Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
PostDO post = postService.getPost(id);
return success(BeanUtils.toBean(post, PostRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
public CommonResult<List<PostSimpleRespVO>> getSimplePostList() {
// 获得岗位列表,只要开启状态的
List<PostDO> list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(PostDO::getSort));
return success(BeanUtils.toBean(list, PostSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得岗位分页列表")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PostRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "岗位管理")
@PreAuthorize("@ss.hasPermission('system:post:export')")
@ApiAccessLog(operateType = EXPORT)
public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PostDO> list = postService.getPostPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class,
BeanUtils.toBean(list, PostRespVO.class));
}
}

View File

@@ -0,0 +1,16 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.dept;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 部门列表 Request VO")
@Data
public class DeptListReqVO {
@Schema(description = "部门名称,模糊匹配", example = "灿能")
private String name;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;
}

View File

@@ -0,0 +1,39 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.dept;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 部门信息 Response VO")
@Data
public class DeptRespVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String name;
@Schema(description = "父部门 ID", example = "1024")
private Long parentId;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Integer sort;
@Schema(description = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@Schema(description = "联系电话", example = "15601691000")
private String phone;
@Schema(description = "邮箱", example = "rdms@iocoder.cn")
private String email;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,48 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.dept;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 部门创建/修改 Request VO")
@Data
public class DeptSaveReqVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@NotBlank(message = "部门名称不能为空")
@Size(max = 30, message = "部门名称长度不能超过 30 个字符")
private String name;
@Schema(description = "父部门 ID", example = "1024")
private Long parentId;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@Schema(description = "联系电话", example = "15601691000")
@Size(max = 11, message = "联系电话长度不能超过11个字符")
private String phone;
@Schema(description = "邮箱", example = "rdms@iocoder.cn")
@Email(message = "邮箱格式不正确")
@Size(max = 50, message = "邮箱长度不能超过 50 个字符")
private String email;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.dept;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "管理后台 - 部门精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptSimpleRespVO {
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String name;
@Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
}

View File

@@ -0,0 +1,22 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.post;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 岗位分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostPageReqVO extends PageParam {
@Schema(description = "岗位编码,模糊匹配", example = "rdms")
private String code;
@Schema(description = "岗位名称,模糊匹配", example = "灿能")
private String name;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;
}

View File

@@ -0,0 +1,45 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.post;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 岗位信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class PostRespVO {
@Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("岗位序号")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@ExcelProperty("岗位名称")
private String name;
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@ExcelProperty("岗位编码")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("岗位排序")
private Integer sort;
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,39 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.post;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 岗位创建/修改 Request VO")
@Data
public class PostSaveReqVO {
@Schema(description = "岗位编号", example = "1024")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@NotBlank(message = "岗位名称不能为空")
@Size(max = 50, message = "岗位名称长度不能超过 50 个字符")
private String name;
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotBlank(message = "岗位编码不能为空")
@Size(max = 64, message = "岗位编码长度不能超过64个字符")
private String code;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
private String remark;
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.system.controller.admin.dept.vo.post;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 岗位信息的精简 Response VO")
@Data
public class PostSimpleRespVO {
@Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("岗位序号")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@ExcelProperty("岗位名称")
private String name;
}

View File

@@ -0,0 +1,4 @@
### 请求 /menu/list 接口 => 成功
GET {{baseUrl}}/system/dict-data/list-all-simple
Authorization: Bearer {{token}}
tenant-id: {{adminTenantId}}

View File

@@ -0,0 +1,113 @@
package com.njcn.rdms.module.system.controller.admin.dict;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.data.DictDataRespVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.dict.DictDataDO;
import com.njcn.rdms.module.system.service.dict.DictDataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 字典数据")
@RestController
@RequestMapping("/system/dict-data")
@Validated
public class DictDataController {
@Resource
private DictDataService dictDataService;
@PostMapping("/create")
@Operation(summary = "新增字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:create')")
public CommonResult<Long> createDictData(@Valid @RequestBody DictDataSaveReqVO createReqVO) {
Long dictDataId = dictDataService.createDictData(createReqVO);
return success(dictDataId);
}
@PutMapping("/update")
@Operation(summary = "修改字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictData(@Valid @RequestBody DictDataSaveReqVO updateReqVO) {
dictDataService.updateDictData(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除字典数据")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictData(@RequestParam("id") Long id) {
dictDataService.deleteDictData(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除字典数据")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictDataList(@RequestParam("ids") List<Long> ids) {
dictDataService.deleteDictDataList(ids);
return success(true);
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地")
// 无需添加权限认证,因为前端全局都需要
public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() {
List<DictDataDO> list = dictDataService.getDictDataList(
CommonStatusEnum.ENABLE.getStatus(), null);
return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得字典类型的分页")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictDataRespVO>> getDictTypePage(@Valid DictDataPageReqVO pageReqVO) {
PageResult<DictDataDO> pageResult = dictDataService.getDictDataPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DictDataRespVO.class));
}
@GetMapping(value = "/get")
@Operation(summary = "/查询字典数据详细")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<DictDataRespVO> getDictData(@RequestParam("id") Long id) {
DictDataDO dictData = dictDataService.getDictData(id);
return success(BeanUtils.toBean(dictData, DictDataRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出字典数据")
@PreAuthorize("@ss.hasPermission('system:dict:export')")
@ApiAccessLog(operateType = EXPORT)
public void export(HttpServletResponse response, @Valid DictDataPageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DictDataDO> list = dictDataService.getDictDataPage(exportReqVO).getList();
// 输出
ExcelUtils.write(response, "字典数据.xls", "数据", DictDataRespVO.class,
BeanUtils.toBean(list, DictDataRespVO.class));
}
}

View File

@@ -0,0 +1,111 @@
package com.njcn.rdms.module.system.controller.admin.dict;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.dict.vo.type.DictTypePageReqVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.type.DictTypeRespVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.dict.DictTypeDO;
import com.njcn.rdms.module.system.service.dict.DictTypeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 字典类型")
@RestController
@RequestMapping("/system/dict-type")
@Validated
public class DictTypeController {
@Resource
private DictTypeService dictTypeService;
@PostMapping("/create")
@Operation(summary = "创建字典类型")
@PreAuthorize("@ss.hasPermission('system:dict:create')")
public CommonResult<Long> createDictType(@Valid @RequestBody DictTypeSaveReqVO createReqVO) {
Long dictTypeId = dictTypeService.createDictType(createReqVO);
return success(dictTypeId);
}
@PutMapping("/update")
@Operation(summary = "修改字典类型")
@PreAuthorize("@ss.hasPermission('system:dict:update')")
public CommonResult<Boolean> updateDictType(@Valid @RequestBody DictTypeSaveReqVO updateReqVO) {
dictTypeService.updateDictType(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除字典类型")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictType(Long id) {
dictTypeService.deleteDictType(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除字典类型")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:dict:delete')")
public CommonResult<Boolean> deleteDictTypeList(@RequestParam("ids") List<Long> ids) {
dictTypeService.deleteDictTypeList(ids);
return success(true);
}
@GetMapping("/page")
@Operation(summary = "获得字典类型的分页列表")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<DictTypeRespVO>> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) {
PageResult<DictTypeDO> pageResult = dictTypeService.getDictTypePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class));
}
@Operation(summary = "/查询字典类型详细")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@GetMapping(value = "/get")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<DictTypeRespVO> getDictType(@RequestParam("id") Long id) {
DictTypeDO dictType = dictTypeService.getDictType(id);
return success(BeanUtils.toBean(dictType, DictTypeRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
// 无需添加权限认证,因为前端全局都需要
public CommonResult<List<DictTypeSimpleRespVO>> getSimpleDictTypeList() {
List<DictTypeDO> list = dictTypeService.getDictTypeList();
return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class));
}
@Operation(summary = "导出数据类型")
@GetMapping("/export-excel")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
@ApiAccessLog(operateType = EXPORT)
public void export(HttpServletResponse response, @Valid DictTypePageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DictTypeDO> list = dictTypeService.getDictTypePage(exportReqVO).getList();
// 导出
ExcelUtils.write(response, "字典类型.xls", "数据", DictTypeRespVO.class,
BeanUtils.toBean(list, DictTypeRespVO.class));
}
}

View File

@@ -0,0 +1,28 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.data;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 字典类型分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictDataPageReqVO extends PageParam {
@Schema(description = "字典标签", example = "灿能")
@Size(max = 100, message = "字典标签长度不能超过100个字符")
private String label;
@Schema(description = "字典类型,模糊匹配", example = "sys_common_sex")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String dictType;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
}

View File

@@ -0,0 +1,55 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.data;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 字典数据信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class DictDataRespVO {
@Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("字典编码")
private Long id;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("字典排序")
private Integer sort;
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@ExcelProperty("字典标签")
private String label;
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
@ExcelProperty("字典键值")
private String value;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
@ExcelProperty("字典类型")
private String dictType;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
@Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default")
private String colorType;
@Schema(description = "css 样式", example = "btn-visible")
private String cssClass;
@Schema(description = "备注", example = "我是一个角色")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,51 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.data;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 字典数据创建/修改 Request VO")
@Data
public class DictDataSaveReqVO {
@Schema(description = "字典数据编号", example = "1024")
private Long id;
@Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@NotBlank(message = "字典标签不能为空")
@Size(max = 100, message = "字典标签长度不能超过100个字符")
private String label;
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
@NotBlank(message = "字典键值不能为空")
@Size(max = 100, message = "字典键值长度不能超过100个字符")
private String value;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
@NotBlank(message = "字典类型不能为空")
@Size(max = 100, message = "字典类型长度不能超过100个字符")
private String dictType;
@Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
@Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default")
private String colorType;
@Schema(description = "css 样式", example = "btn-visible")
private String cssClass;
@Schema(description = "备注", example = "我是一个角色")
private String remark;
}

View File

@@ -0,0 +1,25 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.data;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 数据字典精简 Response VO")
@Data
public class DictDataSimpleRespVO {
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "gender")
private String dictType;
@Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private String value;
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
private String label;
@Schema(description = "颜色类型default、primary、success、info、warning、danger", example = "default")
private String colorType;
@Schema(description = "css 样式", example = "btn-visible")
private String cssClass;
}

View File

@@ -0,0 +1,33 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.type;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 字典类型分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class DictTypePageReqVO extends PageParam {
@Schema(description = "字典类型名称,模糊匹配", example = "灿能")
private String name;
@Schema(description = "字典类型,模糊匹配", example = "sys_common_sex")
@Size(max = 100, message = "字典类型类型长度不能超过100个字符")
private String type;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "创建时间")
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,41 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.type;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 字典类型信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class DictTypeRespVO {
@Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("字典主键")
private Long id;
@Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别")
@ExcelProperty("字典名称")
private String name;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
@ExcelProperty("字典类型")
private String type;
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,34 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.type;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Schema(description = "管理后台 - 字典类型创建/修改 Request VO")
@Data
public class DictTypeSaveReqVO {
@Schema(description = "字典类型编号", example = "1024")
private Long id;
@Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别")
@NotBlank(message = "字典名称不能为空")
@Size(max = 100, message = "字典类型名称长度不能超过100个字符")
private String name;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
@NotNull(message = "字典类型不能为空")
@Size(max = 100, message = "字典类型类型长度不能超过 100 个字符")
private String type;
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
private String remark;
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.system.controller.admin.dict.vo.type;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 字典类型精简信息 Response VO")
@Data
public class DictTypeSimpleRespVO {
@Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "字典类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String name;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
private String type;
}

View File

@@ -0,0 +1,45 @@
### 请求 /infra/file-config/create 接口 => 成功
POST {{baseUrl}}/infra/file-config/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"name": "S3 - 七牛云",
"remark": "",
"storage": 20,
"config": {
"accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8",
"accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP",
"bucket": "ruoyi-vue-pro",
"endpoint": "s3-cn-south-1.qiniucs.com",
"domain": "http://test.rdms.iocoder.cn",
"region": "oss-cn-beijing"
}
}
### 请求 /infra/file-config/update 接口 => 成功
PUT {{baseUrl}}/infra/file-config/update
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"id": 2,
"name": "S3 - 七牛云",
"remark": "",
"config": {
"accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8",
"accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP",
"bucket": "ruoyi-vue-pro",
"endpoint": "s3-cn-south-1.qiniucs.com",
"domain": "http://test.rdms.iocoder.cn",
"region": "oss-cn-beijing"
}
}
### 请求 /infra/file-config/test 接口 => 成功
GET {{baseUrl}}/infra/file-config/test?id=2
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}

View File

@@ -0,0 +1,98 @@
package com.njcn.rdms.module.system.controller.admin.file;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.file.vo.config.FileConfigPageReqVO;
import com.njcn.rdms.module.system.controller.admin.file.vo.config.FileConfigRespVO;
import com.njcn.rdms.module.system.controller.admin.file.vo.config.FileConfigSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.file.FileConfigDO;
import com.njcn.rdms.module.system.service.file.FileConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 文件配置")
@RestController
@RequestMapping("/infra/file-config")
@Validated
public class FileConfigController {
@Resource
private FileConfigService fileConfigService;
@PostMapping("/create")
@Operation(summary = "创建文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:create')")
public CommonResult<Long> createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) {
return success(fileConfigService.createFileConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
public CommonResult<Boolean> updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) {
fileConfigService.updateFileConfig(updateReqVO);
return success(true);
}
@PutMapping("/update-master")
@Operation(summary = "更新文件配置为 Master")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
public CommonResult<Boolean> updateFileConfigMaster(@RequestParam("id") Long id) {
fileConfigService.updateFileConfigMaster(id);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除文件配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
public CommonResult<Boolean> deleteFileConfig(@RequestParam("id") Long id) {
fileConfigService.deleteFileConfig(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
public CommonResult<Boolean> deleteFileConfigList(@RequestParam("ids") List<Long> ids) {
fileConfigService.deleteFileConfigList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得文件配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
public CommonResult<FileConfigRespVO> getFileConfig(@RequestParam("id") Long id) {
FileConfigDO config = fileConfigService.getFileConfig(id);
return success(BeanUtils.toBean(config, FileConfigRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得文件配置分页")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
public CommonResult<PageResult<FileConfigRespVO>> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) {
PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(pageVO);
return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class));
}
@GetMapping("/test")
@Operation(summary = "测试文件配置是否正确")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
public CommonResult<String> testFileConfig(@RequestParam("id") Long id) throws Exception {
String url = fileConfigService.testFileConfig(id);
return success(url);
}
}

View File

@@ -0,0 +1,136 @@
package com.njcn.rdms.module.system.controller.admin.file;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.file.vo.file.*;
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
import com.njcn.rdms.module.system.service.file.FileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.charset.StandardCharsets;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.module.system.framework.file.core.utils.FileTypeUtils.writeAttachment;
@Tag(name = "管理后台 - 文件存储")
@RestController
@RequestMapping("/infra/file")
@Validated
@Slf4j
public class FileController {
@Resource
private FileService fileService;
@PostMapping("/upload")
@Operation(summary = "上传文件", description = "模式一:后端上传文件")
@Parameter(name = "file", description = "文件附件", required = true,
schema = @Schema(type = "string", format = "binary"))
public CommonResult<String> uploadFile(@Valid FileUploadReqVO uploadReqVO) throws Exception {
MultipartFile file = uploadReqVO.getFile();
byte[] content = IoUtil.readBytes(file.getInputStream());
return success(fileService.createFile(content, file.getOriginalFilename(),
uploadReqVO.getDirectory(), file.getContentType()));
}
@GetMapping("/presigned-url")
@Operation(summary = "获取文件预签名地址(上传)", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器")
@Parameters({
@Parameter(name = "name", description = "文件名称", required = true),
@Parameter(name = "directory", description = "文件目录")
})
public CommonResult<FilePresignedUrlRespVO> getFilePresignedUrl(
@RequestParam("name") String name,
@RequestParam(value = "directory", required = false) String directory) {
return success(fileService.presignPutUrl(name, directory));
}
@PostMapping("/create")
@Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件")
public CommonResult<Long> createFile(@Valid @RequestBody FileCreateReqVO createReqVO) {
return success(fileService.createFile(createReqVO));
}
@GetMapping("/get")
@Operation(summary = "获得文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:query')")
public CommonResult<FileRespVO> getFile(@RequestParam("id") Long id) {
return success(BeanUtils.toBean(fileService.getFile(id), FileRespVO.class));
}
@DeleteMapping("/delete")
@Operation(summary = "删除文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) throws Exception {
fileService.deleteFile(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
public CommonResult<Boolean> deleteFileList(@RequestParam("ids") List<Long> ids) throws Exception {
fileService.deleteFileList(ids);
return success(true);
}
@GetMapping("/{configId}/get/**")
@PermitAll
@Operation(summary = "下载文件")
@Parameter(name = "configId", description = "配置编号", required = true)
public void getFileContent(HttpServletRequest request,
HttpServletResponse response,
@PathVariable("configId") Long configId) throws Exception {
// 获取请求的路径
String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false);
if (StrUtil.isEmpty(path)) {
throw new IllegalArgumentException("结尾的 path 路径必须传递");
}
// 解码,解决中文路径的问题
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
path = URLUtil.decode(path, StandardCharsets.UTF_8, false);
// 读取内容
byte[] content = fileService.getFileContent(configId, path);
if (content == null) {
log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
writeAttachment(response, path, content);
}
@GetMapping("/page")
@Operation(summary = "获得文件分页")
@PreAuthorize("@ss.hasPermission('infra:file:query')")
public CommonResult<PageResult<FileRespVO>> getFilePage(@Valid FilePageReqVO pageVO) {
PageResult<FileDO> pageResult = fileService.getFilePage(pageVO);
return success(BeanUtils.toBean(pageResult, FileRespVO.class));
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.config;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 文件配置分页 Request VO")
@Data
public class FileConfigPageReqVO extends PageParam {
@Schema(description = "配置名", example = "S3 - 阿里云")
private String name;
@Schema(description = "存储器", example = "1")
private Integer storage;
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,34 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.config;
import com.njcn.rdms.module.system.framework.file.core.client.FileClientConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 文件配置 Response VO")
@Data
public class FileConfigRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云")
private String name;
@Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer storage;
@Schema(description = "是否为主配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean master;
@Schema(description = "存储配置", requiredMode = Schema.RequiredMode.REQUIRED)
private FileClientConfig config;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,31 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.config;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.Map;
@Schema(description = "管理后台 - 文件配置创建/修改 Request VO")
@Data
public class FileConfigSaveReqVO {
@Schema(description = "编号", example = "1")
private Long id;
@Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云")
@NotNull(message = "配置名不能为空")
private String name;
@Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "存储器不能为空")
private Integer storage;
@Schema(description = "存储配置,配置是动态参数,所以使用 Map 接收", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "存储配置不能为空")
private Map<String, Object> config;
@Schema(description = "备注", example = "我是备注")
private String remark;
}

View File

@@ -0,0 +1,33 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 文件创建 Request VO")
@Data
public class FileCreateReqVO {
@NotNull(message = "文件配置编号不能为空")
@Schema(description = "文件配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
private Long configId;
@NotNull(message = "文件路径不能为空")
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms.jpg")
private String path;
@NotNull(message = "原文件名不能为空")
@Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms.jpg")
private String name;
@NotNull(message = "文件 URL不能为空")
@Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/rdms.jpg")
private String url;
@Schema(description = "文件 MIME 类型", example = "application/octet-stream")
private String type;
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
private Long size;
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.file;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 文件分页 Request VO")
@Data
public class FilePageReqVO extends PageParam {
@Schema(description = "文件路径,模糊匹配", example = "rdms")
private String path;
@Schema(description = "文件类型,模糊匹配", example = "jpg")
private String type;
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,38 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "管理后台 - 文件预签名地址 Response VO")
@Data
public class FilePresignedUrlRespVO {
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
private Long configId;
@Schema(description = "文件上传 URL", requiredMode = Schema.RequiredMode.REQUIRED,
example = "https://s3.cn-south-1.qiniucs.com/ruoyi-vue-pro/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS%2F20240217%2Fcn-south-1%2Fs3%2Faws4_request&X-Amz-Date=20240217T123222Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=a29f33770ab79bf523ccd4034d0752ac545f3c2a3b17baa1eb4e280cfdccfda5")
private String uploadUrl;
/**
* 为什么要返回 url 字段?
*
* 前端上传完文件后,需要使用该 URL 进行访问
*/
@Schema(description = "文件访问 URL", requiredMode = Schema.RequiredMode.REQUIRED,
example = "https://test.rdms.iocoder.cn/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png")
private String url;
/**
* 为什么要返回 path 字段?
*
* 前端上传完文件后,需要调用 createFile 记录下 path 路径
*/
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx.png")
private String path;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.file;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 文件 Response VO,不返回 content 字段,太大")
@Data
public class FileRespVO {
@Schema(description = "文件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
private Long configId;
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms.jpg")
private String path;
@Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms.jpg")
private String name;
@Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/rdms.jpg")
private String url;
@Schema(description = "文件MIME类型", example = "application/octet-stream")
private String type;
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
private Long size;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.system.controller.admin.file.vo.file;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Schema(description = "管理后台 - 上传文件 Request VO")
@Data
public class FileUploadReqVO {
@Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "文件附件不能为空")
private MultipartFile file;
@Schema(description = "文件目录", example = "XXX/YYY")
private String directory;
@AssertTrue(message = "文件目录不正确")
@JsonIgnore
public boolean isDirectoryValid() {
return isDirectoryValid(directory);
}
public static boolean isDirectoryValid(String directory) {
// 1. 不能包含 .. 防止目录穿越
// 2. 不能以 / 或 \ 开头,防止上传到根目录
return !StrUtil.contains(directory, "..")
&& !StrUtil.startWithAny(directory, "/", "\\");
}
}

View File

@@ -0,0 +1,5 @@
### 获得地区树
GET {{baseUrl}}/system/area/tree
Authorization: Bearer {{token}}
tenant-id: {{adminTenantId}}

View File

@@ -0,0 +1,50 @@
package com.njcn.rdms.module.system.controller.admin.ip;
import cn.hutool.core.lang.Assert;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.ip.core.Area;
import com.njcn.rdms.framework.ip.core.utils.AreaUtils;
import com.njcn.rdms.framework.ip.core.utils.IPUtils;
import com.njcn.rdms.module.system.controller.admin.ip.vo.AreaNodeRespVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 地区")
@RestController
@RequestMapping("/system/area")
@Validated
public class AreaController {
@GetMapping("/tree")
@Operation(summary = "获得地区树")
public CommonResult<List<AreaNodeRespVO>> getAreaTree() {
Area area = AreaUtils.getArea(Area.ID_CHINA);
Assert.notNull(area, "获取不到中国");
return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class));
}
@GetMapping("/get-by-ip")
@Operation(summary = "获得 IP 对应的地区名")
@Parameter(name = "ip", description = "IP", required = true)
public CommonResult<String> getAreaByIp(@RequestParam("ip") String ip) {
// 获得城市
Area area = IPUtils.getArea(ip);
if (area == null) {
return success("未知");
}
// 格式化返回
return success(AreaUtils.format(area.getId()));
}
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.system.controller.admin.ip.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 地区节点 Response VO")
@Data
public class AreaNodeRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000")
private Integer id;
@Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京")
private String name;
/**
* 子节点
*/
private List<AreaNodeRespVO> children;
}

View File

@@ -0,0 +1,71 @@
package com.njcn.rdms.module.system.controller.admin.logger;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.logger.ApiAccessLogDO;
import com.njcn.rdms.module.system.service.logger.ApiAccessLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - API 访问日志")
@RestController
@RequestMapping("/infra/api-access-log")
@Validated
public class ApiAccessLogController {
@Resource
private ApiAccessLogService apiAccessLogService;
@GetMapping("/get")
@Operation(summary = "获得 API 访问日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
public CommonResult<ApiAccessLogRespVO> getApiAccessLog(@RequestParam("id") Long id) {
ApiAccessLogDO apiAccessLog = apiAccessLogService.getApiAccessLog(id);
return success(BeanUtils.toBean(apiAccessLog, ApiAccessLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得API 访问日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
public CommonResult<PageResult<ApiAccessLogRespVO>> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) {
PageResult<ApiAccessLogDO> pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出API 访问日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ApiAccessLogDO> list = apiAccessLogService.getApiAccessLogPage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "API 访问日志.xls", "数据", ApiAccessLogRespVO.class,
BeanUtils.toBean(list, ApiAccessLogRespVO.class));
}
}

View File

@@ -0,0 +1,83 @@
package com.njcn.rdms.module.system.controller.admin.logger;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.logger.ApiErrorLogDO;
import com.njcn.rdms.module.system.service.logger.ApiErrorLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - API 错误日志")
@RestController
@RequestMapping("/infra/api-error-log")
@Validated
public class ApiErrorLogController {
@Resource
private ApiErrorLogService apiErrorLogService;
@PutMapping("/update-status")
@Operation(summary = "更新 API 错误日志的状态")
@Parameters({
@Parameter(name = "id", description = "编号", required = true, example = "1024"),
@Parameter(name = "processStatus", description = "处理状态", required = true, example = "1")
})
@PreAuthorize("@ss.hasPermission('infra:api-error-log:update-status')")
public CommonResult<Boolean> updateApiErrorLogProcess(@RequestParam("id") Long id,
@RequestParam("processStatus") Integer processStatus) {
apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId());
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得 API 错误日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
public CommonResult<ApiErrorLogRespVO> getApiErrorLog(@RequestParam("id") Long id) {
ApiErrorLogDO apiErrorLog = apiErrorLogService.getApiErrorLog(id);
return success(BeanUtils.toBean(apiErrorLog, ApiErrorLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得 API 错误日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
public CommonResult<PageResult<ApiErrorLogRespVO>> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) {
PageResult<ApiErrorLogDO> pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出 API 错误日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ApiErrorLogDO> list = apiErrorLogService.getApiErrorLogPage(exportReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "API 错误日志.xls", "数据", ApiErrorLogRespVO.class,
BeanUtils.toBean(list, ApiErrorLogRespVO.class));
}
}

View File

@@ -0,0 +1,67 @@
package com.njcn.rdms.module.system.controller.admin.logger;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.logger.vo.loginlog.LoginLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.logger.LoginLogDO;
import com.njcn.rdms.module.system.service.logger.LoginLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 登录日志")
@RestController
@RequestMapping("/system/login-log")
@Validated
public class LoginLogController {
@Resource
private LoginLogService loginLogService;
@GetMapping("/get")
@Operation(summary = "获得登录日志")
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
public CommonResult<LoginLogRespVO> getLoginLog(Long id) {
LoginLogDO loginLog = loginLogService.getLoginLog(id);
return success(BeanUtils.toBean(loginLog, LoginLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得登录日志分页列表")
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
public CommonResult<PageResult<LoginLogRespVO>> getLoginLogPage(@Valid LoginLogPageReqVO pageReqVO) {
PageResult<LoginLogDO> pageResult = loginLogService.getLoginLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, LoginLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出登录日志 Excel")
@PreAuthorize("@ss.hasPermission('system:login-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportLoginLog(HttpServletResponse response, @Valid LoginLogPageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<LoginLogDO> list = loginLogService.getLoginLogPage(exportReqVO).getList();
// 输出
ExcelUtils.write(response, "登录日志.xls", "数据列表", LoginLogRespVO.class,
BeanUtils.toBean(list, LoginLogRespVO.class));
}
}

View File

@@ -0,0 +1,4 @@
### 请求 /system/operate-log/page 接口 => 成功
GET {{baseUrl}}/system/operate-log/page
Authorization: Bearer {{token}}
tenant-id: {{adminTenantId}}

View File

@@ -0,0 +1,73 @@
package com.njcn.rdms.module.system.controller.admin.logger;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.framework.translate.core.TranslateUtils;
import com.njcn.rdms.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.logger.OperateLogDO;
import com.njcn.rdms.module.system.service.logger.OperateLogService;
import com.fhs.core.trans.anno.TransMethodResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 操作日志")
@RestController
@RequestMapping("/system/operate-log")
@Validated
public class OperateLogController {
@Resource
private OperateLogService operateLogService;
@GetMapping("/get")
@Operation(summary = "查看操作日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
public CommonResult<OperateLogRespVO> getOperateLog(@RequestParam("id") Long id) {
OperateLogDO operateLog = operateLogService.getOperateLog(id);
return success(BeanUtils.toBean(operateLog, OperateLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "查看操作日志分页列表")
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
@TransMethodResult
public CommonResult<PageResult<OperateLogRespVO>> pageOperateLog(@Valid OperateLogPageReqVO pageReqVO) {
PageResult<OperateLogDO> pageResult = operateLogService.getOperateLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, OperateLogRespVO.class));
}
@Operation(summary = "导出操作日志")
@GetMapping("/export-excel")
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
@TransMethodResult
@ApiAccessLog(operateType = EXPORT)
public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<OperateLogDO> list = operateLogService.getOperateLogPage(exportReqVO).getList();
ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogRespVO.class,
TranslateUtils.translate(BeanUtils.toBean(list, OperateLogRespVO.class)));
}
}

View File

@@ -0,0 +1,38 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.apiaccesslog;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - API 访问日志分页 Request VO")
@Data
public class ApiAccessLogPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "666")
private Long userId;
@Schema(description = "用户类型", example = "2")
private Integer userType;
@Schema(description = "应用名", example = "dashboard")
private String applicationName;
@Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy")
private String requestUrl;
@Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] beginTime;
@Schema(description = "执行时长,大于等于,单位:毫秒", example = "100")
private Integer duration;
@Schema(description = "结果码", example = "0")
private Integer resultCode;
}

View File

@@ -0,0 +1,99 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.apiaccesslog;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - API 访问日志 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ApiAccessLogRespVO {
@Schema(description = "日志主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("日志主键")
private Long id;
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002")
@ExcelProperty("链路追踪编号")
private String traceId;
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
@ExcelProperty("用户编号")
private Long userId;
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "用户类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_TYPE)
private Integer userType;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard")
@ExcelProperty("应用名")
private String applicationName;
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
@ExcelProperty("请求方法名")
private String requestMethod;
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
@ExcelProperty("请求地址")
private String requestUrl;
@Schema(description = "请求参数")
@ExcelProperty("请求参数")
private String requestParams;
@Schema(description = "响应结果")
@ExcelProperty("响应结果")
private String responseBody;
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
@ExcelProperty("用户 IP")
private String userIp;
@Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
@ExcelProperty("浏览器 UA")
private String userAgent;
@Schema(description = "操作模块", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品模块")
@ExcelProperty("操作模块")
private String operateModule;
@Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建商品")
@ExcelProperty("操作名")
private String operateName;
@Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "操作分类", converter = DictConvert.class)
@DictFormat(DictTypeConstants.OPERATE_TYPE)
private Integer operateType;
@Schema(description = "开始请求时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("开始请求时间")
private LocalDateTime beginTime;
@Schema(description = "结束请求时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("结束请求时间")
private LocalDateTime endTime;
@Schema(description = "执行时长", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@ExcelProperty("执行时长")
private Integer duration;
@Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@ExcelProperty("结果码")
private Integer resultCode;
@Schema(description = "结果提示", example = "灿能源码,牛逼!")
@ExcelProperty("结果提示")
private String resultMsg;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.apierrorlog;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - API 错误日志分页 Request VO")
@Data
public class ApiErrorLogPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "666")
private Long userId;
@Schema(description = "用户类型", example = "1")
private Integer userType;
@Schema(description = "应用名", example = "dashboard")
private String applicationName;
@Schema(description = "请求地址", example = "/xx/yy")
private String requestUrl;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "异常发生时间")
private LocalDateTime[] exceptionTime;
@Schema(description = "处理状态", example = "0")
private Integer processStatus;
}

View File

@@ -0,0 +1,112 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.apierrorlog;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - API 错误日志 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ApiErrorLogRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("编号")
private Long id;
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002")
@ExcelProperty("链路追踪编号")
private String traceId;
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
@ExcelProperty("用户编号")
private Long userId;
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "用户类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_TYPE)
private Integer userType;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard")
@ExcelProperty("应用名")
private String applicationName;
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
@ExcelProperty("请求方法名")
private String requestMethod;
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xx/yy")
@ExcelProperty("请求地址")
private String requestUrl;
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("请求参数")
private String requestParams;
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
@ExcelProperty("用户 IP")
private String userIp;
@Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
@ExcelProperty("浏览器 UA")
private String userAgent;
@Schema(description = "异常发生时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常发生时间")
private LocalDateTime exceptionTime;
@Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常名")
private String exceptionName;
@Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常导致的消息")
private String exceptionMessage;
@Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常导致的根消息")
private String exceptionRootCauseMessage;
@Schema(description = "异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常的栈轨迹")
private String exceptionStackTrace;
@Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常发生的类全名")
private String exceptionClassName;
@Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常发生的类文件")
private String exceptionFileName;
@Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常发生的方法名")
private String exceptionMethodName;
@Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("异常发生的方法所在行")
private Integer exceptionLineNumber;
@Schema(description = "处理状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@ExcelProperty(value = "处理状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.API_ERROR_LOG_PROCESS_STATUS)
private Integer processStatus;
@Schema(description = "处理时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("处理时间")
private LocalDateTime processTime;
@Schema(description = "处理用户编号", example = "233")
@ExcelProperty("处理用户编号")
private Integer processUserId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,31 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.loginlog;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 登录日志分页列表 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class LoginLogPageReqVO extends PageParam {
@Schema(description = "用户 IP模拟匹配", example = "127.0.0.1")
private String userIp;
@Schema(description = "用户账号,模拟匹配", example = "灿能")
private String username;
@Schema(description = "操作状态", example = "true")
private Boolean status;
@Schema(description = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,57 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.loginlog;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.framework.excel.core.convert.DictConvert;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 登录日志 Response VO")
@Data
@ExcelIgnoreUnannotated
public class LoginLogRespVO {
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("日志主键")
private Long id;
@Schema(description = "日志类型,参见 LoginLogTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "日志类型", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOGIN_TYPE)
private Integer logType;
@Schema(description = "用户编号", example = "666")
private Long userId;
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer userType;
@Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab")
private String traceId;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@ExcelProperty("用户账号")
private String username;
@Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "登录结果", converter = DictConvert.class)
@DictFormat(DictTypeConstants.LOGIN_RESULT)
private Integer result;
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
@ExcelProperty("登录 IP")
private String userIp;
@Schema(description = "浏览器 UserAgent", example = "Mozilla/5.0")
@ExcelProperty("浏览器 UA")
private String userAgent;
@Schema(description = "登录时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("登录时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.operatelog;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 操作日志分页列表 Request VO")
@Data
public class OperateLogPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "灿能")
private Long userId;
@Schema(description = "操作模块业务编号", example = "1")
private Long bizId;
@Schema(description = "操作模块,模拟匹配", example = "订单")
private String type;
@Schema(description = "操作名,模拟匹配", example = "创建订单")
private String subType;
@Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息")
private String action;
@Schema(description = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,75 @@
package com.njcn.rdms.module.system.controller.admin.logger.vo.operatelog;
import com.njcn.rdms.framework.excel.core.annotations.DictFormat;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.njcn.rdms.module.system.enums.DictTypeConstants;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.VO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 操作日志 Response VO")
@Data
@ExcelIgnoreUnannotated
public class OperateLogRespVO implements VO {
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@ExcelProperty("日志编号")
private Long id;
@Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
private String traceId;
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@Trans(type = TransType.SIMPLE, target = AdminUserDO.class, fields = "nickname", ref = "userName")
private Long userId;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@ExcelProperty("操作人")
private String userName;
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1", implementation = Integer.class)
@ExcelProperty("用户类型")
@DictFormat(DictTypeConstants.USER_TYPE)
private Integer userType;
@Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单")
@ExcelProperty("操作模块类型")
private String type;
@Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单")
@ExcelProperty("操作名")
private String subType;
@Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("操作模块业务编号")
private Long bizId;
@Schema(description = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从灿能改成源码。")
private String action;
@Schema(description = "拓展字段", example = "{'orderId': 1}")
private String extra;
@Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET")
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
@Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy")
private String requestUrl;
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
private String userIp;
@Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0")
private String userAgent;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,90 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountRespVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailAccountDO;
import com.njcn.rdms.module.system.service.mail.MailAccountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮箱账号")
@RestController
@RequestMapping("/system/mail-account")
public class MailAccountController {
@Resource
private MailAccountService mailAccountService;
@PostMapping("/create")
@Operation(summary = "创建邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:create')")
public CommonResult<Long> createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) {
return success(mailAccountService.createMailAccount(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:update')")
public CommonResult<Boolean> updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) {
mailAccountService.updateMailAccount(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除邮箱账号")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
public CommonResult<Boolean> deleteMailAccount(@RequestParam Long id) {
mailAccountService.deleteMailAccount(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除邮箱账号")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
public CommonResult<Boolean> deleteMailAccountList(@RequestParam("ids") List<Long> ids) {
mailAccountService.deleteMailAccountList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得邮箱账号")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-account:query')")
public CommonResult<MailAccountRespVO> getMailAccount(@RequestParam("id") Long id) {
MailAccountDO account = mailAccountService.getMailAccount(id);
return success(BeanUtils.toBean(account, MailAccountRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得邮箱账号分页")
@PreAuthorize("@ss.hasPermission('system:mail-account:query')")
public CommonResult<PageResult<MailAccountRespVO>> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) {
PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(summary = "获得邮箱账号精简列表")
public CommonResult<List<MailAccountSimpleRespVO>> getSimpleMailAccountList() {
List<MailAccountDO> list = mailAccountService.getMailAccountList();
return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class));
}
}

View File

@@ -0,0 +1,49 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.log.MailLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailLogDO;
import com.njcn.rdms.module.system.service.mail.MailLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮件日志")
@RestController
@RequestMapping("/system/mail-log")
public class MailLogController {
@Resource
private MailLogService mailLogService;
@GetMapping("/page")
@Operation(summary = "获得邮箱日志分页")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<PageResult<MailLogRespVO>> getMailLogPage(@Valid MailLogPageReqVO pageVO) {
PageResult<MailLogDO> pageResult = mailLogService.getMailLogPage(pageVO);
return success(BeanUtils.toBean(pageResult, MailLogRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得邮箱日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<MailLogRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailLogDO log = mailLogService.getMailLog(id);
return success(BeanUtils.toBean(log, MailLogRespVO.class));
}
}

View File

@@ -0,0 +1,14 @@
### 请求 /system/mail-template/send-mail 接口 => 成功
POST {{baseUrl}}/system/mail-template/send-mail
Authorization: Bearer {{token}}
Content-Type: application/json
tenant-id: {{adminTenantId}}
{
"templateCode": "test_01",
"mail": "7685413@qq.com",
"templateParams": {
"key01": "value01",
"key02": "value02"
}
}

View File

@@ -0,0 +1,99 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.template.*;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailTemplateDO;
import com.njcn.rdms.module.system.service.mail.MailSendService;
import com.njcn.rdms.module.system.service.mail.MailTemplateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 邮件模版")
@RestController
@RequestMapping("/system/mail-template")
public class MailTemplateController {
@Resource
private MailTemplateService mailTempleService;
@Resource
private MailSendService mailSendService;
@PostMapping("/create")
@Operation(summary = "创建邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:create')")
public CommonResult<Long> createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){
return success(mailTempleService.createMailTemplate(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:update')")
public CommonResult<Boolean> updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){
mailTempleService.updateMailTemplate(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
public CommonResult<Boolean> deleteMailTemplate(@RequestParam("id") Long id) {
mailTempleService.deleteMailTemplate(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除邮件模版")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
public CommonResult<Boolean> deleteMailTemplateList(@RequestParam("ids") List<Long> ids) {
mailTempleService.deleteMailTemplateList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:query')")
public CommonResult<MailTemplateRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailTemplateDO template = mailTempleService.getMailTemplate(id);
return success(BeanUtils.toBean(template, MailTemplateRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得邮件模版分页")
@PreAuthorize("@ss.hasPermission('system:mail-template:query')")
public CommonResult<PageResult<MailTemplateRespVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) {
PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(summary = "获得邮件模版精简列表")
public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleTemplateList() {
List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class));
}
@PostMapping("/send-mail")
@Operation(summary = "发送邮件")
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
return success(mailSendService.sendSingleMailToAdmin(getLoginUserId(),
sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
}

View File

@@ -0,0 +1,21 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 邮箱账号分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MailAccountPageReqVO extends PageParam {
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
private String mail;
@Schema(description = "用户名" , requiredMode = Schema.RequiredMode.REQUIRED , example = "rdms")
private String username;
}

View File

@@ -0,0 +1,39 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 邮箱账号 Response VO")
@Data
public class MailAccountRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
private String mail;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
private String password;
@Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
private String host;
@Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
private Integer port;
@Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean sslEnable;
@Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean starttlsEnable;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 邮箱账号创建/修改 Request VO")
@Data
public class MailAccountSaveReqVO {
@Schema(description = "编号", example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
@NotNull(message = "邮箱不能为空")
@Email(message = "必须是 Email 格式")
private String mail;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotNull(message = "用户名不能为空")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotNull(message = "密码必填")
private String password;
@Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
@NotNull(message = "SMTP 服务器域名不能为空")
private String host;
@Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
@NotNull(message = "SMTP 服务器端口不能为空")
private Integer port;
@Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否开启 ssl 必填")
private Boolean sslEnable;
@Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否开启 starttls 必填")
private Boolean starttlsEnable;
}

View File

@@ -0,0 +1,16 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 邮箱账号的精简 Response VO")
@Data
public class MailAccountSimpleRespVO {
@Schema(description = "邮箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "768541388@qq.com")
private String mail;
}

Some files were not shown because too many files have changed in this diff Show More