【更新】更新并升级v3.5.1版本

pull/270/head
xuyuxiang 2025-06-15 23:22:02 +08:00
parent 3a5ecac001
commit b7f164082b
48 changed files with 911 additions and 210 deletions

View File

@ -238,7 +238,9 @@ snowy
QQ技术群732230670已满、685395081
微信技术群因群达到200人以上需加微信拉群
微信技术群:
因群达到200人以上需加微信拉群禁止群内艾特群主及管理员私信提问技术问题无时间精力回答免开尊口请群内互动互助才是建群的意义否则我认为你没有加群的必要
<table>
<tr>

View File

@ -0,0 +1,41 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.common.enums;
import lombok.Getter;
import vip.xiaonuo.common.exception.CommonException;
/**
*
*
* @author xuyuxiang
* @date 2022/7/13 17:48
**/
@Getter
public enum CommonGenderEnum {
/** 未知 */
UNKNOWN("未知"),
/** 男 */
MAN("男"),
/** 女 */
WOMAN("女");
private final String value;
CommonGenderEnum(String value) {
this.value = value.toLowerCase();
}
}

View File

@ -191,7 +191,7 @@ public class CommonDataChangeEventCenter {
* @author xuyuxiang
* @date 2023/3/3 10:22
**/
public static void doDeleteWithDataId(String dataType, List<String> dataIdList) {
public static void doDeleteWithDataIdList(String dataType, List<String> dataIdList) {
for (CommonDataChangeListener listener : listenerList) {
listener.doDeleteWithDataIdList(dataType, dataIdList);
}

View File

@ -19,4 +19,12 @@ package vip.xiaonuo.dev.api;
* @date 2022/9/2 15:58
*/
public interface DevDictApi {
/**
* label
*
* @author yubaoshan
* @date 2025/6/6 13:04
*/
String getDictLabel(String typeCode, String value);
}

View File

@ -26,10 +26,7 @@ import vip.xiaonuo.auth.core.annotation.SaClientCheckLogin;
import vip.xiaonuo.auth.core.enums.SaClientTypeEnum;
import vip.xiaonuo.auth.core.pojo.SaBaseClientLoginUser;
import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthRegisterParam;
import vip.xiaonuo.auth.modular.login.param.*;
import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.common.pojo.CommonResult;
@ -65,25 +62,38 @@ public class AuthClientController {
}
/**
* C
* C
*
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 2)
@Operation(summary = "C端获取手机验证码")
@Operation(summary = "C端获取手机登录验证码")
@GetMapping("/auth/c/getPhoneValidCode")
public CommonResult<String> getPhoneValidCode(@Valid AuthGetPhoneValidCodeParam authGetPhoneValidCodeParam) {
return CommonResult.data(authService.getPhoneValidCode(authGetPhoneValidCodeParam, SaClientTypeEnum.C.getValue()));
}
/**
* C
*
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 3)
@Operation(summary = "C端获取邮箱登录验证码")
@GetMapping("/auth/c/getEmailValidCode")
public CommonResult<String> getEmailValidCode(@Valid AuthGetEmailValidCodeParam authGetEmailValidCodeParam) {
return CommonResult.data(authService.getEmailValidCode(authGetEmailValidCodeParam, SaClientTypeEnum.C.getValue()));
}
/**
* C
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 3)
@ApiOperationSupport(order = 4)
@Operation(summary = "C端账号密码登录")
@PostMapping("/auth/c/doLogin")
public CommonResult<String> doLogin(@RequestBody @Valid AuthAccountPasswordLoginParam authAccountPasswordLoginParam) {
@ -96,20 +106,33 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 4)
@ApiOperationSupport(order = 5)
@Operation(summary = "C端手机验证码登录")
@PostMapping("/auth/c/doLoginByPhone")
public CommonResult<String> doLoginByPhone(@RequestBody @Valid AuthPhoneValidCodeLoginParam authPhoneValidCodeLoginParam) {
return CommonResult.data(authService.doLoginByPhone(authPhoneValidCodeLoginParam, SaClientTypeEnum.C.getValue()));
}
/**
* C
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 6)
@Operation(summary = "C端邮箱验证码登录")
@PostMapping("/auth/c/doLoginByEmail")
public CommonResult<String> doLoginByEmail(@RequestBody @Valid AuthEmailValidCodeLoginParam authEmailValidCodeLoginParam) {
return CommonResult.data(authService.doLoginByEmail(authEmailValidCodeLoginParam, SaClientTypeEnum.C.getValue()));
}
/**
* C退
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 5)
@ApiOperationSupport(order = 7)
@Operation(summary = "C端退出")
@SaClientCheckLogin
@GetMapping("/auth/c/doLogout")
@ -124,7 +147,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 6)
@ApiOperationSupport(order = 8)
@Operation(summary = "C端获取用户信息")
@SaClientCheckLogin
@GetMapping("/auth/c/getLoginUser")
@ -138,7 +161,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 7)
@ApiOperationSupport(order = 9)
@Operation(summary = "C端注册")
@PostMapping("/auth/c/register")
public CommonResult<String> register(@RequestBody @Valid AuthRegisterParam authRegisterParam) {

View File

@ -242,7 +242,7 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
this.removeByIds(toDeleteOrgIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.ORG.getValue(), toDeleteOrgIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(BizDataTypeEnum.ORG.getValue(), toDeleteOrgIdList);
}
}

View File

@ -190,7 +190,7 @@ public class BizPositionServiceImpl extends ServiceImpl<BizPositionMapper, BizPo
this.removeByIds(positionIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.POSITION.getValue(), positionIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(BizDataTypeEnum.POSITION.getValue(), positionIdList);
}
}

View File

@ -310,7 +310,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
bizUserExtService.remove(new LambdaQueryWrapper<BizUserExt>().in(BizUserExt::getUserId, bizUserIdList));
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.USER.getValue(), bizUserIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(BizDataTypeEnum.USER.getValue(), bizUserIdList);
}
}

View File

@ -54,6 +54,7 @@ import vip.xiaonuo.client.modular.user.service.ClientUserExtService;
import vip.xiaonuo.client.modular.user.service.ClientUserPasswordService;
import vip.xiaonuo.client.modular.user.service.ClientUserService;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.enums.CommonGenderEnum;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
@ -942,6 +943,7 @@ public class ClientUserServiceImpl extends ServiceImpl<ClientUserMapper, ClientU
clientUserAddParam.setAccount(phone);
clientUserAddParam.setName(phone);
clientUserAddParam.setPhone(phone);
clientUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(clientUserAddParam, ClientUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 获取用户信息
@ -970,6 +972,7 @@ public class ClientUserServiceImpl extends ServiceImpl<ClientUserMapper, ClientU
clientUserAddParam.setAccount(email);
clientUserAddParam.setName(email);
clientUserAddParam.setEmail(email);
clientUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(clientUserAddParam, ClientUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 获取用户信息
@ -1000,6 +1003,7 @@ public class ClientUserServiceImpl extends ServiceImpl<ClientUserMapper, ClientU
clientUserAddParam.setAccount(account);
clientUserAddParam.setName(account);
clientUserAddParam.setPassword(password);
clientUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(clientUserAddParam, ClientUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 返回用户

View File

@ -13,7 +13,6 @@
package vip.xiaonuo.dev.modular.config.enums;
import lombok.Getter;
import vip.xiaonuo.common.exception.CommonException;
/**
*
@ -32,89 +31,11 @@ public enum DevConfigCategoryEnum {
/**
*
*/
BIZ_DEFINE("BIZ_DEFINE"),
/**
* -
*/
THIRD_GITEE("THIRD_GITEE"),
/**
* -
*/
THIRD_WECHAT("THIRD_WECHAT"),
/**
* -
*/
FILE_LOCAL("FILE_LOCAL"),
/**
* -
*/
FILE_TENCENT("FILE_TENCENT"),
/**
* -
*/
FILE_ALIYUN("FILE_ALIYUN"),
/**
* -MINIO
*/
FILE_MINIO("FILE_MINIO"),
/**
* -
*/
EMAIL_LOCAL("EMAIL_LOCAL"),
/**
* -
*/
EMAIL_TENCENT("EMAIL_TENCENT"),
/**
* -
*/
EMAIL_ALIYUN("EMAIL_ALIYUN"),
/**
* -
*/
SMS_TENCENT("SMS_TENCENT"),
/**
* -
*/
SMS_ALIYUN("SMS_ALIYUN"),
/**
* -
*/
PAY_ALI("PAY_ALI"),
/**
* -
*/
PAY_WX("PAY_WX");
BIZ_DEFINE("BIZ_DEFINE");
private final String value;
DevConfigCategoryEnum(String value) {
this.value = value;
}
public static void validate(String value) {
boolean flag = SYS_BASE.getValue().equals(value) || BIZ_DEFINE.getValue().equals(value) ||
THIRD_GITEE.getValue().equals(value) || THIRD_WECHAT.getValue().equals(value) ||
FILE_LOCAL.getValue().equals(value) || FILE_TENCENT.getValue().equals(value) ||
FILE_ALIYUN.getValue().equals(value) || FILE_MINIO.getValue().equals(value) ||
EMAIL_TENCENT.getValue().equals(value) || EMAIL_ALIYUN.getValue().equals(value) ||
SMS_TENCENT.getValue().equals(value) || SMS_ALIYUN.getValue().equals(value) ||
PAY_ALI.getValue().equals(value) || PAY_WX.getValue().equals(value);
if(!flag) {
throw new CommonException("不支持的配置分类:{}", value);
}
}
}

View File

@ -36,6 +36,7 @@ import vip.xiaonuo.dev.modular.config.mapper.DevConfigMapper;
import vip.xiaonuo.dev.modular.config.param.*;
import vip.xiaonuo.dev.modular.config.service.DevConfigService;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@ -48,8 +49,27 @@ import java.util.stream.Collectors;
@Service
public class DevConfigServiceImpl extends ServiceImpl<DevConfigMapper, DevConfig> implements DevConfigService {
/** 缓存前缀 */
private static final String CONFIG_CACHE_KEY = "dev-config:";
/** B端注册是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B";
/** C端注册是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C";
/** B端手机号登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B";
/** C端手机号登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C";
/** B端邮箱登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B";
/** C端邮箱登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C";
@Resource
private CommonCacheOperator commonCacheOperator;
@ -91,9 +111,20 @@ public class DevConfigServiceImpl extends ServiceImpl<DevConfigMapper, DevConfig
@Override
public List<DevConfig> sysBaseList() {
DevConfigListParam devConfigListParam = new DevConfigListParam();
devConfigListParam.setCategory(DevConfigCategoryEnum.SYS_BASE.getValue());
return this.list(devConfigListParam);
LambdaQueryWrapper<DevConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 查询部分字段
lambdaQueryWrapper.select(DevConfig::getId, DevConfig::getConfigKey, DevConfig::getConfigValue,
DevConfig::getCategory, DevConfig::getSortCode, DevConfig::getRemark);
// 类型为系统基础的
lambdaQueryWrapper.eq(DevConfig::getCategory, DevConfigCategoryEnum.SYS_BASE.getValue());
// 或key为特殊的几个
lambdaQueryWrapper.or().in(DevConfig::getConfigKey, CollectionUtil.newArrayList(SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B_KEY,
SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C_KEY,
SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B_KEY,
SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C_KEY,
SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B_KEY,
SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C_KEY));
return this.list(lambdaQueryWrapper);
}
@Override

View File

@ -12,8 +12,10 @@
*/
package vip.xiaonuo.dev.modular.dict.provider;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import vip.xiaonuo.dev.api.DevDictApi;
import vip.xiaonuo.dev.modular.dict.service.DevDictService;
/**
* API
@ -23,4 +25,17 @@ import vip.xiaonuo.dev.api.DevDictApi;
*/
@Service
public class DevDictApiProvider implements DevDictApi {
@Resource
private DevDictService devDictService;
/**
* label
*
* @author yubaoshan
* @date 2025/6/6 13:04
*/
public String getDictLabel(String typeCode, String value) {
return devDictService.getDictLabel(typeCode, value);
}
}

View File

@ -91,4 +91,12 @@ public interface DevDictService extends IService<DevDict> {
* @date 2022/4/24 21:18
*/
DevDict queryEntity(String id);
/**
* label
*
* @author yubaoshan
* @date 2025/6/6 13:04
*/
String getDictLabel(String typeCode, String value);
}

View File

@ -235,4 +235,20 @@ public class DevDictServiceImpl extends ServiceImpl<DevDictMapper, DevDict> impl
return null;
});
}
@Override
public String getDictLabel(String typeCode, String value) {
List<DevDict> devDictList = this.list(new LambdaQueryWrapper<DevDict>().eq(DevDict::getDictValue, typeCode));
if (ObjectUtil.isNotEmpty(devDictList) && devDictList.size() == 1) {
DevDict devDictClone = devDictList.get(0);
DevDict devDict = this.getOne(new LambdaQueryWrapper<DevDict>().eq(DevDict::getParentId, devDictClone.getId())
.eq(DevDict::getDictValue, value));
if (ObjectUtil.isNotEmpty(devDict)) {
return devDict.getDictLabel();
} else {
return null;
}
}
return null;
}
}

View File

@ -240,13 +240,27 @@ public class DevFileController {
devFileService.download(devFileIdParam, response);
}
/**
*
*
* @author xuyuxiang
* @date 2022/6/21 15:44
**/
@ApiOperationSupport(order = 14)
@Operation(summary = "授权下载文件")
@CommonLog("授权下载文件")
@GetMapping(value = "/dev/file/authDownload", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void authDownload(@Valid DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
devFileService.authDownload(devFileIdParam, response);
}
/**
*
*
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 14)
@ApiOperationSupport(order = 15)
@Operation(summary = "删除文件")
@CommonLog("删除文件")
@PostMapping(value = "/dev/file/delete")
@ -262,6 +276,7 @@ public class DevFileController {
* @author
* @date 2025/4/06 20:25
*/
@ApiOperationSupport(order = 16)
@Operation(summary = "物理删除文件")
@CommonLog("物理删除文件")
@PostMapping(value = "/dev/file/deleteAbsolute")
@ -276,7 +291,7 @@ public class DevFileController {
* @author xuyuxiang
* @date 2022/6/21 15:44
**/
@ApiOperationSupport(order = 15)
@ApiOperationSupport(order = 17)
@Operation(summary = "获取文件详情")
@GetMapping("/dev/file/detail")
public CommonResult<DevFile> detail(@Valid DevFileIdParam devFileIdParam) {
@ -289,7 +304,7 @@ public class DevFileController {
* @author yubaoshan
* @date 2024/6/9 23:52
**/
@ApiOperationSupport(order = 16)
@ApiOperationSupport(order = 18)
@Operation(summary = "根据文件url集合获取文件集合")
@PostMapping("/dev/file/getFileListByUrlList")
public CommonResult<List<DevFile>> getFileListByUrlList(@RequestBody @Valid DevFileUrlListParam devFileUrlListParam) {

View File

@ -73,6 +73,10 @@ public class DevFile extends CommonEntity {
@Schema(description = "文件下载路径")
private String downloadPath;
/** 文件下载是否需要授权 */
@Schema(description = "文件下载是否需要授权")
private Boolean isDownloadAuth;
/** 图片缩略图 */
@Schema(description = "图片缩略图")
private String thumbnail;

View File

@ -73,6 +73,16 @@ public interface DevFileService extends IService<DevFile> {
**/
void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException;
/**
*
*
* @author xuyuxiang
* @date 2022/6/21 15:44
**/
void authDownload(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException;
/**
*
*

View File

@ -18,9 +18,11 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
@ -71,12 +73,12 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
@Override
public String uploadReturnId(String engine, MultipartFile file) {
return this.storageFile(engine, file, true);
return this.storageFile(engine, file, true, true);
}
@Override
public String uploadReturnUrl(String engine, MultipartFile file) {
return this.storageFile(engine, file, false);
return this.storageFile(engine, file, false, false);
}
@Override
@ -105,6 +107,33 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
@Override
public void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
unifiedDownload(devFileIdParam, response, false);
// DevFile devFile;
// try {
// devFile = this.queryEntity(devFileIdParam.getId());
// } catch (Exception e) {
// CommonResponseUtil.renderError(response, e.getMessage());
// return;
// }
// if(!devFile.getEngine().equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
// CommonResponseUtil.renderError(response, "非本地文件不支持此方式下载id值为" + devFile.getId());
// return;
// }
// File file = FileUtil.file(devFile.getStoragePath());
// if(!FileUtil.exist(file)) {
// CommonResponseUtil.renderError(response, "找不到存储的文件id值为" + devFile.getId());
// return;
// }
// CommonDownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
}
@Override
public void authDownload(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
unifiedDownload(devFileIdParam, response, true);
}
// 统一下载
private void unifiedDownload(DevFileIdParam devFileIdParam, HttpServletResponse response, boolean isDownloadAuth) throws IOException{
DevFile devFile;
try {
devFile = this.queryEntity(devFileIdParam.getId());
@ -112,16 +141,21 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
CommonResponseUtil.renderError(response, e.getMessage());
return;
}
if(!devFile.getEngine().equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
CommonResponseUtil.renderError(response, "非本地文件不支持此方式下载id值为" + devFile.getId());
if (BooleanUtil.isTrue(devFile.getIsDownloadAuth()) && !isDownloadAuth){
CommonResponseUtil.renderError(response, "该文件需要授权下载请使用授权接口authDownload进行下载");
return;
}
File file = FileUtil.file(devFile.getStoragePath());
if(!FileUtil.exist(file)) {
CommonResponseUtil.renderError(response, "找不到存储的文件id值为" + devFile.getId());
return;
if(devFile.getEngine().equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
File file = FileUtil.file(devFile.getStoragePath());
if(!FileUtil.exist(file)) {
CommonResponseUtil.renderError(response, "找不到存储的文件id值为" + devFile.getId());
return;
}
CommonDownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
} else {
String storagePath = devFile.getStoragePath();
CommonDownloadUtil.download(devFile.getName(), HttpUtil.downloadBytes(storagePath), response);
}
CommonDownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
}
@Transactional(rollbackFor = Exception.class)
@ -165,7 +199,7 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
* @author xuyuxiang
* @date 2022/6/16 16:24
**/
private String storageFile(String engine, MultipartFile file, boolean returnFileId) {
private String storageFile(String engine, MultipartFile file, boolean returnFileId, Boolean isDownloadAuth) {
// 如果引擎为空,默认使用本地
if(ObjectUtil.isEmpty(engine)) {
@ -241,20 +275,32 @@ public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> impl
// 定义下载地址
String downloadUrl;
// 下载路径,注意:本地文件下载地址设置为下载接口地址 + 文件id
if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
String apiUrl = commonProperties.getBackendUrl();
if(ObjectUtil.isEmpty(apiUrl)) {
throw new CommonException("后端域名地址未正确配置snowy.config.common.backend-url为空");
}
downloadUrl= apiUrl + "/dev/file/download?id=" + fileId;
devFile.setDownloadPath(downloadUrl);
} else {
// 阿里云、腾讯云、MINIO可以直接使用存储地址公网作为下载地址
downloadUrl= storageUrl;
devFile.setDownloadPath(devFile.getStoragePath());
String apiUrl = commonProperties.getBackendUrl();
if(ObjectUtil.isEmpty(apiUrl)) {
throw new CommonException("后端域名地址未正确配置snowy.config.common.backend-url为空");
}
if (BooleanUtil.isTrue(isDownloadAuth)){
downloadUrl= apiUrl + "/dev/file/authDownload?id=" + fileId + "&tenCode=" + tenApi.getCurrentTenCode() + "&token=";
}else {
downloadUrl= apiUrl + "/dev/file/download?id=" + fileId;
}
devFile.setDownloadPath(downloadUrl);
// // 下载路径,注意:本地文件下载地址设置为下载接口地址 + 文件id
// if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
// String apiUrl = commonProperties.getBackendUrl();
// if(ObjectUtil.isEmpty(apiUrl)) {
// throw new CommonException("后端域名地址未正确配置snowy.config.common.backend-url为空");
// }
// downloadUrl= apiUrl + "/dev/file/download?id=" + fileId + "&tenCode=" + tenApi.getCurrentTenCode();
// devFile.setDownloadPath(downloadUrl);
// } else {
// // 阿里云、腾讯云、MINIO可以直接使用存储地址公网作为下载地址
// downloadUrl= storageUrl;
// devFile.setDownloadPath(devFile.getStoragePath());
// }
devFile.setIsDownloadAuth(isDownloadAuth);
this.save(devFile);

View File

@ -98,7 +98,8 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
private static final List<JSONObject> GEN_FRONT_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Api.js.btl").set("path", "api"),
JSONUtil.createObj().set("name", "form.vue.btl").set("path", "views"),
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "views"));
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "views"),
JSONUtil.createObj().set("name", "importModel.vue.btl").set("path", "views"));
private static final List<JSONObject> GEN_MOBILE_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "page.json.btl"),
@ -242,6 +243,7 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
}
addParam.setWhetherRetract(GenYesNoEnum.N.getValue());
addParam.setWhetherRequired(GenYesNoEnum.N.getValue());
addParam.setWhetherUnique(GenYesNoEnum.N.getValue());
addParam.setQueryWhether(GenYesNoEnum.N.getValue());
addParam.setSortCode(i);
GenConfig genConfig = BeanUtil.toBean(addParam, GenConfig.class);
@ -330,27 +332,30 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
schema = metaData.getUserName();
}
List<GenBasicTableColumnResult> columns = new ArrayList<>();
rs = metaData.getColumns(null, schema, genBasicTableColumnParam.getTableName(), "%");
rs = metaData.getColumns(conn.getCatalog(), schema, genBasicTableColumnParam.getTableName(), "%");
if(!rs.isBeforeFirst()) {
rs = metaData.getColumns(null, schema, genBasicTableColumnParam.getTableName().toLowerCase(), "%");
rs = metaData.getColumns(conn.getCatalog(), schema, genBasicTableColumnParam.getTableName().toLowerCase(), "%");
}
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME").toUpperCase();
GenBasicTableColumnResult genBasicTableColumnResult = new GenBasicTableColumnResult();
genBasicTableColumnResult.setColumnName(columnName);
String remarks = rs.getString("REMARKS");
if(ObjectUtil.isEmpty(remarks)) {
genBasicTableColumnResult.setColumnRemark(columnName);
} else {
genBasicTableColumnResult.setColumnRemark(remarks);
boolean exist = columns.stream().anyMatch(dbsTableColumnResult -> dbsTableColumnResult.getColumnName().equals(columnName));
if(!exist) {
GenBasicTableColumnResult genBasicTableColumnResult = new GenBasicTableColumnResult();
genBasicTableColumnResult.setColumnName(columnName);
String remarks = rs.getString("REMARKS");
if(ObjectUtil.isEmpty(remarks)) {
genBasicTableColumnResult.setColumnRemark(columnName);
} else {
genBasicTableColumnResult.setColumnRemark(remarks);
}
String typeName = rs.getString("TYPE_NAME").toUpperCase();
if(ObjectUtil.isEmpty(typeName)) {
genBasicTableColumnResult.setTypeName("NONE");
} else {
genBasicTableColumnResult.setTypeName(typeName);
}
columns.add(genBasicTableColumnResult);
}
String typeName = rs.getString("TYPE_NAME").toUpperCase();
if(ObjectUtil.isEmpty(typeName)) {
genBasicTableColumnResult.setTypeName("NONE");
} else {
genBasicTableColumnResult.setTypeName(typeName);
}
columns.add(genBasicTableColumnResult);
}
return columns;
} catch (SQLException sqlException) {
@ -675,6 +680,10 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
bindingJsonObject.set("deleteButtonId", IdWorker.getIdStr());
// 批量删除按钮ID
bindingJsonObject.set("batchDeleteButtonId", IdWorker.getIdStr());
// 导入按钮ID
bindingJsonObject.set("importButtonId", IdWorker.getIdStr());
// 导出按钮ID
bindingJsonObject.set("exportButtonId", IdWorker.getIdStr());
// 作者
bindingJsonObject.set("authorName", genBasic.getAuthorName());
// 生成时间
@ -697,6 +706,7 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", true);
configItem.set("unique", true);
configItem.set("needTableId", true);
bindingJsonObject.set("dbTableKeyJavaType", genConfig.getFieldJavaType());
bindingJsonObject.set("dbTableKeyRemark", genConfig.getFieldRemark());
@ -712,6 +722,7 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", false);
configItem.set("unique", false);
configItem.set("needTableId", false);
} else {
boolean needAddAndUpdate = genConfig.getWhetherAddUpdate().equalsIgnoreCase(GenYesNoEnum.Y.getValue());
@ -720,6 +731,7 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
configItem.set("needPage", genConfig.getQueryWhether().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
configItem.set("needPageType", genConfig.getQueryType());
configItem.set("required", genConfig.getWhetherRequired().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
configItem.set("unique", ObjectUtil.isNotEmpty(genConfig.getWhetherUnique()) && genConfig.getWhetherUnique().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
configItem.set("needTableId", false);
}
}
@ -754,6 +766,20 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
});
// 配置信息
bindingJsonObject.set("configList", configList);
// 获取必填字段
List<JSONObject> requiredFieldList = configList.stream().filter(configItem -> configItem.getBool("required")).toList();
// 必填字段列表
bindingJsonObject.set("requiredFieldList", requiredFieldList);
// 必填字段字符串
bindingJsonObject.set("requiredFieldStr", StrUtil.join(StrUtil.COMMA + " ", requiredFieldList.stream().map(configItem ->
configItem.getStr("fieldNameCamelCase")).collect(Collectors.toList())));
// 获取唯一字段
List<JSONObject> uniqueFieldList = configList.stream().filter(configItem -> configItem.getBool("unique")).toList();
// 唯一字段列表
bindingJsonObject.set("uniqueFieldList", uniqueFieldList);
// 唯一字段字符串
bindingJsonObject.set("uniqueFieldStr", StrUtil.join(StrUtil.COMMA + " ", uniqueFieldList.stream().map(configItem ->
configItem.getStr("fieldNameCamelCase")).collect(Collectors.toList())));
// 有排序字段
bindingJsonObject.set("hasSortCodeField", hasSortCodeField.get());
return bindingJsonObject;

View File

@ -81,6 +81,10 @@ public class GenConfig extends CommonEntity {
@Schema(description = "必填")
private String whetherRequired;
/** 唯一 */
@Schema(description = "唯一")
private String whetherUnique;
/** 查询 */
@Schema(description = "查询")
private String queryWhether;

View File

@ -80,6 +80,10 @@ public class GenConfigAddParam {
@Schema(description = "必填")
private String whetherRequired;
/** 唯一 */
@Schema(description = "唯一")
private String whetherUnique;
/** 查询 */
@Schema(description = "查询")
private String queryWhether;

View File

@ -91,6 +91,11 @@ public class GenConfigEditParam {
@NotBlank(message = "whetherRequired不能为空")
private String whetherRequired;
/** 唯一 */
@Schema(description = "唯一")
@NotBlank(message = "whetherUnique不能为空")
private String whetherUnique;
/** 查询 */
@Schema(description = "查询", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "queryWhether不能为空")

View File

@ -13,14 +13,15 @@
package ${packageName}.${moduleName}.modular.${busName}.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import ${packageName}.common.annotation.CommonLog;
import ${packageName}.common.pojo.CommonResult;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
@ -33,6 +34,7 @@ import ${packageName}.${moduleName}.modular.${busName}.service.${className}Servi
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.io.IOException;
import java.util.List;
/**
@ -120,4 +122,43 @@ public class ${className}Controller {
public CommonResult<${className}> detail(@Valid ${className}IdParam ${classNameFirstLower}IdParam) {
return CommonResult.data(${classNameFirstLower}Service.detail(${classNameFirstLower}IdParam));
}
/**
* 下载${functionName}导入模板
*
* @author ${authorName}
* @date ${genTime}
*/
@Operation(summary = "下载${functionName}导入模板")
@GetMapping(value = "/${moduleName}/${busName}/downloadImportTemplate", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
${classNameFirstLower}Service.downloadImportTemplate(response);
}
/**
* 导入${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
@Operation(summary = "导入${functionName}")
@CommonLog("导入${functionName}")
@SaCheckPermission("/${moduleName}/${busName}/importData")
@PostMapping("/${moduleName}/${busName}/importData")
public CommonResult<JSONObject> importData(@RequestPart("file") MultipartFile file) {
return CommonResult.data(${classNameFirstLower}Service.importData(file));
}
/**
* 导出${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
@Operation(summary = "导出${functionName}")
@SaCheckPermission("/${moduleName}/${busName}/exportData")
@PostMapping(value = "/${moduleName}/${busName}/exportData", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void exportData(@RequestBody List<${className}IdParam> ${classNameFirstLower}IdParamList, HttpServletResponse response) throws IOException {
${classNameFirstLower}Service.exportData(${classNameFirstLower}IdParamList, response);
}
}

View File

@ -12,6 +12,8 @@
*/
package ${packageName}.${moduleName}.modular.${busName}.param;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@ -34,6 +36,10 @@ public class ${className}EditParam {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needEdit) { %>
/** ${configList[i].fieldRemark} */
<% if(configList[i].fieldJavaType == 'Date') { %>
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
<% } else { %><% } %>
@ExcelProperty("${configList[i].fieldRemark}")
@Schema(description = "${configList[i].fieldRemark}"<% if(configList[i].required) { %>, requiredMode = Schema.RequiredMode.REQUIRED<% } %>)
<% if(configList[i].required) { %>
<% if(configList[i].fieldJavaType == 'String') { %>@NotBlank<% } else { %>@NotNull<% } %>(message = "${configList[i].fieldNameCamelCase}不能为空")

View File

@ -12,14 +12,17 @@
*/
package ${packageName}.${moduleName}.modular.${busName}.service;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
import ${packageName}.${moduleName}.modular.${busName}.param.${className}AddParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}EditParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}IdParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}PageParam;
import java.io.IOException;
import java.util.List;
/**
@ -76,5 +79,29 @@ public interface ${className}Service extends IService<${className}> {
* @author ${authorName}
* @date ${genTime}
**/
${className} queryEntity(String id);
${className} queryEntity(String ${dbTableKeyCamelCase});
/**
* 下载${functionName}导入模板
*
* @author ${authorName}
* @date ${genTime}
*/
void downloadImportTemplate(HttpServletResponse response) throws IOException;
/**
* 导入${functionName}
*
* @author ${authorName}
* @date ${genTime}
**/
JSONObject importData(MultipartFile file);
/**
* 导出${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
void exportData(List<${className}IdParam> ${classNameFirstLower}IdParamList, HttpServletResponse response) throws IOException;
}

View File

@ -13,17 +13,31 @@
package ${packageName}.${moduleName}.modular.${busName}.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import ${packageName}.common.enums.CommonSortOrderEnum;
import ${packageName}.common.exception.CommonException;
import ${packageName}.common.page.CommonPageRequest;
import java.math.BigDecimal;
import java.util.Date;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
import ${packageName}.${moduleName}.modular.${busName}.mapper.${className}Mapper;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}AddParam;
@ -32,6 +46,11 @@ import ${packageName}.${moduleName}.modular.${busName}.param.${className}IdParam
import ${packageName}.${moduleName}.modular.${busName}.param.${className}PageParam;
import ${packageName}.${moduleName}.modular.${busName}.service.${className}Service;
import vip.xiaonuo.common.util.CommonDownloadUtil;
import vip.xiaonuo.common.util.CommonResponseUtil;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
@ -77,18 +96,28 @@ public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${c
@Override
public void add(${className}AddParam ${classNameFirstLower}AddParam) {
${className} ${classNameFirstLower} = BeanUtil.toBean(${classNameFirstLower}AddParam, ${className}.class);
<% for(var i = 0; i < uniqueFieldList.~size; i++) { %>
<% if(!uniqueFieldList[i].needTableId) { %>
if(this.count(new LambdaQueryWrapper<${className}>().eq(${className}::get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}, ${classNameFirstLower}.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}())) > 0) {
throw new CommonException("存在重复的${uniqueFieldList[i].fieldRemark},值为:{}", ${classNameFirstLower}.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}());
}
<% } %>
<% } %>
this.save(${classNameFirstLower});
}
@Transactional(rollbackFor = Exception.class)
@Override
public void edit(${className}EditParam ${classNameFirstLower}EditParam) {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
${className} ${classNameFirstLower} = this.queryEntity(${classNameFirstLower}EditParam.get${configList[i].fieldNameCamelCaseFirstUpper}());
<% } %>
<% } %>
${className} ${classNameFirstLower} = this.queryEntity(${classNameFirstLower}EditParam.get${dbTableKeyFirstUpper}());
BeanUtil.copyProperties(${classNameFirstLower}EditParam, ${classNameFirstLower});
<% for(var i = 0; i < uniqueFieldList.~size; i++) { %>
<% if(!uniqueFieldList[i].needTableId) { %>
if(this.count(new LambdaQueryWrapper<${className}>().ne(${className}::get${dbTableKeyFirstUpper}, ${classNameFirstLower}.get${dbTableKeyFirstUpper}()).eq(${className}::get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}, ${classNameFirstLower}.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}())) > 0) {
throw new CommonException("存在重复的${uniqueFieldList[i].fieldRemark},值为:{}", ${classNameFirstLower}.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}());
}
<% } %>
<% } %>
this.updateById(${classNameFirstLower});
}
@ -96,20 +125,129 @@ public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${c
@Override
public void delete(List<${className}IdParam> ${classNameFirstLower}IdParamList) {
// 执行删除
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
this.removeByIds(CollStreamUtil.toList(${classNameFirstLower}IdParamList, ${className}IdParam::get${configList[i].fieldNameCamelCaseFirstUpper}));
<% } %>
<% } %>
this.removeByIds(CollStreamUtil.toList(${classNameFirstLower}IdParamList, ${className}IdParam::get${dbTableKeyFirstUpper}));
}
@Override
public ${className} detail(${className}IdParam ${classNameFirstLower}IdParam) {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
return this.queryEntity(${classNameFirstLower}IdParam.get${configList[i].fieldNameCamelCaseFirstUpper}());
<% } %>
return this.queryEntity(${classNameFirstLower}IdParam.get${dbTableKeyFirstUpper}());
}
@Override
public ${className} queryEntity(String ${dbTableKeyCamelCase}) {
${className} ${classNameFirstLower} = this.getById(${dbTableKeyCamelCase});
if(ObjectUtil.isEmpty(${classNameFirstLower})) {
throw new CommonException("${functionName}不存在,${dbTableKeyCamelCase}值为:{}", ${dbTableKeyCamelCase});
}
return ${classNameFirstLower};
}
@Override
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
File tempFile = null;
try {
List<${className}EditParam> dataList = CollectionUtil.newArrayList();
String fileName = "${functionName}导入模板_" + DateUtil.format(DateTime.now(), DatePattern.PURE_DATETIME_PATTERN) + ".xlsx";
tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
EasyExcel.write(tempFile.getPath(), ${className}EditParam.class).sheet("${functionName}").doWrite(dataList);
CommonDownloadUtil.download(tempFile, response);
} catch (Exception e) {
log.error(">>> ${functionName}导入模板下载失败:", e);
CommonResponseUtil.renderError(response, "${functionName}导入模板下载失败");
} finally {
FileUtil.del(tempFile);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public JSONObject importData(MultipartFile file) {
try {
int successCount = 0;
int errorCount = 0;
JSONArray errorDetail = JSONUtil.createArray();
// 创建临时文件
File tempFile = FileUtil.writeBytes(file.getBytes(), FileUtil.file(FileUtil.getTmpDir() +
FileUtil.FILE_SEPARATOR + "${classNameFirstLower}ImportTemplate.xlsx"));
// 读取excel
List<${className}EditParam> ${classNameFirstLower}EditParamList = EasyExcel.read(tempFile).head(${className}EditParam.class).sheet()
.headRowNumber(1).doReadSync();
List<${className}> allDataList = this.list();
for (int i = 0; i < ${classNameFirstLower}EditParamList.size(); i++) {
JSONObject jsonObject = this.doImport(allDataList, ${classNameFirstLower}EditParamList.get(i), i);
if(jsonObject.getBool("success")) {
successCount += 1;
} else {
errorCount += 1;
errorDetail.add(jsonObject);
}
}
return JSONUtil.createObj()
.set("totalCount", ${classNameFirstLower}EditParamList.size())
.set("successCount", successCount)
.set("errorCount", errorCount)
.set("errorDetail", errorDetail);
} catch (Exception e) {
log.error(">>> ${functionName}导入失败:", e);
throw new CommonException("${functionName}导入失败");
}
}
public JSONObject doImport(List<${className}> allDataList, ${className}EditParam ${classNameFirstLower}EditParam, int i) {
<% for(var i = 0; i < requiredFieldList.~size; i++) { %>
${requiredFieldList[i].fieldJavaType} ${requiredFieldList[i].fieldNameCamelCase} = ${classNameFirstLower}EditParam.get${requiredFieldList[i].fieldNameCamelCaseFirstUpper}();
<% } %>
if(ObjectUtil.hasEmpty(${requiredFieldStr})) {
return JSONUtil.createObj().set("index", i + 1).set("success", false).set("msg", "必填字段存在空值");
} else {
try {
int index = CollStreamUtil.toList(allDataList, ${className}::get${dbTableKeyFirstUpper}).indexOf(${classNameFirstLower}EditParam.get${dbTableKeyFirstUpper}());
${className} ${classNameFirstLower};
boolean isAdd = false;
if(index == -1) {
isAdd = true;
${classNameFirstLower} = new ${className}();
} else {
${classNameFirstLower} = allDataList.get(index);
}
<% if(uniqueFieldList.~size > 1) { %>
if(isAdd) {
<% for(var i = 0; i < uniqueFieldList.~size; i++) { %>
<% if(!uniqueFieldList[i].needTableId) { %>
boolean repeat${uniqueFieldList[i].fieldNameCamelCaseFirstUpper} = allDataList.stream().anyMatch(tempData -> ObjectUtil
.isNotEmpty(tempData.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}()) && tempData.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}().equals(${classNameFirstLower}EditParam.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}()));
if(repeat${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}) {
return JSONUtil.createObj().set("index", i + 1).set("success", false).set("msg", "新增数据时字段【${uniqueFieldList[i].fieldRemark}${uniqueFieldList[i].fieldNameCamelCase})】与数据库中数据重复,值为:" + ${classNameFirstLower}EditParam.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}());
}
<% } %>
<% } %>
} else {
<% for(var i = 0; i < uniqueFieldList.~size; i++) { %>
<% if(!uniqueFieldList[i].needTableId) { %>
boolean repeat${uniqueFieldList[i].fieldNameCamelCaseFirstUpper} = allDataList.stream().anyMatch(tempData -> ObjectUtil
.isNotEmpty(tempData.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}()) && tempData.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}()
.equals(${classNameFirstLower}EditParam.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}()) && !tempData.get${dbTableKeyFirstUpper}().equals(${classNameFirstLower}.get${dbTableKeyFirstUpper}()));
if(repeat${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}) {
return JSONUtil.createObj().set("index", i + 1).set("success", false).set("msg", "更新数据时字段【${uniqueFieldList[i].fieldRemark}${uniqueFieldList[i].fieldNameCamelCase})】与数据库中数据重复,值为:" + ${classNameFirstLower}EditParam.get${uniqueFieldList[i].fieldNameCamelCaseFirstUpper}());
}
<% } %>
<% } %>
}
<% } %>
BeanUtil.copyProperties(${classNameFirstLower}EditParam, ${classNameFirstLower});
if(isAdd) {
allDataList.add(${classNameFirstLower});
} else {
allDataList.remove(index);
allDataList.add(index, ${classNameFirstLower});
}
this.saveOrUpdate(${classNameFirstLower});
return JSONUtil.createObj().set("success", true);
} catch (Exception e) {
log.error(">>> 数据导入异常:", e);
return JSONUtil.createObj().set("success", false).set("index", i + 1).set("msg", "数据导入异常");
}
}
}
@Override
@ -120,4 +258,27 @@ public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${c
}
return ${classNameFirstLower};
}
@Override
public void exportData(List<${className}IdParam> ${classNameFirstLower}IdParamList, HttpServletResponse response) throws IOException {
File tempFile = null;
try {
List<${className}EditParam> dataList;
if(ObjectUtil.isNotEmpty(${classNameFirstLower}IdParamList)) {
List<String> ${dbTableKeyCamelCase}List = CollStreamUtil.toList(${classNameFirstLower}IdParamList, ${className}IdParam::get${dbTableKeyFirstUpper});
dataList = BeanUtil.copyToList(this.listByIds(${dbTableKeyCamelCase}List), ${className}EditParam.class);
} else {
dataList = BeanUtil.copyToList(this.list(), ${className}EditParam.class);
}
String fileName = "${functionName}_" + DateUtil.format(DateTime.now(), DatePattern.PURE_DATETIME_PATTERN) + ".xlsx";
tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
EasyExcel.write(tempFile.getPath(), ${className}EditParam.class).sheet("${functionName}").doWrite(dataList);
CommonDownloadUtil.download(tempFile, response);
} catch (Exception e) {
log.error(">>> ${functionName}导出失败:", e);
CommonResponseUtil.renderError(response, "${functionName}导出失败");
} finally {
FileUtil.del(tempFile);
}
}
}

View File

@ -24,5 +24,21 @@ export default {
// 获取${functionName}详情
${classNameFirstLower}Detail(data) {
return request('detail', data, 'get')
}
},
// 下载${functionName}导入模板
${classNameFirstLower}DownloadTemplate(data) {
return request('downloadImportTemplate', data, 'get', {
responseType: 'blob'
})
},
// 导入${functionName}
${classNameFirstLower}Import(data) {
return request('importData', data)
},
// 导出${functionName}
${classNameFirstLower}Export(data) {
return request('exportData', data, 'post', {
responseType: 'blob'
})
}
}

View File

@ -0,0 +1,129 @@
<template>
<xn-form-container title="导入导出" :width="700" :visible="visible" :destroy-on-close="true" @close="onClose">
<span>导入数据格式严格按照系统模板进行数据录入,请点击&nbsp;<a-button type="primary" size="small" @click="downloadImportTemplate">下载模板</a-button>
</span>
<a-divider dashed />
<div>
<a-spin :spinning="impUploadLoading">
<a-upload-dragger :show-upload-list="false" :custom-request="customRequestLocal" :accept="uploadAccept">
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
<p class="ant-upload-hint">仅支持xls、xlsx格式文件</p>
</a-upload-dragger>
</a-spin>
</div>
<a-alert v-if="impAlertStatus" type="info" :show-icon="false" banner closable @close="onImpClose" class="mt-3">
<template #description>
<p>导入总数:{{ impResultData.totalCount }} 条</p>
<p>导入成功:{{ impResultData.successCount }} 条</p>
<div v-if="impResultData.errorCount > 0">
<p><span class="xn-color-red">失败条数:</span>{{ impResultData.errorCount }} 条</p>
<a-table :dataSource="impResultErrorDataSource" :columns="impErrorColumns" size="small" />
</div>
</template>
</a-alert>
</xn-form-container>
</template>
<script setup name="${classNameFirstLower}ImportModel">
import { message } from 'ant-design-vue'
import ${classNameFirstLower}Api from '@/api/${moduleName}/${classNameFirstLower}Api'
import downloadUtil from '@/utils/downloadUtil'
const impUploadLoading = ref(false)
const impAlertStatus = ref(false)
const impResultData = ref({})
const impResultErrorDataSource = ref([])
const impAccept = [
{
extension: '.xls',
mimeType: 'application/vnd.ms-excel'
},
{
extension: '.xlsx',
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}
]
// 指定能选择的文件类型
const uploadAccept = String(
impAccept.map((item) => {
return item.mimeType
})
)
// 导入
const customRequestLocal = (data) => {
impUploadLoading.value = true
const fileData = new FormData()
// 校验上传文件扩展名和文件类型是否为.xls、.xlsx
const extension = '.'.concat(data.file.name.split('.').slice(-1).toString().toLowerCase())
const mimeType = data.file.type
// 提取允许的扩展名
const extensionArr = impAccept.map((item) => item.extension)
// 提取允许的MIMEType
const mimeTypeArr = impAccept.map((item) => item.mimeType)
if (!extensionArr.includes(extension) || !mimeTypeArr.includes(mimeType)) {
message.warning('上传文件类型仅支持xls、xlsx格式文件')
impUploadLoading.value = false
return false
}
fileData.append('file', data.file)
return ${classNameFirstLower}Api
.${classNameFirstLower}Import(fileData)
.then((res) => {
impAlertStatus.value = true
impResultData.value = res
impResultErrorDataSource.value = res.errorDetail
})
.finally(() => {
impUploadLoading.value = false
})
}
// 关闭导入提示
const onImpClose = () => {
impAlertStatus.value = false
}
const impErrorColumns = [
{
title: '索引',
dataIndex: 'index',
width: '80px'
},
{
title: '原因',
dataIndex: 'msg'
}
]
// 定义emit事件
const emit = defineEmits({ successful: null })
// 默认是关闭状态
const visible = ref(false)
const submitLoading = ref(false)
// 打开抽屉
const onOpen = () => {
visible.value = true
}
// 关闭抽屉
const onClose = () => {
visible.value = false
// 关闭导入的提示
onImpClose()
}
// 下载导入模板
const downloadImportTemplate = () => {
${classNameFirstLower}Api.${classNameFirstLower}DownloadTemplate().then((res) => {
downloadUtil.resultDownload(res)
})
}
// 调用这个函数将子组件的一些数据和方法暴露出去
defineExpose({
onOpen
})
</script>
<style scoped>
.xn-color-red {
color: #ff0000;
}
</style>

View File

@ -82,11 +82,7 @@
:data="loadData"
:alert="options.alert.show"
bordered
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
:row-key="(record) => record.${configList[i].fieldNameCamelCase}"
<% } %>
<% } %>
:row-key="(record) => record.${dbTableKeyCamelCase}"
:tool-config="toolConfig"
:row-selection="options.rowSelection"
>
@ -96,6 +92,14 @@
<template #icon><plus-outlined /></template>
新增
</a-button>
<a-button @click="importModelRef.onOpen()" v-if="hasPerm('${classNameFirstLower}Import')">
<template #icon><import-outlined /></template>
<span>导入</span>
</a-button>
<a-button @click="exportData" v-if="hasPerm('${classNameFirstLower}Export')">
<template #icon><export-outlined /></template>
<span>导出</span>
</a-button>
<xn-batch-button
v-if="hasPerm('${classNameFirstLower}BatchDelete')"
buttonName="批量删除"
@ -140,6 +144,7 @@
</template>
</s-table>
</a-card>
<ImportModel ref="importModelRef" />
<Form ref="formRef" @successful="tableRef.refresh()" />
</template>
@ -161,12 +166,15 @@
<% } %>
import { cloneDeep } from 'lodash-es'
import Form from './form.vue'
import ImportModel from './importModel.vue'
import downloadUtil from '@/utils/downloadUtil'
import ${classNameFirstLower}Api from '@/api/${moduleName}/${classNameFirstLower}Api'
<% if (searchCount > 0) { %>
const searchFormState = ref({})
const searchFormRef = ref()
<% } %>
const tableRef = ref()
const importModelRef = ref()
const formRef = ref()
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
<% if(searchCount > 3) { %>
@ -245,17 +253,30 @@
const delete${className} = (record) => {
let params = [
{
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
${configList[i].fieldNameCamelCase}: record.${configList[i].fieldNameCamelCase}
<% } %>
<% } %>
${dbTableKeyCamelCase}: record.${dbTableKeyCamelCase}
}
]
${classNameFirstLower}Api.${classNameFirstLower}Delete(params).then(() => {
tableRef.value.refresh(true)
})
}
// 导出
const exportData = () => {
if (selectedRowKeys.value.length > 0) {
const params = selectedRowKeys.value.map((m) => {
return {
id: m
}
})
${classNameFirstLower}Api.${classNameFirstLower}Export(params).then((res) => {
downloadUtil.resultDownload(res)
})
} else {
${classNameFirstLower}Api.${classNameFirstLower}Export([]).then((res) => {
downloadUtil.resultDownload(res)
})
}
}
// 批量删除
const deleteBatch${className} = (params) => {
${classNameFirstLower}Api.${classNameFirstLower}Delete(params).then(() => {

View File

@ -3,16 +3,19 @@
Date: ${genTime}
*/
INSERT INTO `SYS_RESOURCE` VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, NULL, 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, NULL, NULL, NULL, 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 4, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 4, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${importButtonId}', '${menuId}', '导入${functionName}', NULL, '${classNameFirstLower}Import', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 5, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${exportButtonId}', ${menuId}', '导出${functionName}', NULL, '${classNameFirstLower}Export', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 6, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
<% if (mobileModuleId != null && mobileModuleId != '') { %>
INSERT INTO `MOBILE_RESOURCE` VALUES ('${menuId}', '0', '${functionName}管理', NULL, 'MENU', '${mobileModuleId}', 'MENU', '/pages/${moduleName}/${busName}/index', 'apartment-outlined', '#1890ff', 'YES', 'ENABLE', 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -3,16 +3,19 @@
Date: ${genTime}
*/
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, NULL, '99', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, NULL, NULL, NULL, '99', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '3', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '3', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '4', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '4', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${importButtonId}', '${menuId}', '导入${functionName}', NULL, '${classNameFirstLower}Import', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '5', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${exportButtonId}', '${menuId}', '导出${functionName}', NULL, '${classNameFirstLower}Export', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '6', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
<% if (mobileModuleId != null && mobileModuleId != '') { %>
INSERT INTO "SNOWY"."MOBILE_RESOURCE" VALUES ('${menuId}', '0', '${functionName}管理', NULL, 'MENU', '${mobileModuleId}', 'MENU', '/pages/${moduleName}/${busName}/index', 'apartment-outlined', '#1890ff', 'YES', 'ENABLE', 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -192,7 +192,7 @@ public class SysOrgServiceImpl extends ServiceImpl<SysOrgMapper, SysOrg> impleme
this.removeByIds(toDeleteOrgIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.ORG.getValue(), toDeleteOrgIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.ORG.getValue(), toDeleteOrgIdList);
}
}

View File

@ -146,7 +146,7 @@ public class SysPositionServiceImpl extends ServiceImpl<SysPositionMapper, SysPo
this.removeByIds(positionIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.POSITION.getValue(), positionIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.POSITION.getValue(), positionIdList);
}
}

View File

@ -24,10 +24,13 @@ import vip.xiaonuo.sys.api.SysRelationApi;
import vip.xiaonuo.sys.modular.relation.entity.SysRelation;
import vip.xiaonuo.sys.modular.relation.enums.SysRelationCategoryEnum;
import vip.xiaonuo.sys.modular.relation.service.SysRelationService;
import vip.xiaonuo.sys.modular.user.entity.SysUser;
import vip.xiaonuo.sys.modular.user.service.SysUserService;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* API
@ -41,16 +44,29 @@ public class SysRelationApiProvider implements SysRelationApi {
@Resource
private SysRelationService sysRelationService;
@Resource
private SysUserService sysUserService;
@Override
public List<String> getUserIdListByRoleIdList(List<String> roleIdList) {
return sysRelationService.getRelationObjectIdListByTargetIdListAndCategory(roleIdList,
List<String> userIdList = sysRelationService.getRelationObjectIdListByTargetIdListAndCategory(roleIdList,
SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
if(ObjectUtil.isEmpty(userIdList)){
return sysUserService.listByIds(userIdList).stream().map(SysUser::getId).collect(Collectors.toList());
} else {
return CollectionUtil.newArrayList();
}
}
@Override
public List<String> getUserIdListByGroupIdList(List<String> groupIdList) {
return sysRelationService.getRelationObjectIdListByTargetIdListAndCategory(groupIdList,
List<String> userIdList = sysRelationService.getRelationObjectIdListByTargetIdListAndCategory(groupIdList,
SysRelationCategoryEnum.SYS_USER_HAS_GROUP.getValue());
if(ObjectUtil.isEmpty(userIdList)){
return sysUserService.listByIds(userIdList).stream().map(SysUser::getId).collect(Collectors.toList());
} else {
return CollectionUtil.newArrayList();
}
}
@Override

View File

@ -86,6 +86,14 @@ public class SysMenu extends CommonEntity {
@Schema(description = "是否可见")
private String visible;
/** 显示布局 */
@Schema(description = "显示布局")
private String displayLayout;
/** 缓存 */
@Schema(description = "缓存")
private String keepLive;
/** 排序码 */
@Schema(description = "排序码")
private Integer sortCode;

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.modular.resource.enums;
import lombok.Getter;
/**
*
*
* @author yubaoshan
* @date 2024/9/17 00:14
**/
@Getter
public enum SysMenuWhetherEnum {
/** 写入 */
YES("YES"),
/** 不写入 */
NO("NO");
private final String value;
SysMenuWhetherEnum(String value) {
this.value = value;
}
}

View File

@ -74,6 +74,14 @@ public class SysMenuAddParam {
@Schema(description = "是否可见")
private String visible;
/** 显示布局 */
@Schema(description = "显示布局")
private String displayLayout;
/** 缓存 */
@Schema(description = "缓存")
private String keepLive;
/** 扩展信息 */
@Schema(description = "扩展信息")
private String extJson;

View File

@ -79,6 +79,14 @@ public class SysMenuEditParam {
@Schema(description = "是否可见")
private String visible;
/** 显示布局 */
@Schema(description = "显示布局")
private String displayLayout;
/** 缓存 */
@Schema(description = "缓存")
private String keepLive;
/** 扩展信息 */
@Schema(description = "扩展信息")
private String extJson;

View File

@ -115,7 +115,9 @@ public class SysButtonServiceImpl extends ServiceImpl<SysButtonMapper, SysButton
CollectionUtil.newArrayList(JSONUtil.createObj().set("title", "新增" + functionName).set("code", classNameFirstLower + "Add").set("sortCode", 1),
JSONUtil.createObj().set("title", "编辑" + functionName).set("code", classNameFirstLower + "Edit").set("sortCode", 2),
JSONUtil.createObj().set("title", "删除" + functionName).set("code", classNameFirstLower + "Delete").set("sortCode", 3),
JSONUtil.createObj().set("title", "批量删除").set("code", classNameFirstLower + "BatchDelete").set("sortCode", 4)).forEach(jsonObject -> {
JSONUtil.createObj().set("title", "批量删除").set("code", classNameFirstLower + "BatchDelete").set("sortCode", 4),
JSONUtil.createObj().set("title", "导入" + functionName).set("code", classNameFirstLower + "Import").set("sortCode", 5),
JSONUtil.createObj().set("title", "导出" + functionName).set("code", classNameFirstLower + "Export").set("sortCode", 6)).forEach(jsonObject -> {
SysButtonAddParam sysButtonAddParam = new SysButtonAddParam();
BeanUtil.copyProperties(jsonObject, sysButtonAddParam);
sysButtonAddParam.setParentId(sysMenu.getId());
@ -171,7 +173,7 @@ public class SysButtonServiceImpl extends ServiceImpl<SysButtonMapper, SysButton
this.removeByIds(buttonIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.RESOURCE.getValue(), buttonIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.RESOURCE.getValue(), buttonIdList);
}
}
}

View File

@ -343,7 +343,7 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
this.removeByIds(toDeleteMenuIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.RESOURCE.getValue(), toDeleteMenuIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.RESOURCE.getValue(), toDeleteMenuIdList);
}
}
}

View File

@ -147,7 +147,7 @@ public class SysModuleServiceImpl extends ServiceImpl<SysModuleMapper, SysModule
this.removeByIds(toDeleteMenuIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.RESOURCE.getValue(), toDeleteMenuIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.RESOURCE.getValue(), toDeleteMenuIdList);
}
}
}

View File

@ -231,6 +231,7 @@ public class SysRoleController {
@CommonLog("给角色授权用户")
@PostMapping("/sys/role/grantUser")
public CommonResult<String> grantUser(@RequestBody @Valid SysRoleGrantUserParam sysRoleGrantUserParam) {
sysRoleGrantUserParam.setRemoveFirst(true);
sysRoleService.grantUser(sysRoleGrantUserParam);
return CommonResult.ok();
}

View File

@ -39,4 +39,7 @@ public class SysRoleGrantUserParam {
@Schema(description = "授权用户信息")
@NotNull(message = "grantInfoList不能为空")
private List<String> grantInfoList;
/** 是否先清空授权信息 */
private Boolean removeFirst = false;
}

View File

@ -233,7 +233,7 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
this.removeByIds(sysRoleIdList);
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.ROLE.getValue(), sysRoleIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.ROLE.getValue(), sysRoleIdList);
}
}
@ -326,8 +326,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
public void grantUser(SysRoleGrantUserParam sysRoleGrantUserParam) {
String id = sysRoleGrantUserParam.getId();
List<String> grantInfoList = sysRoleGrantUserParam.getGrantInfoList();
sysRelationService.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getTargetId, id)
.eq(SysRelation::getCategory, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue()));
if(sysRoleGrantUserParam.getRemoveFirst()) {
sysRelationService.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getTargetId, id)
.eq(SysRelation::getCategory, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue()));
}
sysRelationService.saveBatch(grantInfoList.stream().map(userId -> {
SysRelation sysRelation = new SysRelation();
sysRelation.setObjectId(userId);

View File

@ -41,9 +41,4 @@ public class SysUserBindEmailParam {
@Schema(description = "验证码请求号")
@NotBlank(message = "validCodeReqNo不能为空")
private String validCodeReqNo;
/** 新密码 */
@Schema(description = "新密码")
@NotBlank(message = "newPassword不能为空")
private String newPassword;
}

View File

@ -65,6 +65,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.enums.CommonGenderEnum;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.excel.CommonExcelCustomMergeStrategy;
import vip.xiaonuo.common.exception.CommonException;
@ -93,6 +94,7 @@ import vip.xiaonuo.sys.modular.relation.service.SysRelationService;
import vip.xiaonuo.sys.modular.resource.entity.SysButton;
import vip.xiaonuo.sys.modular.resource.entity.SysMenu;
import vip.xiaonuo.sys.modular.resource.entity.SysModule;
import vip.xiaonuo.sys.modular.resource.enums.SysMenuWhetherEnum;
import vip.xiaonuo.sys.modular.resource.enums.SysResourceCategoryEnum;
import vip.xiaonuo.sys.modular.resource.enums.SysResourceMenuTypeEnum;
import vip.xiaonuo.sys.modular.resource.service.SysButtonService;
@ -447,7 +449,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
sysUserExtService.remove(new LambdaQueryWrapper<SysUserExt>().in(SysUserExt::getUserId, sysUserIdList));
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(SysDataTypeEnum.USER.getValue(), sysUserIdList);
CommonDataChangeEventCenter.doDeleteWithDataIdList(SysDataTypeEnum.USER.getValue(), sysUserIdList);
}
}
@ -992,7 +994,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 执行校验验证码
validValidCode(null, sysUserGetEmailValidCodeParam.getValidCode(), sysUserGetEmailValidCodeParam.getValidCodeReqNo());
// 根据邮箱获取用户信息,判断用户是否存在,如果存在则不能绑定该邮箱
if (ObjectUtil.isEmpty(this.getUserByEmail(email))) {
if (ObjectUtil.isNotEmpty(this.getUserByEmail(email))) {
throw new CommonException("邮箱:{}已存在对应用户", email);
}
// 生成邮箱验证码的值随机6为数字
@ -1034,7 +1036,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 执行校验验证码
validValidCode(null, sysUserGetEmailValidCodeParam.getValidCode(), sysUserGetEmailValidCodeParam.getValidCodeReqNo());
// 根据邮箱获取用户信息,判断用户是否存在,如果存在则不能绑定该邮箱
if (ObjectUtil.isEmpty(this.getUserByEmail(email))) {
if (ObjectUtil.isNotEmpty(this.getUserByEmail(email))) {
throw new CommonException("邮箱:{}已存在对应用户", email);
}
// 生成邮箱验证码的值随机6为数字
@ -1074,7 +1076,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
throw new CommonException("邮箱:{}格式错误", email);
}
// 根据邮箱获取用户信息,判断用户是否存在,如果存在则不能绑定该邮箱
if (ObjectUtil.isEmpty(this.getUserByEmail(email))) {
if (ObjectUtil.isNotEmpty(this.getUserByEmail(email))) {
throw new CommonException("邮箱:{}已存在对应用户", email);
}
// 执行校验验证码
@ -1253,6 +1255,20 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 如果是首页则设置affix
metaJsonObject.set("affix", true);
}
String menuMetaKeepLiveKey = "keepLive";
String menuMetaDisplayLayoutKey = "displayLayout";
// 设置缓存
if (ObjectUtil.isEmpty(sysMenu.getKeepLive()) || sysMenu.getKeepLive().equals(SysMenuWhetherEnum.NO.getValue())) {
metaJsonObject.set(menuMetaKeepLiveKey, false);
} else if (sysMenu.getKeepLive().equals(SysMenuWhetherEnum.YES.getValue())) {
metaJsonObject.set(menuMetaKeepLiveKey, true);
}
// 设置显示布局
if (ObjectUtil.isEmpty(sysMenu.getDisplayLayout()) || sysMenu.getDisplayLayout().equals(SysMenuWhetherEnum.YES.getValue())) {
metaJsonObject.set(menuMetaDisplayLayoutKey, true);
} else if (sysMenu.getDisplayLayout().equals(SysMenuWhetherEnum.NO.getValue())) {
metaJsonObject.set(menuMetaDisplayLayoutKey, false);
}
}
// 如果设置了不可见那么设置为false为了兼容已有所以只是false的为不显示
if (ObjectUtil.isNotEmpty(sysMenu.getVisible()) && sysMenu.getVisible().equals("FALSE")) {
@ -1347,10 +1363,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
}
}
List<String> extJsonList = sysUserGrantResourceParam.getGrantInfoList().stream()
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
sysRelationService.saveRelationBatchWithClear(sysUserGrantResourceParam.getId(), menuIdList, SysRelationCategoryEnum.SYS_USER_HAS_RESOURCE.getValue(), extJsonList);
}
List<String> extJsonList = sysUserGrantResourceParam.getGrantInfoList().stream()
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
sysRelationService.saveRelationBatchWithClear(sysUserGrantResourceParam.getId(), menuIdList, SysRelationCategoryEnum.SYS_USER_HAS_RESOURCE.getValue(), extJsonList);
}
@Override
@ -1551,7 +1567,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
FileUtil.FILE_SEPARATOR + "userImportTemplate.xlsx"));
// 读取excel
List<SysUserImportParam> sysUserImportParamList = EasyExcel.read(tempFile).head(SysUserImportParam.class).sheet()
.headRowNumber(2).doReadSync();
.headRowNumber(3).doReadSync();
List<SysUser> allUserList = this.list();
for (int i = 0; i < sysUserImportParamList.size(); i++) {
JSONObject jsonObject = this.doImport(allUserList, sysUserImportParamList.get(i), i);
@ -2147,6 +2163,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
sysUserAddParam.setPhone(phone);
sysUserAddParam.setOrgId(this.getDefaultNewUserOrgId());
sysUserAddParam.setPositionId(this.getDefaultNewUserPositionId());
sysUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(sysUserAddParam, SysUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 获取用户信息
@ -2182,6 +2199,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
sysUserAddParam.setEmail(email);
sysUserAddParam.setOrgId(this.getDefaultNewUserOrgId());
sysUserAddParam.setPositionId(this.getDefaultNewUserPositionId());
sysUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(sysUserAddParam, SysUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 获取用户信息
@ -2219,6 +2237,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
sysUserAddParam.setPassword(password);
sysUserAddParam.setOrgId(this.getDefaultNewUserOrgId());
sysUserAddParam.setPositionId(this.getDefaultNewUserPositionId());
sysUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
// 保存用户
this.add(sysUserAddParam, SysUserSourceFromTypeEnum.SYSTEM_REGISTER.getValue());
// 获取用户信息

View File

@ -107,7 +107,7 @@ import java.util.Map;
@MapperScan(basePackages = {"vip.xiaonuo.**.mapper"})
public class GlobalConfigure implements WebMvcConfigurer {
@Autowired
@Resource
private SaTokenConfig saTokenConfig;
private static final String COMMON_REPEAT_SUBMIT_CACHE_KEY = "common-repeatSubmit:";
@ -118,7 +118,6 @@ public class GlobalConfigure implements WebMvcConfigurer {
public static final String[] NO_LOGIN_PATH_ARR = {
/* 主入口 */
"/",
/* 静态资源 */
"/favicon.ico",
"/doc.html",
@ -133,11 +132,17 @@ public class GlobalConfigure implements WebMvcConfigurer {
"/auth/c/getPhoneValidCode",
"/auth/c/doLogin",
"/auth/c/doLoginByPhone",
"/auth/c/register",
"/auth/c/getEmailValidCode",
"/auth/c/doLoginByEmail",
"/auth/b/getPicCaptcha",
"/auth/b/getPhoneValidCode",
"/auth/b/doLogin",
"/auth/b/doLoginByPhone",
"/auth/b/register",
"/auth/b/getEmailValidCode",
"/auth/b/doLoginByEmail",
/* 三方登录相关 */
"/auth/third/render",
@ -154,7 +159,10 @@ public class GlobalConfigure implements WebMvcConfigurer {
"/sys/userCenter/findPasswordGetPhoneValidCode",
"/sys/userCenter/findPasswordGetEmailValidCode",
"/sys/userCenter/findPasswordByPhone",
"/sys/userCenter/findPasswordByEmail"
"/sys/userCenter/findPasswordByEmail",
/* 文件下载 */
"/dev/file/download"
};
/**

View File

@ -587,6 +587,7 @@ CREATE TABLE `DEV_FILE` (
`OBJ_NAME` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件的对象名(唯一名称)',
`STORAGE_PATH` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件存储路径',
`DOWNLOAD_PATH` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件下载路径',
`IS_DOWNLOAD_AUTH` tinyint(1) NULL DEFAULT NULL COMMENT '文件下载是否需要授权',
`THUMBNAIL` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片缩略图',
`EXT_JSON` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '扩展信息',
`DELETE_FLAG` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除标志',
@ -847,6 +848,7 @@ CREATE TABLE `GEN_CONFIG` (
`WHETHER_RETRACT` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列省略',
`WHETHER_ADD_UPDATE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否增改',
`WHETHER_REQUIRED` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '必填',
`WHETHER_UNIQUE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '唯一',
`QUERY_WHETHER` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询',
`QUERY_TYPE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询方式',
`SORT_CODE` int(11) NULL DEFAULT NULL COMMENT '排序',
@ -1196,6 +1198,8 @@ CREATE TABLE `SYS_RESOURCE` (
`ICON` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图标',
`COLOR` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '颜色',
`VISIBLE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否可见',
`DISPLAY_LAYOUT` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '显示布局',
`KEEP_LIVE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '页签缓存',
`SORT_CODE` int(11) NULL DEFAULT NULL COMMENT '排序码',
`EXT_JSON` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '扩展信息',
`DELETE_FLAG` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除标志',