Merge branch 'dev-tw'

This commit is contained in:
tangwei 2026-04-30 11:40:31 +08:00
commit 035a02f5dc
55 changed files with 2364 additions and 325 deletions

View File

@ -0,0 +1,14 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记字段为用户ID字段用于用户名称自动填充
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserIdField {
}

View File

@ -0,0 +1,14 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记字段为用户名字段用于接收自动填充的用户名称
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserNameField {
}

View File

@ -0,0 +1,190 @@
package com.yfd.platform.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.mapper.SysUserMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* 用户名称自动填充工具类
* <p>
* 使用方式
* 1. 在实体类的用户ID字段上添加 @UserIdField 注解
* 2. 在对应需要填充用户名的字段上添加 @UserNameField 注解
* 3. 调用 {@link #fillUserNames(List)} 方法自动填充
*
* <pre>
* 示例
* {@code
* @Data
* public class MyEntity {
* @UserIdField
* private String userId;
*
* @UserNameField
* private String userName;
* }
*
* // 使用
* List<MyEntity> list = ...;
* userNameFillHelper.fillUserNames(list);
* }
* </pre>
*/
@Component
public class UserNameFillHelper {
@Resource
private SysUserMapper sysUserMapper;
/**
* 批量填充用户名称
*
* @param list 需要填充的实体列表
*/
public <T> void fillUserNames(List<T> list) {
if (CollUtil.isEmpty(list)) {
return;
}
Class<?> clazz = list.get(0).getClass();
Field[] fields = clazz.getDeclaredFields();
Field idField = null;
Field nameField = null;
for (Field field : fields) {
if (field.isAnnotationPresent(UserIdField.class)) {
idField = field;
idField.setAccessible(true);
}
if (field.isAnnotationPresent(UserNameField.class)) {
nameField = field;
nameField.setAccessible(true);
}
}
if (idField == null || nameField == null) {
return;
}
Set<String> userIds = new HashSet<>();
for (T item : list) {
try {
Object idValue = idField.get(item);
if (idValue != null && StrUtil.isNotBlank(idValue.toString())) {
userIds.add(idValue.toString());
}
} catch (IllegalAccessException e) {
continue;
}
}
if (userIds.isEmpty()) {
return;
}
List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
Map<String, String> userNameMap = users.stream()
.collect(Collectors.toMap(SysUser::getId, SysUser::getNickname, (a, b) -> a));
for (T item : list) {
try {
Object idValue = idField.get(item);
if (idValue != null && StrUtil.isNotBlank(idValue.toString())) {
String userName = userNameMap.get(idValue.toString());
nameField.set(item, StrUtil.blankToDefault(userName, "未知"));
}
} catch (IllegalAccessException e) {
continue;
}
}
}
/**
* 批量填充用户名称支持多个用户ID字段
* <p>
* 使用方式在实体类中定义多个 @UserIdField @UserNameField 配对字段
*
* @param list 需要填充的实体列表
* @param idFields 用户ID字段名数组
* @param nameFields 用户名字段名数组
*/
public <T> void fillUserNames(List<T> list, String[] idFields, String[] nameFields) {
if (CollUtil.isEmpty(list) || idFields == null || nameFields == null || idFields.length != nameFields.length) {
return;
}
Class<?> clazz = list.get(0).getClass();
Field[] allFields = clazz.getDeclaredFields();
Map<String, Field> fieldMap = new HashMap<>();
for (Field field : allFields) {
fieldMap.put(field.getName(), field);
}
List<Field> idFieldList = new ArrayList<>();
List<Field> nameFieldList = new ArrayList<>();
for (String idFieldName : idFields) {
Field f = fieldMap.get(idFieldName);
if (f != null) {
f.setAccessible(true);
idFieldList.add(f);
}
}
for (String nameFieldName : nameFields) {
Field f = fieldMap.get(nameFieldName);
if (f != null) {
f.setAccessible(true);
nameFieldList.add(f);
}
}
if (idFieldList.isEmpty() || nameFieldList.isEmpty()) {
return;
}
Set<String> userIds = new HashSet<>();
for (T item : list) {
for (Field idField : idFieldList) {
try {
Object idValue = idField.get(item);
if (idValue != null && StrUtil.isNotBlank(idValue.toString())) {
userIds.add(idValue.toString());
}
} catch (IllegalAccessException e) {
continue;
}
}
}
if (userIds.isEmpty()) {
return;
}
List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
Map<String, String> userNameMap = users.stream()
.collect(Collectors.toMap(SysUser::getId, SysUser::getNickname, (a, b) -> a));
for (T item : list) {
for (int i = 0; i < idFieldList.size() && i < nameFieldList.size(); i++) {
try {
Object idValue = idFieldList.get(i).get(item);
if (idValue != null && StrUtil.isNotBlank(idValue.toString())) {
String userName = userNameMap.get(idValue.toString());
nameFieldList.get(i).set(item, StrUtil.blankToDefault(userName, "未知"));
}
} catch (IllegalAccessException e) {
continue;
}
}
}
}
}

View File

@ -27,11 +27,17 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
// 自动填充更新时间 // 自动填充更新时间
this.strictInsertFill(metaObject, "updatedAt", Date.class, now); this.strictInsertFill(metaObject, "updatedAt", Date.class, now);
try {
String userId = SecurityUtils.getUserId();
// 自动填充更新时间 // 自动填充更新时间
this.strictInsertFill(metaObject, "createdBy", String.class, SecurityUtils.getUserId()); this.strictInsertFill(metaObject, "createdBy", String.class, userId );
// 自动填充更新时间 // 自动填充更新时间
this.strictInsertFill(metaObject, "updatedBy", String.class, SecurityUtils.getUserId()); this.strictInsertFill(metaObject, "updatedBy", String.class, userId);
} catch (Exception e) {
e.printStackTrace();
}
} }
/** /**
@ -41,7 +47,13 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
public void updateFill(MetaObject metaObject) { public void updateFill(MetaObject metaObject) {
// 自动填充更新时间 // 自动填充更新时间
this.strictUpdateFill(metaObject, "updatedAt", Date.class, new Date()); this.strictUpdateFill(metaObject, "updatedAt", Date.class, new Date());
try {
String userId = SecurityUtils.getUserId();
// 自动填充更新人 // 自动填充更新人
this.strictInsertFill(metaObject, "updatedBy", String.class, SecurityUtils.getUserId()); this.strictInsertFill(metaObject, "updatedBy", String.class, userId);
} catch (Exception e) {
e.printStackTrace();
}
} }
} }

View File

@ -53,6 +53,10 @@ public class SecurityConfig {
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.requestMatchers("/user/login").anonymous() .requestMatchers("/user/login").anonymous()
.requestMatchers("/user/code").permitAll() .requestMatchers("/user/code").permitAll()
.requestMatchers("/sms/resetPassword").permitAll()
.requestMatchers("/data/fishDraft/previewFile").permitAll()
.requestMatchers("/tempFile/**").permitAll()
.requestMatchers("/system/user/auditUser").permitAll()
.requestMatchers("/eng/**").permitAll() .requestMatchers("/eng/**").permitAll()
.requestMatchers("/env/**").permitAll() .requestMatchers("/env/**").permitAll()
.requestMatchers("/sw/**").permitAll() .requestMatchers("/sw/**").permitAll()

View File

@ -4,6 +4,7 @@ import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil; import cn.hutool.cache.CacheUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
@ -17,6 +18,9 @@ public class WebConfig implements WebMvcConfigurer {
@Resource @Resource
private FileSpaceProperties fileSpaceProperties; private FileSpaceProperties fileSpaceProperties;
@Value("${app.zip-import.temp-dir}")
private String platformPath;
@Bean @Bean
@ -54,7 +58,8 @@ public class WebConfig implements WebMvcConfigurer {
String systemUrl = "file:" + fileSpaceProperties.getSystem().replace("\\", "/")+"user\\"; String systemUrl = "file:" + fileSpaceProperties.getSystem().replace("\\", "/")+"user\\";
registry.addResourceHandler("/avatar/**").addResourceLocations(systemUrl).setCachePeriod(0); registry.addResourceHandler("/avatar/**").addResourceLocations(systemUrl).setCachePeriod(0);
String platformUrl = "file:" + platformPath.replace("\\", "/");
registry.addResourceHandler("/tempFile/**").addResourceLocations(platformUrl).setCachePeriod(0);
} }

View File

@ -2,6 +2,7 @@ package com.yfd.platform.data.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.utils.UserNameFillHelper;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.ApprovalChangeLog; import com.yfd.platform.data.domain.ApprovalChangeLog;
import com.yfd.platform.data.domain.ApprovalLog; import com.yfd.platform.data.domain.ApprovalLog;
@ -28,6 +29,9 @@ public class ApprovalChangeLogController {
@Resource @Resource
private IApprovalChangeLogService approvalChangeLogService; private IApprovalChangeLogService approvalChangeLogService;
@Resource
private UserNameFillHelper userNameFillHelper;
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "查询变更记录列表") @Operation(summary = "查询变更记录列表")
public ResponseResult list() { public ResponseResult list() {
@ -39,7 +43,8 @@ public class ApprovalChangeLogController {
@Operation(summary = "分页查询变更记录列表(通用)") @Operation(summary = "分页查询变更记录列表(通用)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) { public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<ApprovalChangeLog> approvalChangeLogPage = DataSourceRequestUtil.executeQuery(request, ApprovalChangeLog.class, approvalChangeLogService); Page<ApprovalChangeLog> approvalChangeLogPage = DataSourceRequestUtil.executeQuery(request, ApprovalChangeLog.class, approvalChangeLogService);
approvalChangeLogService.fillUserNames(approvalChangeLogPage.getRecords()); userNameFillHelper.fillUserNames(approvalChangeLogPage.getRecords());
// approvalChangeLogService.fillUserNames(approvalChangeLogPage.getRecords());
return ResponseResult.successData(approvalChangeLogPage); return ResponseResult.successData(approvalChangeLogPage);
} }

View File

@ -1,24 +1,35 @@
package com.yfd.platform.data.controller; package com.yfd.platform.data.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.*;
import com.yfd.platform.data.domain.FishImportRequest;
import com.yfd.platform.data.domain.FishImportResult;
import com.yfd.platform.data.domain.ImportTask;
import com.yfd.platform.data.domain.BatchApproveRequest;
import com.yfd.platform.data.domain.BatchRejectRequest;
import com.yfd.platform.data.domain.vo.FishDraftDataVO; import com.yfd.platform.data.domain.vo.FishDraftDataVO;
import com.yfd.platform.data.service.AttachmentUploadService;
import com.yfd.platform.data.service.IFishDraftDataService; import com.yfd.platform.data.service.IFishDraftDataService;
import com.yfd.platform.data.service.IFishImportService; import com.yfd.platform.data.service.IFishImportService;
import com.yfd.platform.data.service.IImportTaskService; import com.yfd.platform.data.service.IImportTaskService;
import com.yfd.platform.data.utils.ZipFileUtil;
import com.yfd.platform.utils.KendoUtil; import com.yfd.platform.utils.KendoUtil;
import com.yfd.platform.utils.SecurityUtils; import com.yfd.platform.utils.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -33,6 +44,7 @@ import java.util.*;
@RestController @RestController
@RequestMapping("/data/fishDraft") @RequestMapping("/data/fishDraft")
@Tag(name = "过鱼数据") @Tag(name = "过鱼数据")
@Slf4j
public class FishDraftDataController { public class FishDraftDataController {
@Resource @Resource
@ -47,6 +59,9 @@ public class FishDraftDataController {
@Resource @Resource
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Resource
private AttachmentUploadService attachmentUploadService;
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "分页查询过鱼数据(关联电站和设施)") @Operation(summary = "分页查询过鱼数据(关联电站和设施)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) { public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) {
@ -109,6 +124,45 @@ public class FishDraftDataController {
return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败"); return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败");
} }
@PostMapping("/importBatchSaveDraft")
@Operation(summary = "批量保存草稿(导入)")
public ResponseResult importBatchSaveDraft(@RequestBody BatchSaveDraftRequest batchSaveDraftRequest) {
String taskId = batchSaveDraftRequest.getTaskId();
ImportTask importTask = importTaskService.getById(taskId);
if (importTask == null) {
return ResponseResult.error("导入任务不存在");
}
String resultJson = importTask.getResultJson();
List<FishDraftData> fishDraftDataList = batchSaveDraftRequest.getFishDraftDataList();
if (resultJson != null && !resultJson.isEmpty()) {
try {
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
ZipFileUtil.ZipContent content = new ZipFileUtil.ZipContent();
content.images = importResult.getImageFiles();
content.videos = importResult.getVideoFiles();
fishImportService.processAttachments(importResult, content);
fishDraftDataList.forEach(fishDraftData -> {
for (FishImportResult.FishImportRow row : importResult.getRows()) {
if (fishDraftData.getId().equals(row.getData().getId())) {
fishDraftData.setPicpth(row.getData().getPicpth());
fishDraftData.setVdpth(row.getData().getVdpth());
break;
}
}
fishDraftData.setStatus("DRAFT");
fishDraftData.setDeletedFlag(0);
fishDraftData.setLockFlag(0);
});
} catch (Exception e) {
e.printStackTrace();
// ignore parse error
}
}
boolean result = fishDraftDataService.saveBatch(fishDraftDataList);
return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败");
}
@PostMapping("/updateDraft") @PostMapping("/updateDraft")
@Operation(summary = "更新草稿") @Operation(summary = "更新草稿")
public ResponseResult updateDraft(@RequestBody FishDraftData fishDraftData) { public ResponseResult updateDraft(@RequestBody FishDraftData fishDraftData) {
@ -161,7 +215,6 @@ public class FishDraftDataController {
} }
@PostMapping("/lockDraft") @PostMapping("/lockDraft")
@Operation(summary = "锁定草稿") @Operation(summary = "锁定草稿")
public ResponseResult lockDraft(@RequestParam String id) { public ResponseResult lockDraft(@RequestParam String id) {
@ -207,18 +260,22 @@ public class FishDraftDataController {
@PostMapping("/importZip") @PostMapping("/importZip")
@Operation(summary = "导入ZIP过鱼数据每个用户同时只能进行一次导入") @Operation(summary = "导入ZIP过鱼数据每个用户同时只能进行一次导入")
public ResponseResult importZip(@RequestParam("file") MultipartFile file) { public ResponseResult importZip(@RequestParam("file") MultipartFile file) {
log.info("开始导入ZIP文件");
if (file == null || file.isEmpty()) { if (file == null || file.isEmpty()) {
return ResponseResult.error("请上传文件"); return ResponseResult.error("请上传文件");
} }
log.info("开始上传文件");
String fileName = file.getOriginalFilename(); String fileName = file.getOriginalFilename();
if (fileName == null || (!fileName.endsWith(".zip"))) { if (fileName == null || (!fileName.endsWith(".zip"))) {
return ResponseResult.error("请上传ZIP文件(.zip)"); return ResponseResult.error("请上传ZIP文件(.zip)");
} }
log.info("开始处理文件");
String uploadUserId = SecurityUtils.getUserId(); String uploadUserId = SecurityUtils.getUserId();
if (importTaskService.hasImportingTask(uploadUserId)) { if (importTaskService.hasImportingTask(uploadUserId)) {
return ResponseResult.error("您有正在进行的导入任务,请等待完成后重试"); return ResponseResult.error("您有正在进行的导入任务,请等待完成后重试");
} }
log.info("开始保存导入任务");
String importNo = "IMP" + System.currentTimeMillis(); String importNo = "IMP" + System.currentTimeMillis();
String taskId = UUID.randomUUID().toString(); String taskId = UUID.randomUUID().toString();
@ -232,8 +289,10 @@ public class FishDraftDataController {
task.setStatus("UPLOADED"); task.setStatus("UPLOADED");
task.setUploadUserId(uploadUserId); task.setUploadUserId(uploadUserId);
task.setUploadTime(new Date()); task.setUploadTime(new Date());
log.info("保存导入任务成功");
importTaskService.save(task); importTaskService.save(task);
log.info("开始保存文件");
FishImportRequest request = new FishImportRequest(); FishImportRequest request = new FishImportRequest();
request.setImportNo(importNo); request.setImportNo(importNo);
request.setUploadUserId(uploadUserId); request.setUploadUserId(uploadUserId);
@ -262,6 +321,277 @@ public class FishDraftDataController {
} }
} }
@GetMapping("/previewTempFiles")
@Operation(summary = "预览临时文件列表")
public ResponseResult previewTempFiles(@RequestParam String taskId) {
if (taskId == null || taskId.isEmpty()) {
return ResponseResult.error("任务ID不能为空");
}
try {
ImportTask task = importTaskService.getById(taskId);
if (task == null) {
return ResponseResult.error("任务不存在");
}
String resultJson = task.getResultJson();
if (resultJson == null || resultJson.isEmpty()) {
return ResponseResult.error("任务结果为空");
}
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
Map<String, Object> previewData = new HashMap<>();
previewData.put("tempDir", importResult.getTempDir());
previewData.put("excelFileName", importResult.getExcelFileName());
previewData.put("excelFilePath", importResult.getExcelFilePath());
List<Map<String, String>> imageList = new ArrayList<>();
if (importResult.getImageFiles() != null) {
for (Map.Entry<String, String> entry : importResult.getImageFiles().entrySet()) {
Map<String, String> fileInfo = new HashMap<>();
fileInfo.put("originalName", entry.getKey());
fileInfo.put("path", entry.getValue());
fileInfo.put("type", "image");
imageList.add(fileInfo);
}
}
previewData.put("images", imageList);
List<Map<String, String>> videoList = new ArrayList<>();
if (importResult.getVideoFiles() != null) {
for (Map.Entry<String, String> entry : importResult.getVideoFiles().entrySet()) {
Map<String, String> fileInfo = new HashMap<>();
fileInfo.put("originalName", entry.getKey());
fileInfo.put("path", entry.getValue());
fileInfo.put("type", "video");
videoList.add(fileInfo);
}
}
previewData.put("videos", videoList);
previewData.put("totalImages", imageList.size());
previewData.put("totalVideos", videoList.size());
return ResponseResult.successData(previewData);
} catch (Exception e) {
log.error("预览临时文件失败: " + e.getMessage(), e);
return ResponseResult.error("预览失败: " + e.getMessage());
}
}
@GetMapping("/previewFile")
@Operation(summary = "预览临时文件内容")
public void previewFile(@RequestParam String taskId, @RequestParam String filename, @RequestParam String type, HttpServletRequest request, HttpServletResponse response) {
ImportTask importTask = importTaskService.getById(taskId);
String resultJson = importTask.getResultJson();
String filePath = null;
String dir = "1".equals(type) ? "images" : "videos";
if (resultJson != null && !resultJson.isEmpty()) {
try {
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
String tempDir = importResult.getTempDir();
filePath = tempDir + File.separator + dir + File.separator + filename;
} catch (Exception e) {
e.printStackTrace();
// ignore parse error
}
}
if (filePath == null) {
writeErrorResponse(response, "文件路径不能为空");
return;
}
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
writeErrorResponse(response, "文件不存在");
return;
}
try {
String fileName = file.getName();
String contentType = request.getServletContext().getMimeType(fileName);
if (contentType == null) {
contentType = "application/octet-stream";
}
response.setContentType(contentType);
response.setHeader("Content-Disposition", "inline; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
response.setContentLengthLong(file.length());
try (FileInputStream fis = new FileInputStream(file);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.flush();
}
} catch (Exception e) {
log.error("预览文件失败: " + e.getMessage(), e);
writeErrorResponse(response, "预览失败: " + e.getMessage());
}
}
@GetMapping("/deleteFile")
@Operation(summary = "删除导入文件")
public ResponseResult deleteFile(@RequestParam String taskId,
@RequestParam String id,
@RequestParam String type,
@RequestParam String filename) {
if (taskId == null || taskId.isEmpty()) {
return ResponseResult.error("任务ID不能为空");
}
if (id == null || id.isEmpty()) {
return ResponseResult.error("数据ID不能为空");
}
if (filename == null || filename.isEmpty()) {
return ResponseResult.error("文件名不能为空");
}
ImportTask importTask = importTaskService.getById(taskId);
if (importTask == null) {
return ResponseResult.error("任务不存在");
}
String resultJson = importTask.getResultJson();
if (resultJson == null || resultJson.isEmpty()) {
return ResponseResult.error("任务结果为空");
}
try {
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
boolean found = false;
for (FishImportResult.FishImportRow row : importResult.getRows()) {
FishDraftData data = row.getData();
if (data == null || !id.equals(data.getId())) {
continue;
}
found = true;
if ("1".equals(type)) {
String picpthName = data.getPicpthName();
if (picpthName != null && !picpthName.isEmpty()) {
String[] names = picpthName.split(";");
StringBuilder newNames = new StringBuilder();
for (String name : names) {
if (!filename.equals(name.trim())) {
if (newNames.length() > 0) {
newNames.append(";");
}
newNames.append(name.trim());
}
}
data.setPicpthName(newNames.toString());
}
List<Map<String, String>> picpthList = row.getPicpthList();
if (picpthList != null) {
picpthList.removeIf(map -> filename.equals(map.get("name")));
}
} else if ("2".equals(type)) {
String vdpthName = data.getVdpthName();
if (vdpthName != null && !vdpthName.isEmpty()) {
String[] names = vdpthName.split(";");
StringBuilder newNames = new StringBuilder();
for (String name : names) {
if (!filename.equals(name.trim())) {
if (newNames.length() > 0) {
newNames.append(";");
}
newNames.append(name.trim());
}
}
data.setVdpthName(newNames.toString());
}
List<Map<String, String>> vdpthList = row.getVdpthList();
if (vdpthList != null) {
vdpthList.removeIf(map -> filename.equals(map.get("name")));
}
}
}
if (!found) {
return ResponseResult.error("未找到对应的数据行");
}
String updatedJson = objectMapper.writeValueAsString(importResult);
importTaskService.saveResultJson(taskId, updatedJson);
return ResponseResult.success("删除成功");
} catch (Exception e) {
log.error("删除文件失败: " + e.getMessage(), e);
return ResponseResult.error("删除失败: " + e.getMessage());
}
}
@GetMapping("/previewFileBase64")
@Operation(summary = "预览临时文件内容(Base64方式)")
public ResponseResult previewFileBase64(@RequestParam String filePath) {
if (filePath == null || filePath.isEmpty()) {
return ResponseResult.error("文件路径不能为空");
}
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
return ResponseResult.error("文件不存在");
}
try {
String fileName = file.getName();
String contentType = getMimeType(fileName);
byte[] fileContent = Files.readAllBytes(file.toPath());
String base64Content = Base64.getEncoder().encodeToString(fileContent);
Map<String, Object> result = new HashMap<>();
result.put("fileName", fileName);
result.put("contentType", contentType);
result.put("base64Content", base64Content);
result.put("size", file.length());
return ResponseResult.successData(result);
} catch (Exception e) {
log.error("预览文件失败: " + e.getMessage(), e);
return ResponseResult.error("预览失败: " + e.getMessage());
}
}
private void writeErrorResponse(HttpServletResponse response, String message) {
try {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"success\":false,\"message\":\"" + message + "\"}");
} catch (Exception ignored) {
}
}
private String getMimeType(String fileName) {
if (fileName == null) return "application/octet-stream";
String lowerName = fileName.toLowerCase();
if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")) {
return "image/jpeg";
} else if (lowerName.endsWith(".png")) {
return "image/png";
} else if (lowerName.endsWith(".gif")) {
return "image/gif";
} else if (lowerName.endsWith(".mp4")) {
return "video/mp4";
} else if (lowerName.endsWith(".webm")) {
return "video/webm";
} else if (lowerName.endsWith(".pdf")) {
return "application/pdf";
} else if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
return "application/octet-stream";
}
@PostMapping("/cancelImport") @PostMapping("/cancelImport")
@Operation(summary = "取消导入任务") @Operation(summary = "取消导入任务")
public ResponseResult cancelImport(@RequestBody FishImportRequest fishImportRequest) { public ResponseResult cancelImport(@RequestBody FishImportRequest fishImportRequest) {
@ -392,15 +722,11 @@ public class FishDraftDataController {
} }
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("successRows", importResult.getSuccessRows() != null ? importResult.getSuccessRows().size() : 0);
map.put("failedRows", importResult.getFailedRows() != null ? importResult.getFailedRows().size() : 0);
map.put("unrecognizedFields", importResult.getUnrecognizedFields() != null ?
importResult.getUnrecognizedFields() : new ArrayList<>());
map.put("tempDir", importResult.getTempDir() != null ? importResult.getTempDir() : ""); map.put("tempDir", importResult.getTempDir() != null ? importResult.getTempDir() : "");
map.put("excelFileName", importResult.getExcelFileName() != null ? map.put("excelFileName", importResult.getExcelFileName() != null ?
importResult.getExcelFileName() : ""); importResult.getExcelFileName() : "");
map.put("failedRowDetails", importResult.getFailedRows() != null ? map.put("rows", importResult.getRows() != null ?
importResult.getFailedRows() : new ArrayList<>()); importResult.getRows() : new ArrayList<>());
return map; return map;
} }
@ -414,4 +740,316 @@ public class FishDraftDataController {
return ResponseResult.error("清理失败: " + e.getMessage()); return ResponseResult.error("清理失败: " + e.getMessage());
} }
} }
@PostMapping("/deleteAttachment")
@Operation(summary = "删除附件")
public ResponseResult deleteAttachment(@RequestParam String id) {
if (id == null || id.isEmpty()) {
return ResponseResult.error("附件ID不能为空");
}
boolean result = attachmentUploadService.deleteFile(id);
if (result) {
return ResponseResult.success("删除成功");
} else {
return ResponseResult.error("删除失败");
}
}
@PostMapping("/revalidateAndUpdateRow")
@Operation(summary = "重新校验并更新导入数据")
public ResponseResult revalidateAndUpdateRow(@RequestBody FishImportRowRequest request) {
String taskId = request.getTaskId();
FishDraftData data = request.getData();
if (taskId == null || taskId.isEmpty()) {
return ResponseResult.error("任务ID不能为空");
}
if (data == null || data.getId() == null || data.getId().isEmpty()) {
return ResponseResult.error("数据对象或其ID不能为空");
}
try {
ImportTask task = importTaskService.getById(taskId);
if (task == null) {
return ResponseResult.error("任务不存在");
}
String resultJson = task.getResultJson();
if (resultJson == null || resultJson.isEmpty()) {
return ResponseResult.error("任务结果为空");
}
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
FishImportResult.FishImportRow targetRow = null;
int targetIndex = -1;
for (int i = 0; i < importResult.getRows().size(); i++) {
FishImportResult.FishImportRow row = importResult.getRows().get(i);
if (row.getData() != null && data.getId().equals(row.getData().getId())) {
targetRow = row;
targetIndex = i;
break;
}
}
if (targetIndex == -1) {
return ResponseResult.error("未找到对应的数据行");
}
FishImportResult.FishImportRow newRow = new FishImportResult.FishImportRow(targetRow.getRowIndex());
newRow.setData(data);
newRow.setVdpthList(targetRow.getVdpthList());
newRow.setPicpthList(targetRow.getPicpthList());
newRow.setVdpthsWarnings(targetRow.getVdpthsWarnings());
newRow.setPicpthsWarnings(targetRow.getPicpthsWarnings());
List<String> warnings = new ArrayList<>();
validateAndNormalizeData(data, newRow, warnings);
newRow.setWarnings(warnings);
String newStatus;
if (warnings.isEmpty()) {
newStatus = FishImportResult.STATUS_SUCCESS;
} else {
newStatus = FishImportResult.STATUS_FAILED;
}
newRow.setStatus(newStatus);
importResult.getRows().set(targetIndex, newRow);
int successCount = 0;
int failedCount = 0;
for (FishImportResult.FishImportRow row : importResult.getRows()) {
if (FishImportResult.STATUS_SUCCESS.equals(row.getStatus())) {
successCount++;
} else if (FishImportResult.STATUS_FAILED.equals(row.getStatus())) {
failedCount++;
}
}
importResult.setSuccessCount(successCount);
importResult.setFailedCount(failedCount);
String updatedJson = objectMapper.writeValueAsString(importResult);
importTaskService.saveResultJson(taskId, updatedJson);
Map<String, Object> map = new HashMap<>();
map.put("success", true);
map.put("row", newRow);
map.put("successCount", successCount);
map.put("failedCount", failedCount);
map.put("warnings", warnings);
return ResponseResult.successData(map);
} catch (Exception e) {
log.error("重新校验数据失败: " + e.getMessage(), e);
return ResponseResult.error("重新校验失败: " + e.getMessage());
}
}
private void validateAndNormalizeData(FishDraftData data, FishImportResult.FishImportRow importRow,
List<String> warnings) {
if (data.getStcd() == null || data.getStcd().isEmpty()) {
warnings.add("stcd");
} else {
String stcd = fishImportService.resolveFpssCode(data.getStcd(), data.getStnm());
if (stcd == null) {
warnings.add("stcd");
}
}
if (data.getRstcd() != null && !data.getRstcd().isEmpty()) {
String stationCode = fishImportService.resolveStationCode(data.getRstcd(), data.getEnnm());
if (stationCode == null) {
warnings.add("rstcd");
}
} else {
warnings.add("rstcd");
}
if (data.getBaseId() != null && !data.getBaseId().isEmpty()) {
String baseId = fishImportService.resolveBaseCode(data.getBaseId(), data.getBaseName());
if (baseId == null) {
warnings.add("baseId");
}
}
if (data.getRvcd() != null && !data.getRvcd().isEmpty()) {
String rvcd = fishImportService.resolveRiverCode(data.getRvcd(), data.getRvcd());
if (rvcd == null) {
warnings.add("rvcd");
}
}
if (data.getTm() == null) {
warnings.add("tm");
}
if (data.getFtp() == null || data.getFtp().isEmpty()) {
warnings.add("ftp");
} else {
String ftpCode = fishImportService.resolveFishDictCode(data.getFtp(), data.getFtpName());
if (ftpCode == null) {
warnings.add("ftp");
}
}
if (data.getFcnt() == null) {
warnings.add("fcnt");
}
if (data.getStrdt() == null) {
warnings.add("strdt");
}
if (data.getEnddt() != null && data.getStrdt() != null && data.getEnddt().before(data.getStrdt())) {
warnings.add("enddt");
}
if (data.getDirection() == null || data.getDirection().isEmpty()) {
warnings.add("direction");
} else {
String direction = fishImportService.resolveDirection(data.getDirection().trim(), importRow);
if (direction == null) {
warnings.add("direction");
}
}
if (data.getIsfs() == null) {
warnings.add("isfs");
} else {
String isfs = fishImportService.resolveIsfs(String.valueOf(data.getIsfs()), importRow);
if (isfs == null) {
warnings.add("isfs");
}
}
if (StringUtils.hasText(data.getBaseId()) && StringUtils.hasText(data.getRstcd())) {
if (!fishImportService.validateStationBelongsToBase(data.getRstcd(), data.getBaseId())) {
warnings.add("baseId");
warnings.add("rstcd");
}
}
if (StringUtils.hasText(data.getRstcd()) && StringUtils.hasText(data.getStcd())) {
if (!fishImportService.validateFpssBelongsToStation(data.getStcd(), data.getRstcd())) {
warnings.add("stcd");
warnings.add("rstcd");
}
}
// if (data.getSourceType() != null && !data.getSourceType().isEmpty()) {
// data.setSourceType(fishImportService.parseSourceType(data.getSourceType().trim()));
// }
}
@PostMapping("/validateAndMatchRow")
@Operation(summary = "校验数据并匹配到成功或失败列表")
public ResponseResult validateAndMatchRow(@RequestBody FishImportRowRequest request) {
String taskId = request.getTaskId();
FishDraftData data = request.getData();
if (taskId == null || taskId.isEmpty()) {
return ResponseResult.error("任务ID不能为空");
}
if (data == null || data.getId() == null || data.getId().isEmpty()) {
return ResponseResult.error("数据对象或其ID不能为空");
}
try {
ImportTask task = importTaskService.getById(taskId);
if (task == null) {
return ResponseResult.error("任务不存在");
}
String resultJson = task.getResultJson();
if (resultJson == null || resultJson.isEmpty()) {
return ResponseResult.error("任务结果为空");
}
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
FishImportResult.FishImportRow matchedRow = findMatchingRow(importResult, data.getId());
FishImportResult.FishImportRow resultRow = new FishImportResult.FishImportRow();
resultRow.setData(data);
if (matchedRow != null) {
resultRow.setUnrecognizedFields(matchedRow.getUnrecognizedFields());
resultRow.setWarnings(matchedRow.getWarnings());
resultRow.setVdpthList(matchedRow.getVdpthList());
resultRow.setPicpthList(matchedRow.getPicpthList());
resultRow.setVdpthsWarnings(matchedRow.getVdpthsWarnings());
resultRow.setPicpthsWarnings(matchedRow.getPicpthsWarnings());
resultRow.setStatus(matchedRow.getStatus());
}
List<String> validationErrors = validateFishDraftData(data);
boolean originallySuccess = matchedRow != null && matchedRow.isSuccess();
boolean originallyFailed = matchedRow != null && matchedRow.isFailed();
boolean hasValidationErrors = !validationErrors.isEmpty();
boolean shouldBeSuccess = originallySuccess && !hasValidationErrors;
boolean shouldBeFailed = originallyFailed || hasValidationErrors;
if (shouldBeSuccess) {
resultRow.setStatus(FishImportResult.STATUS_SUCCESS);
} else if (shouldBeFailed) {
resultRow.setStatus(FishImportResult.STATUS_FAILED);
}
return ResponseResult.successData(java.util.Map.of(
"matched", matchedRow != null,
"originallySuccess", originallySuccess,
"originallyFailed", originallyFailed,
"hasValidationErrors", hasValidationErrors,
"shouldBeSuccess", shouldBeSuccess,
"shouldBeFailed", shouldBeFailed,
"row", resultRow,
"validationErrors", validationErrors
));
} catch (Exception e) {
log.error("校验数据失败: " + e.getMessage(), e);
return ResponseResult.error("校验失败: " + e.getMessage());
}
}
private FishImportResult.FishImportRow findMatchingRow(FishImportResult importResult, String dataId) {
if (importResult.getRows() != null) {
for (FishImportResult.FishImportRow row : importResult.getRows()) {
if (row.getData() != null && dataId.equals(row.getData().getId())) {
return row;
}
}
}
return null;
}
private List<String> validateFishDraftData(FishDraftData data) {
List<String> errors = new ArrayList<>();
if (data.getStcd() == null || data.getStcd().isEmpty()) {
errors.add("电站编码不能为空");
}
if (data.getTm() == null) {
errors.add("填报时间不能为空");
}
if (data.getFtp() == null || data.getFtp().isEmpty()) {
errors.add("鱼类不能为空");
}
if (data.getFcnt() == null || data.getFcnt() < 0) {
errors.add("过鱼数量不合法");
}
if (data.getStrdt() == null) {
errors.add("开始日期不能为空");
}
if (data.getEnddt() == null) {
errors.add("结束日期不能为空");
}
if (data.getStrdt() != null && data.getEnddt() != null && data.getStrdt().after(data.getEnddt())) {
errors.add("开始日期不能晚于结束日期");
}
return errors;
}
} }

View File

@ -1,6 +1,8 @@
package com.yfd.platform.data.domain; package com.yfd.platform.data.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -59,12 +61,14 @@ public class ApprovalChangeLog implements Serializable {
/** /**
* 操作人ID * 操作人ID
*/ */
@UserIdField
private String operatorId; private String operatorId;
/** /**
* 操作人名称 * 操作人名称
*/ */
@TableField(exist = false) @TableField(exist = false)
@UserNameField
private String operatorName; private String operatorName;
/** /**

View File

@ -0,0 +1,23 @@
package com.yfd.platform.data.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BatchSaveDraftRequest {
/**
* 任务id
*/
String taskId;
/**
* 批量保存数据
*/
List<FishDraftData> fishDraftDataList;
}

View File

@ -124,7 +124,7 @@ public class FishDraftData implements Serializable {
private String approvalId; private String approvalId;
/** /**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回 * 状态DRAFT未提交 / PENDING已提交 / APPROVED已通过 / REJECTED已驳回
*/ */
private String status; private String status;
@ -221,6 +221,12 @@ public class FishDraftData implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private String stnm; private String stnm;
/**
* 电站编码名称
*/
@TableField(exist = false)
private String rstcd;
/** /**
* 鱼类名称 * 鱼类名称
*/ */

View File

@ -12,11 +12,15 @@ import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class FishImportResult { public class FishImportResult {
private List<FishImportRow> successRows; public static final String STATUS_SUCCESS = "SUCCESS";
private List<FishImportRow> failedRows; public static final String STATUS_FAILED = "FAILED";
private List<FishImportRow> rows;
private List<String> unrecognizedFields; private List<String> unrecognizedFields;
private Map<String, String> imageFiles; private Map<String, String> imageFiles;
private Map<String, String> videoFiles; private Map<String, String> videoFiles;
// public Map<String, String> images;
// public Map<String, String> videos;
private String tempDir; private String tempDir;
private String excelFileName; private String excelFileName;
private String excelFilePath; private String excelFilePath;
@ -29,11 +33,24 @@ public class FishImportResult {
private String taskId; private String taskId;
public FishImportResult() { public FishImportResult() {
this.successRows = new ArrayList<>(); this.rows = new ArrayList<>();
this.failedRows = new ArrayList<>();
this.unrecognizedFields = new ArrayList<>(); this.unrecognizedFields = new ArrayList<>();
this.imageFiles = new LinkedHashMap<>(); this.imageFiles = new LinkedHashMap<>();
this.videoFiles = new LinkedHashMap<>(); this.videoFiles = new LinkedHashMap<>();
// this.images = new LinkedHashMap<>();
// this.videos = new LinkedHashMap<>();
}
public void addSuccessRow(FishImportRow row) {
if (rows == null) rows = new ArrayList<>();
row.setStatus(STATUS_SUCCESS);
rows.add(row);
}
public void addFailedRow(FishImportRow row) {
if (rows == null) rows = new ArrayList<>();
row.setStatus(STATUS_FAILED);
rows.add(row);
} }
@Data @Data
@ -47,6 +64,8 @@ public class FishImportResult {
private List<Map<String, String>> picpthList; private List<Map<String, String>> picpthList;
private List<String> vdpthsWarnings; private List<String> vdpthsWarnings;
private List<String> picpthsWarnings; private List<String> picpthsWarnings;
private String status;
public FishImportRow() { public FishImportRow() {
this.unrecognizedFields = new ArrayList<>(); this.unrecognizedFields = new ArrayList<>();
this.warnings = new ArrayList<>(); this.warnings = new ArrayList<>();
@ -57,13 +76,16 @@ public class FishImportResult {
} }
public FishImportRow(int rowIndex) { public FishImportRow(int rowIndex) {
this();
this.rowIndex = rowIndex; this.rowIndex = rowIndex;
this.unrecognizedFields = new ArrayList<>(); }
this.warnings = new ArrayList<>();
this.vdpthsWarnings = new ArrayList<>(); public boolean isSuccess() {
this.picpthsWarnings = new ArrayList<>(); return STATUS_SUCCESS.equals(status);
this.vdpthList = new ArrayList<>(); }
this.picpthList = new ArrayList<>();
public boolean isFailed() {
return STATUS_FAILED.equals(status);
} }
} }
} }

View File

@ -0,0 +1,9 @@
package com.yfd.platform.data.domain;
import lombok.Data;
@Data
public class FishImportRowRequest {
private String taskId;
private FishDraftData data;
}

View File

@ -113,7 +113,7 @@ public class FishDraftDataVO implements Serializable {
private String approvalId; private String approvalId;
/** /**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回 * 状态DRAFT未提交 / PENDING已提交 / APPROVED已通过 / REJECTED已驳回
*/ */
private String status; private String status;

View File

@ -2,6 +2,7 @@ package com.yfd.platform.data.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -27,6 +28,10 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
public class AttachmentUploadService { public class AttachmentUploadService {
@Value("${attachment.token}")
private String token;
// 定义一个固定的线程池用于文件上传建议根据服务器性能调整核心线程数 // 定义一个固定的线程池用于文件上传建议根据服务器性能调整核心线程数
private static final ExecutorService UPLOAD_EXECUTOR = new ThreadPoolExecutor( private static final ExecutorService UPLOAD_EXECUTOR = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), 5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
@ -260,4 +265,65 @@ public class AttachmentUploadService {
return null; return null;
} }
} }
private static final String DELETE_URL = "https://211.99.26.225:12125/FileDelete";
public boolean deleteFile(String attachmentId) {
if (attachmentId == null || attachmentId.isEmpty()) {
log.warn("附件ID为空");
return false;
}
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpClient secureClient = HttpClient.newBuilder()
.sslContext(sc)
.build();
String formData = "fileId=" + attachmentId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(DELETE_URL))
.header("Content-Type", "application/x-www-form-urlencoded")
.header("token", token)
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse<String> response = secureClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String responseBody = response.body();
return parseDeleteResult(responseBody);
} else {
log.error("删除附件失败: {}, 状态码: {}", attachmentId, response.statusCode());
return false;
}
} catch (Exception e) {
log.error("删除附件过程中发生异常: {}", attachmentId, e);
return false;
}
}
private boolean parseDeleteResult(String jsonResponse) {
if (jsonResponse == null || jsonResponse.isEmpty()) {
return false;
}
try {
JSONObject json = JSONObject.parseObject(jsonResponse);
return json.containsKey("success") && json.getBoolean("success");
} catch (Exception e) {
log.error("解析删除结果失败: {}", jsonResponse, e);
return false;
}
}
} }

View File

@ -17,7 +17,7 @@ public interface IApprovalChangeLogService extends IService<ApprovalChangeLog> {
*/ */
List<ApprovalChangeLog> getByApprovalId(String approvalId); List<ApprovalChangeLog> getByApprovalId(String approvalId);
void fillUserNames(List<ApprovalChangeLog> list); // void fillUserNames(List<ApprovalChangeLog> list);
/** /**
* 根据草稿数据ID查询变更记录 * 根据草稿数据ID查询变更记录

View File

@ -2,6 +2,7 @@ package com.yfd.platform.data.service;
import com.yfd.platform.data.domain.FishImportRequest; import com.yfd.platform.data.domain.FishImportRequest;
import com.yfd.platform.data.domain.FishImportResult; import com.yfd.platform.data.domain.FishImportResult;
import com.yfd.platform.data.utils.ZipFileUtil;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream; import java.io.InputStream;
@ -18,4 +19,33 @@ public interface IFishImportService {
FishImportResult parseAndMapExcelFromPath(FishImportRequest request); FishImportResult parseAndMapExcelFromPath(FishImportRequest request);
FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId); FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId);
String resolveStationCode(String stationName);
String resolveFpssCode(String name);
String resolveFishDictCode(String name);
String resolveBaseCode(String baseName);
String resolveRiverCode(String riverName);
String resolveStationCode(String code,String stationName);
String resolveFpssCode(String code,String name);
String resolveFishDictCode(String code,String name);
String resolveBaseCode(String code,String baseName);
String resolveRiverCode(String code,String riverName);
String resolveDirection(String direction, FishImportResult.FishImportRow importRow);
String resolveIsfs(String value, FishImportResult.FishImportRow importRow);
String parseSourceType(String value);
boolean validateStationBelongsToBase(String stationCode, String baseId);
boolean validateFpssBelongsToStation(String fpssCode, String stationCode);
void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent);
} }

View File

@ -29,42 +29,42 @@ public class ApprovalChangeLogServiceImpl extends ServiceImpl<ApprovalChangeLogM
public List<ApprovalChangeLog> getByApprovalId(String approvalId) { public List<ApprovalChangeLog> getByApprovalId(String approvalId) {
return approvalChangeLogMapper.selectByApprovalId(approvalId); return approvalChangeLogMapper.selectByApprovalId(approvalId);
} }
@Override // @Override
public void fillUserNames(List<ApprovalChangeLog> list) { // public void fillUserNames(List<ApprovalChangeLog> list) {
if (list == null || list.isEmpty()) { // if (list == null || list.isEmpty()) {
return; // return;
} // }
//
Set<String> userIds = new HashSet<>(); // Set<String> userIds = new HashSet<>();
for (ApprovalChangeLog vo : list) { // for (ApprovalChangeLog vo : list) {
if (StrUtil.isNotBlank(vo.getApprovalId())) { // if (StrUtil.isNotBlank(vo.getApprovalId())) {
userIds.add(vo.getApprovalId()); // userIds.add(vo.getApprovalId());
} // }
if (StrUtil.isNotBlank(vo.getOperatorId())) { // if (StrUtil.isNotBlank(vo.getOperatorId())) {
userIds.add(vo.getOperatorId()); // userIds.add(vo.getOperatorId());
} // }
} // }
//
if (userIds.isEmpty()) { // if (userIds.isEmpty()) {
return; // return;
} // }
//
Map<String, String> userNameMap = new HashMap<>(); // Map<String, String> userNameMap = new HashMap<>();
List<SysUser> users = sysUserMapper.selectBatchIds(userIds); // List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
for (SysUser user : users) { // for (SysUser user : users) {
userNameMap.put(user.getId(), user.getNickname()); // userNameMap.put(user.getId(), user.getNickname());
} // }
//
for (ApprovalChangeLog vo : list) { // for (ApprovalChangeLog vo : list) {
if (StrUtil.isNotBlank(vo.getApprovalId())) { // if (StrUtil.isNotBlank(vo.getApprovalId())) {
vo.setApprovalName(userNameMap.get(vo.getApprovalId())); // vo.setApprovalName(userNameMap.get(vo.getApprovalId()));
} // }
if (StrUtil.isNotBlank(vo.getOperatorId())) { // if (StrUtil.isNotBlank(vo.getOperatorId())) {
vo.setOperatorName(userNameMap.get(vo.getOperatorId())); // vo.setOperatorName(userNameMap.get(vo.getOperatorId()));
} // }
//
} // }
} // }
@Override @Override
public List<ApprovalChangeLog> getByDataId(String dataId) { public List<ApprovalChangeLog> getByDataId(String dataId) {
return approvalChangeLogMapper.selectByDataId(dataId); return approvalChangeLogMapper.selectByDataId(dataId);

View File

@ -106,7 +106,7 @@ public class ApprovalMainServiceImpl extends ServiceImpl<ApprovalMainMapper, App
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean submitApproval(ApprovalMain approvalMain) { public boolean submitApproval(ApprovalMain approvalMain) {
approvalMain.setStatus("SUBMITTED"); approvalMain.setStatus("PENDING");
approvalMain.setApplyTime(new Date()); approvalMain.setApplyTime(new Date());
boolean result = this.save(approvalMain); boolean result = this.save(approvalMain);
if (result) { if (result) {

View File

@ -22,6 +22,7 @@ import com.yfd.platform.utils.QgcQueryWrapperUtil;
import com.yfd.platform.utils.SecurityUtils; import com.yfd.platform.utils.SecurityUtils;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -67,9 +68,7 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
String TM = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "TM"); String TM = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "TM");
String startTime=null; String startTime=null;
String endTime=null; String endTime=null;
String userId = (SecurityUtils.hasPermission("sjtb:edit-review") || "admin".equals(SecurityUtils.getCurrentUsername())) ?null:SecurityUtils.getUserId();
SecurityUtils.getCurrentUser().getAuthorities();
String userId = SecurityUtils.getCurrentUser().getAuthorities().contains("sjtb:import-add") || "admin".equals(SecurityUtils.getCurrentUsername()) ?null:SecurityUtils.getUserId();
// 如果 startTime endTime 为空尝试从 TM 字段解析 // 如果 startTime endTime 为空尝试从 TM 字段解析
if (StrUtil.isNotBlank(TM)&& TM.split( ",").length==2) { if (StrUtil.isNotBlank(TM)&& TM.split( ",").length==2) {
startTime=TM.split(",")[0]; startTime=TM.split(",")[0];
@ -243,7 +242,7 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
approvalMainService.save(approvalMain); approvalMainService.save(approvalMain);
fishDraftData.setApprovalId(approvalMain.getId()); fishDraftData.setApprovalId(approvalMain.getId());
fishDraftData.setStatus("SUBMITTED"); fishDraftData.setStatus("PENDING");
fishDraftData.setSubmitTime(new Date()); fishDraftData.setSubmitTime(new Date());
boolean result = this.updateById(fishDraftData); boolean result = this.updateById(fishDraftData);
if (result) { if (result) {
@ -273,7 +272,7 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
updateWrapper.in(FishDraftData::getId, ids); updateWrapper.in(FishDraftData::getId, ids);
updateWrapper.eq(FishDraftData::getLockFlag, 0); updateWrapper.eq(FishDraftData::getLockFlag, 0);
updateWrapper.set(FishDraftData::getApprovalId, approvalMain.getId()); updateWrapper.set(FishDraftData::getApprovalId, approvalMain.getId());
updateWrapper.set(FishDraftData::getStatus, "SUBMITTED"); updateWrapper.set(FishDraftData::getStatus, "PENDING");
updateWrapper.set(FishDraftData::getSubmitTime, new Date()); updateWrapper.set(FishDraftData::getSubmitTime, new Date());
this.update(updateWrapper); this.update(updateWrapper);
@ -297,7 +296,7 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
List<String> validIds = new ArrayList<>(); List<String> validIds = new ArrayList<>();
for (FishDraftData fishDraftData : dataList) { for (FishDraftData fishDraftData : dataList) {
if ("SUBMITTED".equals(fishDraftData.getStatus())) { if ("PENDING".equals(fishDraftData.getStatus())) {
validIds.add(fishDraftData.getId()); validIds.add(fishDraftData.getId());
if (fishDraftData.getApprovalId() != null) { if (fishDraftData.getApprovalId() != null) {
processedApprovalIds.add(fishDraftData.getApprovalId()); processedApprovalIds.add(fishDraftData.getApprovalId());
@ -340,7 +339,7 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
Date now = new Date(); Date now = new Date();
String operatorId = SecurityUtils.getUserId(); String operatorId = SecurityUtils.getUserId();
FishDraftData fishDraftData = this.getById(id); FishDraftData fishDraftData = this.getById(id);
if (fishDraftData != null && "SUBMITTED".equals(fishDraftData.getStatus())) { if (fishDraftData != null && "PENDING".equals(fishDraftData.getStatus())) {
fishDraftData.setStatus("REJECTED"); fishDraftData.setStatus("REJECTED");
fishDraftData.setApproveTime(now); fishDraftData.setApproveTime(now);
fishDraftData.setUpdatedBy(operatorId); fishDraftData.setUpdatedBy(operatorId);

View File

@ -1,5 +1,6 @@
package com.yfd.platform.data.service.impl; package com.yfd.platform.data.service.impl;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.FishDraftData;
import com.yfd.platform.data.domain.FishImportRequest; import com.yfd.platform.data.domain.FishImportRequest;
import com.yfd.platform.data.domain.FishImportResult; import com.yfd.platform.data.domain.FishImportResult;
@ -8,11 +9,10 @@ import com.yfd.platform.data.service.IFishImportService;
import com.yfd.platform.data.utils.ZipFileUtil; import com.yfd.platform.data.utils.ZipFileUtil;
import com.yfd.platform.env.domain.*; import com.yfd.platform.env.domain.*;
import com.yfd.platform.env.mapper.*; import com.yfd.platform.env.mapper.*;
import com.yfd.platform.system.domain.SysDictionary;
import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.service.ISysDictionaryItemsService; import com.yfd.platform.system.service.ISysDictionaryItemsService;
import com.yfd.platform.system.service.ISysDictionaryService; import com.yfd.platform.system.service.ISysDictionaryService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -26,9 +26,9 @@ import java.math.BigDecimal;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service @Service
@Slf4j
public class FishImportServiceImpl implements IFishImportService { public class FishImportServiceImpl implements IFishImportService {
@Resource @Resource
@ -59,11 +59,18 @@ public class FishImportServiceImpl implements IFishImportService {
private static final Map<Integer, String> EXCEL_COLUMN_INDEX_MAPPING = new LinkedHashMap<>(); private static final Map<Integer, String> EXCEL_COLUMN_INDEX_MAPPING = new LinkedHashMap<>();
private static final Map<String, String> STATION_NAME_CACHE = new LinkedHashMap<>(); private static final Map<String, String> STATION_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> STATION_CODE_TO_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> STATION_TO_BASE_CACHE = new LinkedHashMap<>();
private static final Map<String, String> BASE_NAME_CACHE = new LinkedHashMap<>(); private static final Map<String, String> BASE_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> BASE_CODE_TO_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> RIVER_NAME_CACHE = new LinkedHashMap<>(); private static final Map<String, String> RIVER_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> RIVER_CODE_TO_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FISH_DICT_CACHE = new LinkedHashMap<>(); private static final Map<String, String> FISH_DICT_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FISH_CODE_TO_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FPSS_BH_CACHE = new LinkedHashMap<>(); private static final Map<String, String> FPSS_BH_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FPSS_CODE_TO_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FPSS_TO_STATION_CACHE = new LinkedHashMap<>();
private static final Map<String, String> ISFS_DICT_CACHE = new LinkedHashMap<>(); private static final Map<String, String> ISFS_DICT_CACHE = new LinkedHashMap<>();
private static final String DICT_CODE_FISH = "FISH_TYPE"; private static final String DICT_CODE_FISH = "FISH_TYPE";
@ -146,7 +153,6 @@ public class FishImportServiceImpl implements IFishImportService {
return result; return result;
} }
List<String> unrecognizedHeaders = new ArrayList<>();
Map<Integer, String> columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING); Map<Integer, String> columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING);
int totalRows = sheet.getLastRowNum(); int totalRows = sheet.getLastRowNum();
@ -156,29 +162,26 @@ public class FishImportServiceImpl implements IFishImportService {
continue; continue;
} }
FishImportResult.FishImportRow importRow = parseRow(row, columnIndexMap, i); FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i);
result.setTotalCount(result.getTotalCount() + 1); result.setTotalCount(result.getTotalCount() + 1);
if (importRow.getData() != null && importRow.getWarnings().isEmpty()) { if (importRow.getData() != null && importRow.getWarnings().isEmpty()) {
result.getSuccessRows().add(importRow); result.addSuccessRow(importRow);
result.setSuccessCount(result.getSuccessCount() + 1); result.setSuccessCount(result.getSuccessCount() + 1);
} else { } else {
result.getFailedRows().add(importRow); result.addFailedRow(importRow);
result.setFailedCount(result.getFailedCount() + 1); result.setFailedCount(result.getFailedCount() + 1);
} }
} }
result.setSummary(String.format("共解析%d条数据失败%d条未识别字段%s", result.setSummary(String.format("共解析%d条数据失败%d条",
result.getSuccessCount(), result.getFailedCount(), result.getSuccessCount(), result.getFailedCount()));
unrecognizedHeaders.isEmpty() ? "" : String.join(", ", unrecognizedHeaders)));
return result; return result;
} }
private FishImportResult.FishImportRow parseRow(Row row, Map<Integer, String> columnIndexMap, int rowIndex) { private FishImportResult.FishImportRow parseRow(FishImportResult result, Row row, Map<Integer, String> columnIndexMap, int rowIndex) {
FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(rowIndex); FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(rowIndex);
FishDraftData data = new FishDraftData(); FishDraftData data = new FishDraftData();
data.setId(UUID.randomUUID().toString()); data.setId(UUID.randomUUID().toString());
List<String> missingRequiredFields = new ArrayList<>();
for (Map.Entry<Integer, String> entry : columnIndexMap.entrySet()) { for (Map.Entry<Integer, String> entry : columnIndexMap.entrySet()) {
Integer columnIndex = entry.getKey(); Integer columnIndex = entry.getKey();
String fieldName = entry.getValue(); String fieldName = entry.getValue();
@ -188,15 +191,17 @@ public class FishImportServiceImpl implements IFishImportService {
switch (fieldName) { switch (fieldName) {
case "stationName": case "stationName":
if (!StringUtils.hasText(cellValue)) { if (!StringUtils.hasText(cellValue)) {
importRow.getWarnings().add("ennm"); importRow.getWarnings().add("rstcd");
data.setEnnm(cellValue.trim()); data.setEnnm(cellValue.trim());
data.setRstcd(cellValue);
} else { } else {
String stcd = resolveStationCode(cellValue.trim()); String stcd = resolveStationCode(cellValue.trim());
if (stcd == null) { if (stcd == null) {
importRow.getWarnings().add("ennm"); importRow.getWarnings().add("rstcd");
data.setEnnm(cellValue.trim()); data.setEnnm(cellValue.trim());
} else { } else {
data.setEnnm(cellValue.trim()); data.setEnnm(cellValue.trim());
data.setRstcd(stcd);
} }
} }
break; break;
@ -274,12 +279,12 @@ public class FishImportServiceImpl implements IFishImportService {
break; break;
case "wt": case "wt":
if (!StringUtils.hasText(cellValue)) { if (!StringUtils.hasText(cellValue)) {
importRow.getWarnings().add(fieldName); // importRow.getWarnings().add(fieldName);
data.setWt(parseBigDecimal(cellValue)); data.setWt(parseBigDecimal(cellValue));
} else { } else {
BigDecimal wt = parseBigDecimal(cellValue); BigDecimal wt = parseBigDecimal(cellValue);
if (wt == null) { if (wt == null) {
importRow.getWarnings().add(fieldName); // importRow.getWarnings().add(fieldName);
data.setWt(parseBigDecimal(cellValue)); data.setWt(parseBigDecimal(cellValue));
} }
data.setWt(wt); data.setWt(wt);
@ -318,17 +323,54 @@ public class FishImportServiceImpl implements IFishImportService {
data.setMouth(parseInteger(cellValue)); data.setMouth(parseInteger(cellValue));
break; break;
case "vdpth": case "vdpth":
data.setVdpth(cellValue.trim()); String vdpth = cellValue.trim();
data.setVdpthName(cellValue.trim()); List<String> vdpthList = new ArrayList<>();
Map<String, String> videoFiles = result.getVideoFiles();
for (String fileName : vdpth.split(";")) {
for (String entryName : videoFiles.keySet()) {
if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) {
Map<String, String> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("name", fileName);
objectObjectHashMap.put("value", fileName);
importRow.getVdpthList().add(objectObjectHashMap);
vdpthList.add(fileName);
}
}
}
String vdpthJoin = StrUtil.join(";", vdpthList);
data.setVdpth(vdpthJoin);
data.setVdpthName(vdpthJoin);
break; break;
case "picpth": case "picpth":
data.setPicpth(cellValue.trim()); String picpth = cellValue.trim();
data.setPicpthName(cellValue.trim()); List<String> picpthList = new ArrayList<>();
Map<String, String> imageFiles = result.getImageFiles();
for (String fileName : picpth.split(";")) {
for (String entryName : imageFiles.keySet()) {
if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) {
Map<String, String> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("name", fileName);
objectObjectHashMap.put("value", fileName);
importRow.getPicpthList().add(objectObjectHashMap);
picpthList.add(fileName);
}
}
}
String picpthJoin = StrUtil.join(";", picpthList);
data.setPicpth(picpthJoin);
data.setPicpthName(picpthJoin);
break; break;
case "isfs": case "isfs":
if (StringUtils.hasText(cellValue)) { if (StringUtils.hasText(cellValue)) {
String isfs = resolveIsfs(cellValue.trim(), importRow); String isfs = resolveIsfs(cellValue.trim(), importRow);
data.setIsfs("1".equals(isfs) ? 1 : 0); data.setIsfs("1".equals(isfs) ? 1 : 0);
} else {
importRow.getWarnings().add("isfs");
} }
break; break;
case "sourceType": case "sourceType":
@ -336,7 +378,8 @@ public class FishImportServiceImpl implements IFishImportService {
break; break;
case "stnm": case "stnm":
if (!StringUtils.hasText(cellValue)) { if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("stcd"); importRow.getWarnings().add("stcd");
data.setStcd(cellValue);
} else { } else {
String stcd = resolveFpssCode(cellValue.trim()); String stcd = resolveFpssCode(cellValue.trim());
if (stcd == null) { if (stcd == null) {
@ -344,7 +387,7 @@ public class FishImportServiceImpl implements IFishImportService {
data.setStcd(cellValue.trim()); data.setStcd(cellValue.trim());
data.setStnm(cellValue.trim()); data.setStnm(cellValue.trim());
} else { } else {
data.setStnm(stcd); data.setStnm(cellValue.trim());
data.setStcd(stcd); data.setStcd(stcd);
} }
} }
@ -357,10 +400,41 @@ public class FishImportServiceImpl implements IFishImportService {
// importRow.getWarnings().add("字段[" + fieldName + "]解析异常: " + e.getMessage()); // importRow.getWarnings().add("字段[" + fieldName + "]解析异常: " + e.getMessage());
} }
} }
validateStationFpssRelation(data, importRow);
importRow.setData(data); importRow.setData(data);
return importRow; return importRow;
} }
private void validateStationFpssRelation(FishDraftData data, FishImportResult.FishImportRow importRow) {
loadStationAndBaseCache();
if (StringUtils.hasText(data.getBaseId()) && StringUtils.hasText(data.getRstcd())) {
if (!validateStationBelongsToBase(data.getRstcd(), data.getBaseId())) {
if (!importRow.getWarnings().contains("baseId")) {
importRow.getWarnings().add("baseId");
}
if (!importRow.getWarnings().contains("rstcd")) {
importRow.getWarnings().add("rstcd");
}
if (!importRow.getWarnings().contains("stcd")) {
importRow.getWarnings().add("stcd");
}
}
}
if (StringUtils.hasText(data.getRstcd()) && StringUtils.hasText(data.getStcd())) {
if (!validateFpssBelongsToStation(data.getStcd(), data.getRstcd())) {
if (!importRow.getWarnings().contains("baseId")) {
importRow.getWarnings().add("baseId");
}
if (!importRow.getWarnings().contains("stcd")) {
importRow.getWarnings().add("stcd");
}
if (!importRow.getWarnings().contains("rstcd")) {
importRow.getWarnings().add("rstcd");
}
}
}
}
private void loadStationAndBaseCache() { private void loadStationAndBaseCache() {
if (STATION_NAME_CACHE.isEmpty()) { if (STATION_NAME_CACHE.isEmpty()) {
List<SdEngInfoBH> stationList = engInfoBHMapper.selectList(null); List<SdEngInfoBH> stationList = engInfoBHMapper.selectList(null);
@ -369,7 +443,12 @@ public class FishImportServiceImpl implements IFishImportService {
STATION_NAME_CACHE.put(station.getEnnm().trim().toLowerCase(), station.getStcd()); STATION_NAME_CACHE.put(station.getEnnm().trim().toLowerCase(), station.getStcd());
} }
if (StringUtils.hasText(station.getStcd())) { if (StringUtils.hasText(station.getStcd())) {
STATION_NAME_CACHE.put(station.getStcd().trim().toLowerCase(), station.getStcd()); if (StringUtils.hasText(station.getEnnm())) {
STATION_CODE_TO_NAME_CACHE.put(station.getStcd().trim().toLowerCase(), station.getEnnm().trim().toLowerCase());
}
if (StringUtils.hasText(station.getBaseId())) {
STATION_TO_BASE_CACHE.put(station.getStcd().trim().toLowerCase(), station.getBaseId());
}
} }
} }
} }
@ -381,7 +460,9 @@ public class FishImportServiceImpl implements IFishImportService {
BASE_NAME_CACHE.put(base.getBasename().trim().toLowerCase(), base.getBaseid()); BASE_NAME_CACHE.put(base.getBasename().trim().toLowerCase(), base.getBaseid());
} }
if (StringUtils.hasText(base.getBaseid())) { if (StringUtils.hasText(base.getBaseid())) {
BASE_NAME_CACHE.put(base.getBaseid().trim().toLowerCase(), base.getBaseid()); if (StringUtils.hasText(base.getBasename())) {
BASE_CODE_TO_NAME_CACHE.put(base.getBaseid().trim().toLowerCase(), base.getBasename().trim().toLowerCase());
}
} }
} }
} }
@ -393,7 +474,9 @@ public class FishImportServiceImpl implements IFishImportService {
RIVER_NAME_CACHE.put(river.getRvnm().trim().toLowerCase(), river.getRvcd()); RIVER_NAME_CACHE.put(river.getRvnm().trim().toLowerCase(), river.getRvcd());
} }
if (StringUtils.hasText(river.getRvcd())) { if (StringUtils.hasText(river.getRvcd())) {
RIVER_NAME_CACHE.put(river.getRvcd().trim().toLowerCase(), river.getRvcd()); if (StringUtils.hasText(river.getRvnm())) {
RIVER_CODE_TO_NAME_CACHE.put(river.getRvcd().trim().toLowerCase(), river.getRvnm().trim().toLowerCase());
}
} }
} }
} }
@ -405,7 +488,9 @@ public class FishImportServiceImpl implements IFishImportService {
FISH_DICT_CACHE.put(fishDictoryB.getName().trim().toLowerCase(), fishDictoryB.getCode()); FISH_DICT_CACHE.put(fishDictoryB.getName().trim().toLowerCase(), fishDictoryB.getCode());
} }
if (StringUtils.hasText(fishDictoryB.getCode())) { if (StringUtils.hasText(fishDictoryB.getCode())) {
FISH_DICT_CACHE.put(fishDictoryB.getCode().trim().toLowerCase(), fishDictoryB.getCode()); if (StringUtils.hasText(fishDictoryB.getName())) {
FISH_CODE_TO_NAME_CACHE.put(fishDictoryB.getCode().trim().toLowerCase(), fishDictoryB.getName().trim().toLowerCase());
}
} }
} }
} }
@ -417,15 +502,19 @@ public class FishImportServiceImpl implements IFishImportService {
FPSS_BH_CACHE.put(sdFpssBH.getStnm().trim().toLowerCase(), sdFpssBH.getStcd()); FPSS_BH_CACHE.put(sdFpssBH.getStnm().trim().toLowerCase(), sdFpssBH.getStcd());
} }
if (StringUtils.hasText(sdFpssBH.getStcd())) { if (StringUtils.hasText(sdFpssBH.getStcd())) {
FPSS_BH_CACHE.put(sdFpssBH.getStcd().trim().toLowerCase(), sdFpssBH.getStcd()); if (StringUtils.hasText(sdFpssBH.getStnm())) {
FPSS_CODE_TO_NAME_CACHE.put(sdFpssBH.getStcd().trim().toLowerCase(), sdFpssBH.getStnm().trim().toLowerCase());
}
if (StringUtils.hasText(sdFpssBH.getRstcd())) {
FPSS_TO_STATION_CACHE.put(sdFpssBH.getStcd().trim().toLowerCase(), sdFpssBH.getRstcd());
}
} }
} }
} }
} }
public String resolveStationCode(String stationName) {
private String resolveStationCode(String stationName) {
if (stationName == null) { if (stationName == null) {
return null; return null;
} }
@ -434,14 +523,14 @@ public class FishImportServiceImpl implements IFishImportService {
return STATION_NAME_CACHE.get(lowerName); return STATION_NAME_CACHE.get(lowerName);
} }
for (Map.Entry<String, String> entry : STATION_NAME_CACHE.entrySet()) { for (Map.Entry<String, String> entry : STATION_NAME_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) { if (entry.getKey().contains(lowerName)) {
return entry.getValue(); return entry.getValue();
} }
} }
return null; return null;
} }
private String resolveFpssCode(String name) { public String resolveFpssCode(String name) {
if (name == null) { if (name == null) {
return null; return null;
} }
@ -450,14 +539,56 @@ public class FishImportServiceImpl implements IFishImportService {
return FPSS_BH_CACHE.get(lowerName); return FPSS_BH_CACHE.get(lowerName);
} }
for (Map.Entry<String, String> entry : FPSS_BH_CACHE.entrySet()) { for (Map.Entry<String, String> entry : FPSS_BH_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) { if (entry.getKey().contains(lowerName)) {
return entry.getValue(); return entry.getValue();
} }
} }
return null; return null;
} }
private String resolveFishDictCode(String name) { @Override
public String resolveStationCode(String code, String stationName) {
if (code == null && stationName == null) {
return null;
}
loadStationAndBaseCache();
String lowerCode = code != null ? code.trim().toLowerCase() : null;
String lowerName = stationName != null ? stationName.trim().toLowerCase() : null;
if (lowerCode != null && lowerName != null) {
String cachedName = STATION_CODE_TO_NAME_CACHE.get(lowerCode);
if (cachedName != null && cachedName.equals(lowerName)) {
return code.trim();
}
}
String resultByName = resolveStationCode(stationName);
if (resultByName != null && resultByName.equalsIgnoreCase(code)) {
return resultByName;
}
return null;
}
@Override
public String resolveFpssCode(String code, String name) {
if (code == null && name == null) {
return null;
}
loadStationAndBaseCache();
String lowerCode = code != null ? code.trim().toLowerCase() : null;
String lowerName = name != null ? name.trim().toLowerCase() : null;
if (lowerCode != null && lowerName != null) {
String cachedName = FPSS_CODE_TO_NAME_CACHE.get(lowerCode);
if (cachedName != null && cachedName.equals(lowerName)) {
return code.trim();
}
}
String resultByName = resolveFpssCode(name);
if (resultByName != null && resultByName.equalsIgnoreCase(code)) {
return resultByName;
}
return null;
}
public String resolveFishDictCode(String name) {
if (name == null) { if (name == null) {
return null; return null;
} }
@ -473,7 +604,28 @@ public class FishImportServiceImpl implements IFishImportService {
return null; return null;
} }
private String resolveBaseCode(String baseName) { @Override
public String resolveFishDictCode(String code, String name) {
if (code == null && name == null) {
return null;
}
loadStationAndBaseCache();
String lowerCode = code != null ? code.trim().toLowerCase() : null;
String lowerName = name != null ? name.trim().toLowerCase() : null;
if (lowerCode != null && lowerName != null) {
String cachedName = FISH_CODE_TO_NAME_CACHE.get(lowerCode);
if (cachedName != null && cachedName.equals(lowerName)) {
return code.trim();
}
}
String resultByName = resolveFishDictCode(name);
if (resultByName != null && resultByName.equalsIgnoreCase(code)) {
return resultByName;
}
return null;
}
public String resolveBaseCode(String baseName) {
if (baseName == null) { if (baseName == null) {
return null; return null;
} }
@ -482,14 +634,35 @@ public class FishImportServiceImpl implements IFishImportService {
return BASE_NAME_CACHE.get(lowerName); return BASE_NAME_CACHE.get(lowerName);
} }
for (Map.Entry<String, String> entry : BASE_NAME_CACHE.entrySet()) { for (Map.Entry<String, String> entry : BASE_NAME_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) { if (entry.getKey().contains(lowerName)) {
return entry.getValue(); return entry.getValue();
} }
} }
return null; return null;
} }
private String resolveRiverCode(String riverName) { @Override
public String resolveBaseCode(String code, String baseName) {
if (code == null && baseName == null) {
return null;
}
loadStationAndBaseCache();
String lowerCode = code != null ? code.trim().toLowerCase() : null;
String lowerName = baseName != null ? baseName.trim().toLowerCase() : null;
if (lowerCode != null && lowerName != null) {
String cachedName = BASE_CODE_TO_NAME_CACHE.get(lowerCode);
if (cachedName != null && cachedName.equals(lowerName)) {
return code.trim();
}
}
String resultByName = resolveBaseCode(baseName);
if (resultByName != null && resultByName.equalsIgnoreCase(code)) {
return resultByName;
}
return null;
}
public String resolveRiverCode(String riverName) {
if (riverName == null) { if (riverName == null) {
return null; return null;
} }
@ -498,13 +671,56 @@ public class FishImportServiceImpl implements IFishImportService {
return RIVER_NAME_CACHE.get(lowerName); return RIVER_NAME_CACHE.get(lowerName);
} }
for (Map.Entry<String, String> entry : RIVER_NAME_CACHE.entrySet()) { for (Map.Entry<String, String> entry : RIVER_NAME_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) { if (entry.getKey().contains(lowerName)) {
return entry.getValue(); return entry.getValue();
} }
} }
return null; return null;
} }
@Override
public String resolveRiverCode(String code, String riverName) {
if (code == null && riverName == null) {
return null;
}
loadStationAndBaseCache();
String lowerCode = code != null ? code.trim().toLowerCase() : null;
String lowerName = riverName != null ? riverName.trim().toLowerCase() : null;
if (lowerCode != null && lowerName != null) {
String cachedName = RIVER_CODE_TO_NAME_CACHE.get(lowerCode);
if (cachedName != null && cachedName.equals(lowerName)) {
return code.trim();
}
}
String resultByName = resolveRiverCode(riverName);
if (resultByName != null && resultByName.equalsIgnoreCase(code)) {
return resultByName;
}
return null;
}
@Override
public boolean validateStationBelongsToBase(String stationCode, String baseId) {
if (stationCode == null || baseId == null) {
return false;
}
loadStationAndBaseCache();
String stationLower = stationCode.trim().toLowerCase();
String cachedBaseId = STATION_TO_BASE_CACHE.get(stationLower);
return baseId.equalsIgnoreCase(cachedBaseId);
}
@Override
public boolean validateFpssBelongsToStation(String fpssCode, String stationCode) {
if (fpssCode == null || stationCode == null) {
return false;
}
loadStationAndBaseCache();
String fpssLower = fpssCode.trim().toLowerCase();
String cachedStationCode = FPSS_TO_STATION_CACHE.get(fpssLower);
return stationCode.equalsIgnoreCase(cachedStationCode);
}
private String validateFishType(String fishName, FishImportResult.FishImportRow importRow) { private String validateFishType(String fishName, FishImportResult.FishImportRow importRow) {
if (fishName == null) { if (fishName == null) {
return null; return null;
@ -536,7 +752,7 @@ public class FishImportServiceImpl implements IFishImportService {
return facilityName; return facilityName;
} }
private String resolveDirection(String direction, FishImportResult.FishImportRow importRow) { public String resolveDirection(String direction, FishImportResult.FishImportRow importRow) {
if (direction == null) { if (direction == null) {
return null; return null;
} }
@ -555,7 +771,7 @@ public class FishImportServiceImpl implements IFishImportService {
return direction; return direction;
} }
private String resolveIsfs(String value, FishImportResult.FishImportRow importRow) { public String resolveIsfs(String value, FishImportResult.FishImportRow importRow) {
if (value == null) { if (value == null) {
return null; return null;
} }
@ -697,6 +913,7 @@ public class FishImportServiceImpl implements IFishImportService {
/** /**
* 解析 BigDecimal 类型数据 * 解析 BigDecimal 类型数据
*
* @param value 字符串数值 * @param value 字符串数值
* @return BigDecimal 对象解析失败或为空时返回 null * @return BigDecimal 对象解析失败或为空时返回 null
*/ */
@ -712,7 +929,7 @@ public class FishImportServiceImpl implements IFishImportService {
} }
private String parseSourceType(String value) { public String parseSourceType(String value) {
if (!StringUtils.hasText(value)) { if (!StringUtils.hasText(value)) {
return "IMPORT"; return "IMPORT";
} }
@ -732,6 +949,7 @@ public class FishImportServiceImpl implements IFishImportService {
FishImportResult result = new FishImportResult(); FishImportResult result = new FishImportResult();
try { try {
log.info("开始解析ZIP文件...");
ZipFileUtil.ZipContent zipContent = ZipFileUtil.extractZipToTemp(file); ZipFileUtil.ZipContent zipContent = ZipFileUtil.extractZipToTemp(file);
if (zipContent.excelFilePath == null) { if (zipContent.excelFilePath == null) {
@ -739,22 +957,23 @@ public class FishImportServiceImpl implements IFishImportService {
ZipFileUtil.cleanupTempDir(zipContent.tempDir); ZipFileUtil.cleanupTempDir(zipContent.tempDir);
return result; return result;
} }
result.setTempDir(zipContent.tempDir);
result.setImageFiles(zipContent.images);
result.setVideoFiles(zipContent.videos);
try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) { try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) {
Sheet sheet = workbook.getSheetAt(0); Sheet sheet = workbook.getSheetAt(0);
result = parseSheet(sheet, result); result = parseSheet(sheet, result);
} }
result.setImageFiles(zipContent.images);
result.setVideoFiles(zipContent.videos);
result.setTempDir(zipContent.tempDir);
result.setExcelFileName(zipContent.excelFileName); result.setExcelFileName(zipContent.excelFileName);
result.setExcelFilePath(zipContent.excelFilePath); result.setExcelFilePath(zipContent.excelFilePath);
// result.setVideos(zipContent.videos);
processAttachments(result, zipContent); // result.setImages(zipContent.images);
log.info("ZIP文件解析完成");
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s", // processAttachments(result, zipContent);
zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir)); //
// log.info("ZIP文件处理完成");
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频",
zipContent.images.size(), zipContent.videos.size()));
return result; return result;
@ -766,28 +985,9 @@ public class FishImportServiceImpl implements IFishImportService {
} }
} }
private void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) { @Override
for (FishImportResult.FishImportRow importRow : result.getFailedRows()) { public void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) {
FishDraftData data = importRow.getData(); for (FishImportResult.FishImportRow importRow : result.getRows()) {
if (data == null) {
continue;
}
String vdpth = data.getVdpth();
String picpth = data.getPicpth();
if (StringUtils.hasText(vdpth)) {
String uploadedVdpth = processVideoAttachments(importRow,vdpth, zipContent.videos);
data.setVdpth(uploadedVdpth);
}
if (StringUtils.hasText(picpth)) {
String uploadedPicpth = processImageAttachments(importRow,picpth, zipContent.images);
data.setPicpth(uploadedPicpth);
}
}
for (FishImportResult.FishImportRow importRow : result.getSuccessRows()) {
FishDraftData data = importRow.getData(); FishDraftData data = importRow.getData();
if (data == null) { if (data == null) {
continue; continue;

View File

@ -1,10 +1,15 @@
package com.yfd.platform.data.service.impl; package com.yfd.platform.data.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yfd.platform.data.domain.FishImportResult;
import com.yfd.platform.data.domain.ImportTask; import com.yfd.platform.data.domain.ImportTask;
import com.yfd.platform.data.mapper.ImportTaskMapper; import com.yfd.platform.data.mapper.ImportTaskMapper;
import com.yfd.platform.data.service.AttachmentUploadService;
import com.yfd.platform.data.service.IImportTaskService; import com.yfd.platform.data.service.IImportTaskService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,6 +30,12 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
@Resource @Resource
private ImportTaskMapper importTaskMapper; private ImportTaskMapper importTaskMapper;
@Resource
private ObjectMapper objectMapper;
@Resource
AttachmentUploadService attachmentUploadService;
@Override @Override
public Page<ImportTask> queryPageList(Page<ImportTask> page, String bizType, String status, String uploadUserId) { public Page<ImportTask> queryPageList(Page<ImportTask> page, String bizType, String status, String uploadUserId) {
return this.page(page, this.lambdaQuery() return this.page(page, this.lambdaQuery()
@ -125,7 +136,21 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
} }
importTask.setStatus("CONFIRMED"); importTask.setStatus("CONFIRMED");
importTask.setUpdatedAt(new Date()); importTask.setUpdatedAt(new Date());
return this.updateById(importTask); boolean b = this.updateById(importTask);
// 删除本地临时目录数据
String resultJson = importTask.getResultJson();
if (resultJson != null && !resultJson.isEmpty()) {
try {
FishImportResult importResult = objectMapper.readValue(resultJson, FishImportResult.class);
String tempDir = importResult.getTempDir();
// del 方法会递归删除目录及其所有内容
FileUtil.del(tempDir);
} catch (Exception e) {
e.printStackTrace();
// ignore parse error
}
}
return b;
} }
@Override @Override
@ -157,6 +182,32 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
if ("CONFIRMED".equals(currentStatus) || "FAILED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) { if ("CONFIRMED".equals(currentStatus) || "FAILED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) {
return false; return false;
} }
if (importTask.getResultJson() != null && !importTask.getResultJson().isEmpty()) {
try {
FishImportResult importResult = objectMapper.readValue(importTask.getResultJson(), FishImportResult.class);
for (FishImportResult.FishImportRow successRow : importResult.getRows()) {
if (successRow.getData()==null) {
continue;
}
String vdpth = successRow.getData().getVdpth();
if (StringUtils.hasText(vdpth)) {
List<String> fileIds = StrUtil.split(vdpth, ",");
fileIds.forEach(fileId -> attachmentUploadService.deleteFile(fileId));
}
String picpth = successRow.getData().getPicpth();
if (StringUtils.hasText(picpth)) {
List<String> fileIds = StrUtil.split(vdpth, ",");
fileIds.forEach(fileId -> attachmentUploadService.deleteFile(fileId));
}
}
String tempDir = importResult.getTempDir();
// del 方法会递归删除目录及其所有内容
FileUtil.del(tempDir);
} catch (Exception e) {
e.printStackTrace();
// ignore parse error
}
}
importTask.setStatus("CANCELLED"); importTask.setStatus("CANCELLED");
importTask.setErrorMsg("用户取消: " + operatorId); importTask.setErrorMsg("用户取消: " + operatorId);
importTask.setUpdatedAt(new Date()); importTask.setUpdatedAt(new Date());

View File

@ -1,5 +1,6 @@
package com.yfd.platform.data.utils; package com.yfd.platform.data.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -18,6 +19,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@Component @Component
@Slf4j
public class ZipFileUtil { public class ZipFileUtil {
private static String tempBaseDir; private static String tempBaseDir;
@ -35,9 +37,9 @@ public class ZipFileUtil {
} }
String os = System.getProperty("os.name").toLowerCase(); String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) { if (os.contains("win")) {
return "D:\\zip_import_temp"; return "D:\\qgc-platform\\zip_import_temp";
} else { } else {
return "/tmp/zip_import_temp"; return "/qgc-platform/tmp/zip_import_temp";
} }
} }
@ -76,14 +78,17 @@ public class ZipFileUtil {
String taskId = UUID.randomUUID().toString().substring(0, 8); String taskId = UUID.randomUUID().toString().substring(0, 8);
Path tempDirPath = Paths.get(baseTempDir, "zip_" + taskId); Path tempDirPath = Paths.get(baseTempDir, "zip_" + taskId);
log.info("extractZipToTemp: {}", tempDirPath);
Files.createDirectories(tempDirPath); Files.createDirectories(tempDirPath);
content.tempDir = tempDirPath.toString(); content.tempDir = tempDirPath.toString();
File zipFile = new File(tempDirPath.toFile(), "upload.zip"); File zipFile = new File(tempDirPath.toFile(), "upload.zip");
file.transferTo(zipFile); file.transferTo(zipFile);
try { try {
log.info("--------------isValidZipFile------------");
if (!isValidZipFile(zipFile)) { if (!isValidZipFile(zipFile)) {
log.info("--------------文件不是有效的ZIP格式或已损坏------------");
throw new IOException("文件不是有效的ZIP格式或已损坏"); throw new IOException("文件不是有效的ZIP格式或已损坏");
} }
@ -107,6 +112,7 @@ public class ZipFileUtil {
} }
} }
log.error("extractZipToTemp: {}", lastException.getMessage());
throw lastException != null ? lastException : new IOException("无法解析ZIP文件"); throw lastException != null ? lastException : new IOException("无法解析ZIP文件");
} finally { } finally {

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.env.domain.SdEngInfoBH; import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.domain.SdEngInfoBHRequest;
import com.yfd.platform.env.service.ISdEngInfoBHService; import com.yfd.platform.env.service.ISdEngInfoBHService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -69,18 +70,16 @@ public class SdEngInfoBHController {
return ResponseResult.successData(engInfoBHService.getByRvcd(rvcd)); return ResponseResult.successData(engInfoBHService.getByRvcd(rvcd));
} }
@GetMapping("/dropdown") @PostMapping("/dropdown")
@Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)") @Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)")
public ResponseResult dropdown(@RequestParam(required = false) String baseId, public ResponseResult dropdown(@RequestBody SdEngInfoBHRequest sdEngInfoBHRequest) {
@RequestParam(required = false) String ennm) { return ResponseResult.successData(engInfoBHService.selectForDropdown(sdEngInfoBHRequest));
return ResponseResult.successData(engInfoBHService.selectForDropdown(baseId, ennm));
} }
@GetMapping("/regDropdown") @PostMapping("/regDropdown")
@Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)注册") @Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)注册")
public ResponseResult regDropdown(@RequestParam(required = false) String baseId, public ResponseResult regDropdown(@RequestBody SdEngInfoBHRequest sdEngInfoBHRequest) {
@RequestParam(required = false) String ennm) { return ResponseResult.successData(engInfoBHService.selectRegDropdown(sdEngInfoBHRequest));
return ResponseResult.successData(engInfoBHService.selectRegDropdown(baseId, ennm));
} }
@Log(module = "电站管理", value = "新增电站") @Log(module = "电站管理", value = "新增电站")

View File

@ -1,6 +1,7 @@
package com.yfd.platform.env.controller; package com.yfd.platform.env.controller;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
@ -55,8 +56,8 @@ public class SdFishDictoryBController {
@Operation(summary = "根据名称查询所有鱼类字典") @Operation(summary = "根据名称查询所有鱼类字典")
public ResponseResult listByName(@RequestParam(required = false) String name) { public ResponseResult listByName(@RequestParam(required = false) String name) {
return ResponseResult.successData(sdFishDictoryBService.list( return ResponseResult.successData(sdFishDictoryBService.list(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SdFishDictoryB>() new LambdaQueryWrapper<SdFishDictoryB>()
.eq(StrUtil.isNotBlank(name), SdFishDictoryB::getName, name) .eq(StrUtil.isNotBlank(name), SdFishDictoryB::getName, name).select(SdFishDictoryB::getId, SdFishDictoryB::getName, SdFishDictoryB::getAlias)
)); ));
} }
@ -89,4 +90,12 @@ public class SdFishDictoryBController {
boolean result = sdFishDictoryBService.deleteById(id); boolean result = sdFishDictoryBService.deleteById(id);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
} }
@GetMapping("/similar")
@Operation(summary = "查询相似鱼类列表")
public ResponseResult findSimilarFish(
@RequestParam String name,
@RequestParam(required = false, defaultValue = "10") Integer limit) {
return ResponseResult.successData(sdFishDictoryBService.findSimilarFish(name, limit));
}
} }

View File

@ -106,7 +106,7 @@ public class SdHbrvDicController {
} }
@GetMapping("/regDropdown") @GetMapping("/regDropdown")
@Operation(summary = "下拉框列表查询") @Operation(summary = "下拉框列表查询(注册)")
public ResponseResult regDropdown( public ResponseResult regDropdown(
@RequestParam(required = false) String hbrvnm, @RequestParam(required = false) String hbrvnm,
@RequestParam(required = false) String baseid) { @RequestParam(required = false) String baseid) {

View File

@ -66,16 +66,20 @@ public class SdHycdDicController {
@Operation(summary = "下拉框列表查询") @Operation(summary = "下拉框列表查询")
public ResponseResult selectForDropdown( public ResponseResult selectForDropdown(
@RequestParam(required = false) String hynm, @RequestParam(required = false) String hynm,
@RequestParam(required = false) Integer grd) { @RequestParam(required = false) Integer grd,
return ResponseResult.successData(hycdDicService.selectForDropdown(hynm, grd)); @RequestParam(required = false) Integer lx,
@RequestParam(required = false) String phycd) {
return ResponseResult.successData(hycdDicService.selectForDropdown(hynm, grd,lx,phycd));
} }
@GetMapping("/regDropdown") @GetMapping("/regDropdown")
@Operation(summary = "下拉框列表查询(注册)") @Operation(summary = "下拉框列表查询(注册)")
public ResponseResult regDropdown( public ResponseResult regDropdown(
@RequestParam(required = false) String hynm, @RequestParam(required = false) String hynm,
@RequestParam(required = false) Integer grd) { @RequestParam(required = false) Integer grd,
return ResponseResult.successData(hycdDicService.regDropdown(hynm, grd)); @RequestParam(required = false) Integer lx,
@RequestParam(required = false) String phycd) {
return ResponseResult.successData(hycdDicService.regDropdown(hynm, grd,lx,phycd));
} }

View File

@ -0,0 +1,18 @@
package com.yfd.platform.env.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SdEngInfoBHRequest {
private String baseId;
private List<String> basIds;
private List<String> hbrvcds;
private List<String> rvcds;
private String ennm;
}

View File

@ -228,7 +228,7 @@ public class SdFpssBH implements Serializable {
/** /**
* 鱼道或仿自然通道-流速单位m/s * 鱼道或仿自然通道-流速单位m/s
*/ */
private BigDecimal v; private String v;
/** /**
* 仿自然通道断面形状 * 仿自然通道断面形状
@ -293,7 +293,7 @@ public class SdFpssBH implements Serializable {
/** /**
* 升鱼机集鱼槽流量单位m3/s * 升鱼机集鱼槽流量单位m3/s
*/ */
private BigDecimal syjq; private String syjq;
/** /**
* 升鱼机断面尺寸**单位m * 升鱼机断面尺寸**单位m
@ -303,7 +303,7 @@ public class SdFpssBH implements Serializable {
/** /**
* 升鱼机集鱼槽水深单位m * 升鱼机集鱼槽水深单位m
*/ */
private BigDecimal syjwdp; private String syjwdp;
/** /**
* 设计过鱼规模单位 * 设计过鱼规模单位

View File

@ -49,15 +49,6 @@ public class SdHycdDic implements Serializable {
*/ */
private Integer orderIndex; private Integer orderIndex;
/**
* 中心经度
*/
private String lgtd;
/**
* 中心纬度
*/
private String lttd;
/** /**
* 所属国家关联SD_COUNTRY_B.COUNTRY_ID * 所属国家关联SD_COUNTRY_B.COUNTRY_ID
@ -72,7 +63,7 @@ public class SdHycdDic implements Serializable {
/** /**
* 简介 * 简介
*/ */
private String des; private String introduce;
/** /**
* 介绍图片 * 介绍图片
@ -87,6 +78,6 @@ public class SdHycdDic implements Serializable {
/** /**
* 类型 1集团 2:公司 * 类型 1集团 2:公司
*/ */
private String lx; private Integer lx;
} }

View File

@ -3,6 +3,7 @@ package com.yfd.platform.env.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.env.domain.SdEngInfoBH; import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.domain.SdEngInfoBHRequest;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -37,7 +38,7 @@ public interface ISdEngInfoBHService extends IService<SdEngInfoBH> {
/** /**
* 电站下拉列表根据基地编码筛选 + 支持名称模糊搜索 * 电站下拉列表根据基地编码筛选 + 支持名称模糊搜索
*/ */
List<SdEngInfoBH> selectForDropdown(String baseId, String ennm); List<SdEngInfoBH> selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest);
Set<String> getUserAuthorizedStationCodes(); Set<String> getUserAuthorizedStationCodes();
@ -56,5 +57,5 @@ public interface ISdEngInfoBHService extends IService<SdEngInfoBH> {
*/ */
boolean deleteEngInfo(String stcd); boolean deleteEngInfo(String stcd);
List<SdEngInfoBH> selectRegDropdown(String baseId, String ennm); List<SdEngInfoBH> selectRegDropdown(SdEngInfoBHRequest sdEngInfoBHRequest);
} }

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.env.domain.SdFishDictoryB; import com.yfd.platform.env.domain.SdFishDictoryB;
import java.util.List;
public interface ISdFishDictoryBService extends IService<SdFishDictoryB> { public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
Page<SdFishDictoryB> selectPage(String name, String code, Integer type, Integer rare, Page<SdFishDictoryB> page); Page<SdFishDictoryB> selectPage(String name, String code, Integer type, Integer rare, Page<SdFishDictoryB> page);
@ -15,4 +17,6 @@ public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
boolean deleteById(String id); boolean deleteById(String id);
SdFishDictoryB getById(String id); SdFishDictoryB getById(String id);
List<SdFishDictoryB> findSimilarFish(String name, Integer limit);
} }

View File

@ -46,7 +46,7 @@ public interface ISdHycdDicService extends IService<SdHycdDic> {
/** /**
* 下拉框列表查询支持名称和级别过滤 * 下拉框列表查询支持名称和级别过滤
*/ */
List<SdHycdDic> selectForDropdown(String hynm, Integer grd); List<SdHycdDic> selectForDropdown(String hynm, Integer grd,Integer lx,String phycd);
List<SdHycdDic> regDropdown(String hynm, Integer grd); List<SdHycdDic> regDropdown(String hynm, Integer grd,Integer lx,String phycd);
} }

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.data.domain.SysUserDataScope; import com.yfd.platform.data.domain.SysUserDataScope;
import com.yfd.platform.data.mapper.SysUserDataScopeMapper; import com.yfd.platform.data.mapper.SysUserDataScopeMapper;
import com.yfd.platform.env.domain.SdEngInfoBH; import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.domain.SdEngInfoBHRequest;
import com.yfd.platform.env.mapper.SdEngInfoBHMapper; import com.yfd.platform.env.mapper.SdEngInfoBHMapper;
import com.yfd.platform.env.service.ISdEngInfoBHService; import com.yfd.platform.env.service.ISdEngInfoBHService;
import com.yfd.platform.utils.SecurityUtils; import com.yfd.platform.utils.SecurityUtils;
@ -65,9 +66,15 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
} }
@Override @Override
public List<SdEngInfoBH> selectForDropdown(String baseId, String ennm) { public List<SdEngInfoBH> selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) {
String baseId = sdEngInfoBHRequest.getBaseId();
String ennm = sdEngInfoBHRequest.getEnnm();
List<String> rvcds = sdEngInfoBHRequest.getRvcds();
List<String> hbrvcds = sdEngInfoBHRequest.getHbrvcds();
LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId) wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId)
.in(rvcds != null && !rvcds.isEmpty(), SdEngInfoBH::getRvcd, rvcds)
.in(hbrvcds != null && !hbrvcds.isEmpty(), SdEngInfoBH::getHbrvcd, hbrvcds)
.like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm) .like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId) .select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getOrderIndex); .orderByAsc(SdEngInfoBH::getOrderIndex);
@ -143,9 +150,15 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
} }
@Override @Override
public List<SdEngInfoBH> selectRegDropdown(String baseId, String ennm) { public List<SdEngInfoBH> selectRegDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) {
String baseId = sdEngInfoBHRequest.getBaseId();
String ennm = sdEngInfoBHRequest.getEnnm();
List<String> rvcds = sdEngInfoBHRequest.getRvcds();
List<String> hbrvcds = sdEngInfoBHRequest.getHbrvcds();
LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId) wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId)
.in(rvcds != null && !rvcds.isEmpty(), SdEngInfoBH::getRvcd, rvcds)
.in(hbrvcds != null && !hbrvcds.isEmpty(), SdEngInfoBH::getHbrvcd, hbrvcds)
.like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm) .like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId) .select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getOrderIndex); .orderByAsc(SdEngInfoBH::getOrderIndex);

View File

@ -1,5 +1,6 @@
package com.yfd.platform.env.service.impl; package com.yfd.platform.env.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -9,6 +10,9 @@ import com.yfd.platform.env.service.ISdFishDictoryBService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
@Service @Service
public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper, SdFishDictoryB> implements ISdFishDictoryBService { public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper, SdFishDictoryB> implements ISdFishDictoryBService {
@ -62,4 +66,146 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper,
.eq(SdFishDictoryB::getIsDeleted, 0); .eq(SdFishDictoryB::getIsDeleted, 0);
return getOne(wrapper); return getOne(wrapper);
} }
@Override
public List<SdFishDictoryB> findSimilarFish(String name, Integer limit) {
if (!StringUtils.hasText(name)) {
return Collections.emptyList();
}
int resultLimit = (limit != null && limit > 0) ? limit : 10;
String searchName = name.trim();
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFishDictoryB::getIsDeleted, 0);
List<SdFishDictoryB> allFish = list(wrapper);
SdFishDictoryB exactMatch = allFish.stream()
.filter(f -> f.getName() != null && f.getName().equals(searchName))
.findFirst()
.orElse(null);
if (exactMatch != null) {
Map<SdFishDictoryB, Integer> similarityMap = new HashMap<>();
for (SdFishDictoryB fish : allFish) {
if (fish.getId().equals(exactMatch.getId())) {
continue;
}
int score = calculateSimilarity(exactMatch, fish);
if (score > 0) {
similarityMap.put(fish, score);
}
}
List<SdFishDictoryB> result = similarityMap.entrySet().stream()
.sorted(Map.Entry.<SdFishDictoryB, Integer>comparingByValue().reversed())
.limit(resultLimit)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
result.add(0, exactMatch);
return result;
}
List<SdFishDictoryB> containsMatches = allFish.stream()
.filter(f -> f.getName() != null && f.getName().contains(searchName))
.collect(Collectors.toList());
if (!containsMatches.isEmpty()) {
List<SdFishDictoryB> result = containsMatches.stream()
.sorted((f1, f2) -> {
int len1 = f1.getName().length();
int len2 = f2.getName().length();
if (len1 != len2) {
return Integer.compare(len1, len2);
}
return f1.getName().compareTo(f2.getName());
})
.limit(resultLimit)
.collect(Collectors.toList());
return result;
}
SdFishDictoryB partialMatch = allFish.stream()
.filter(f -> f.getName() != null && (searchName.contains(f.getName()) || f.getName().contains(searchName)))
.findFirst()
.orElse(null);
if (partialMatch != null) {
Map<SdFishDictoryB, Integer> similarityMap = new HashMap<>();
for (SdFishDictoryB fish : allFish) {
if (fish.getId().equals(partialMatch.getId())) {
continue;
}
int score = calculateSimilarity(partialMatch, fish);
if (score > 0) {
similarityMap.put(fish, score);
}
}
List<SdFishDictoryB> result = similarityMap.entrySet().stream()
.sorted(Map.Entry.<SdFishDictoryB, Integer>comparingByValue().reversed())
.limit(resultLimit)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
result.add(0, partialMatch);
return result;
}
return Collections.emptyList();
}
private int calculateSimilarity(SdFishDictoryB ref, SdFishDictoryB target) {
int score = 0;
if (ref.getGenus() != null && ref.getGenus().equals(target.getGenus()) && !ref.getGenus().isEmpty()) {
score += 25;
}
if (ref.getSpecies() != null && ref.getSpecies().equals(target.getSpecies()) && !ref.getSpecies().isEmpty()) {
score += 20;
}
if (ref.getFamily() != null && ref.getFamily().equals(target.getFamily()) && !ref.getFamily().isEmpty()) {
score += 15;
}
if (ref.getOrders() != null && ref.getOrders().equals(target.getOrders()) && !ref.getOrders().isEmpty()) {
score += 10;
}
if (ref.getType() != null && ref.getType().equals(target.getType()) && !ObjectUtil.isEmpty(ref.getType()) ) {
score += 5;
}
if (ref.getHabitat() != null && ref.getHabitat().equals(target.getHabitat()) && !ObjectUtil.isEmpty(ref.getHabitat())) {
score += 5;
}
if (ref.getHabitMigrat() != null && ref.getHabitMigrat().equals(target.getHabitMigrat()) && !ref.getHabitMigrat().isEmpty()) {
score += 5;
}
if (ref.getFeedingHabit() != null && ref.getFeedingHabit().equals(target.getFeedingHabit()) && !ref.getFeedingHabit().isEmpty()) {
score += 3;
}
if (ref.getSpawnCharact() != null && ref.getSpawnCharact().equals(target.getSpawnCharact()) && !ref.getSpawnCharact().isEmpty()) {
score += 3;
}
if (ref.getPtype() != null && ref.getPtype().equals(target.getPtype()) && !ObjectUtil.isEmpty(ref.getPtype())) {
score += 2;
}
if (ref.getResourceType() != null && ref.getResourceType().equals(target.getResourceType()) && !ObjectUtil.isEmpty(ref.getResourceType())) {
score += 2;
}
if (ref.getRare() != null && ref.getRare().equals(target.getRare()) && !ObjectUtil.isEmpty(ref.getRare())) {
score += 2;
}
return score;
}
} }

View File

@ -58,19 +58,23 @@ public class SdHycdDicServiceImpl extends ServiceImpl<SdHycdDicMapper, SdHycdDic
} }
@Override @Override
public List<SdHycdDic> selectForDropdown(String hynm, Integer grd) { public List<SdHycdDic> selectForDropdown(String hynm, Integer grd, Integer lx,String phycd) {
return this.lambdaQuery() return this.lambdaQuery()
.like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm) .like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm)
.eq(phycd != null, SdHycdDic::getPhycd, phycd)
.eq(grd != null, SdHycdDic::getGrd, grd) .eq(grd != null, SdHycdDic::getGrd, grd)
.eq(lx != null, SdHycdDic::getLx, lx)
.orderByAsc(SdHycdDic::getOrderIndex) .orderByAsc(SdHycdDic::getOrderIndex)
.list(); .list();
} }
@Override @Override
public List<SdHycdDic> regDropdown(String hynm, Integer grd) { public List<SdHycdDic> regDropdown(String hynm, Integer grd,Integer lx,String phycd) {
return this.lambdaQuery() return this.lambdaQuery()
.like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm) .like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm)
.eq(phycd != null, SdHycdDic::getPhycd, phycd)
.eq(grd != null, SdHycdDic::getGrd, grd) .eq(grd != null, SdHycdDic::getGrd, grd)
.eq(lx != null, SdHycdDic::getLx, lx)
.orderByAsc(SdHycdDic::getOrderIndex) .orderByAsc(SdHycdDic::getOrderIndex)
.list(); .list();
} }

View File

@ -4,11 +4,18 @@ import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil; import cn.hutool.jwt.JWTUtil;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.WebConfig; import com.yfd.platform.config.WebConfig;
import com.yfd.platform.data.domain.SysUserDataScope;
import com.yfd.platform.data.service.ISysUserDataScopeService;
import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.service.ISdEngInfoBHService;
import com.yfd.platform.env.service.ISdHbrvDicService;
import com.yfd.platform.system.domain.*; import com.yfd.platform.system.domain.*;
import com.yfd.platform.system.mapper.SysMenuMapper;
import com.yfd.platform.system.service.ISmsVerifyCodeService; import com.yfd.platform.system.service.ISmsVerifyCodeService;
import com.yfd.platform.system.service.ISysLogService; import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService; import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder; import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.RsaUtils;
import com.yfd.platform.utils.StringUtils; import com.yfd.platform.utils.StringUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -19,12 +26,12 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Date; import java.util.*;
import java.util.HashMap; import java.util.stream.Collectors;
import java.util.Map;
/** /**
* <p> * <p>
@ -48,6 +55,18 @@ public class SmsVerifyCodeController {
@Resource @Resource
private ISysLogService sysLogService; private ISysLogService sysLogService;
@Resource
private SysMenuMapper sysMenuMapper;
@Resource
private ISysUserDataScopeService sysUserDataScopeService;
@Resource
private ISdEngInfoBHService engInfoBHService;
@Resource
private ISdHbrvDicService hbrvDicService;
@Value("${rsa.private_key}") @Value("${rsa.private_key}")
private String privateKey; private String privateKey;
@ -59,26 +78,42 @@ public class SmsVerifyCodeController {
public ResponseResult sendVerifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { public ResponseResult sendVerifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone(); String phone = smsVerifyCodeRequest.getPhone();
Integer type = smsVerifyCodeRequest.getType(); Integer type = smsVerifyCodeRequest.getType();
if (phone == null || phone.isEmpty()) { if (phone == null || phone.isEmpty()) {
return ResponseResult.error("手机号不能为空"); return ResponseResult.error("手机号不能为空");
} }
if (type == null || (!type.equals(SmsVerifyCode.TYPE_REGISTER) && !type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD))) { if (type == null) {
return ResponseResult.error("类型错误1-注册 2-找回密码"); return ResponseResult.error("类型不能为空1-注册 2-找回密码 3-登录");
} }
// 1. 注册验证码校验
if (type.equals(SmsVerifyCode.TYPE_REGISTER)) { if (type.equals(SmsVerifyCode.TYPE_REGISTER)) {
SysUser existUser = userService.getUserByPhone(phone); SysUser existUser = userService.getUserByPhone(phone);
if (existUser != null) { if (existUser != null) {
return ResponseResult.error("该手机号已注册"); return ResponseResult.error("该手机号已注册");
} }
} }
// 2. 找回密码验证码校验
if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) { else if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) {
SysUser existUser = userService.getUserByPhone(phone); SysUser existUser = userService.getUserByPhone(phone);
if (existUser == null) { if (existUser == null) {
return ResponseResult.error("该手机号未注册"); return ResponseResult.error("该手机号未注册");
} }
} }
// 3. 登录验证码校验新增
else if (type.equals(SmsVerifyCode.TYPE_LOGIN)) {
SysUser existUser = userService.getUserByPhone(phone);
if (existUser == null) {
return ResponseResult.error("该手机号未注册,请先注册");
}
// 可选如果用户状态异常如被禁用也可以在此处拦截
// if (existUser.getStatus() == 0) {
// return ResponseResult.error("账号已被禁用");
// }
}
else {
return ResponseResult.error("类型错误1-注册 2-找回密码 3-登录");
}
String code = smsVerifyCodeService.sendVerifyCode(phone, type); String code = smsVerifyCodeService.sendVerifyCode(phone, type);
if (code == null) { if (code == null) {
@ -88,51 +123,62 @@ public class SmsVerifyCodeController {
return ResponseResult.success(); return ResponseResult.success();
} }
/** /**
* 注册用户 * 注册用户
*/ */
@PostMapping("/register") @PostMapping("/register")
@Operation(summary = "注册用户") @Operation(summary = "注册用户")
@Transactional
public ResponseResult register(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { public ResponseResult register(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
SysUser user = smsVerifyCodeRequest.getUser();
String code = smsVerifyCodeRequest.getCode(); String code = smsVerifyCodeRequest.getCode();
if (user.getPhone() == null || user.getPhone().isEmpty()) { if (smsVerifyCodeRequest.getPhone() == null || smsVerifyCodeRequest.getPhone().isEmpty()) {
return ResponseResult.error("手机号不能为空"); return ResponseResult.error("手机号不能为空");
} }
if (user.getUsername() == null || user.getUsername().isEmpty()) { if (smsVerifyCodeRequest.getUsername() == null || smsVerifyCodeRequest.getUsername().isEmpty()) {
return ResponseResult.error("用户名不能为空"); return ResponseResult.error("用户名不能为空");
} }
if (user.getPassword() == null || user.getPassword().isEmpty()) { if (smsVerifyCodeRequest.getPassword() == null || smsVerifyCodeRequest.getPassword().isEmpty()) {
return ResponseResult.error("密码不能为空"); return ResponseResult.error("密码不能为空");
} }
if (code == null || code.isEmpty()) { if (code == null || code.isEmpty()) {
return ResponseResult.error("验证码不能为空"); return ResponseResult.error("验证码不能为空");
} }
boolean verified = smsVerifyCodeService.verifyCode(user.getPhone(), code, SmsVerifyCode.TYPE_REGISTER); boolean verified = smsVerifyCodeService.verifyCode(smsVerifyCodeRequest.getPhone(), code, SmsVerifyCode.TYPE_REGISTER);
if (!verified) { if (!verified) {
return ResponseResult.error("验证码错误或已过期"); return ResponseResult.error("验证码错误或已过期");
} }
SysUser existUser = userService.getUserByPhone(user.getPhone()); SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
if (existUser != null) { if (existUser != null) {
return ResponseResult.error("该手机号已注册"); return ResponseResult.error("该手机号已注册");
} }
SysUser user = new SysUser();
try { try {
com.yfd.platform.utils.RsaUtils.decryptByPrivateKey(privateKey, user.getPassword()); String password = RsaUtils.decryptByPrivateKey(privateKey, smsVerifyCodeRequest.getPassword());
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
user.setPassword(passwordEncoder.encode(password));
} catch (Exception e) { } catch (Exception e) {
return ResponseResult.error("密码解密失败"); return ResponseResult.error("密码解密失败");
} }
user.setRegStatus("PENDING");
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); user.setPhone(smsVerifyCodeRequest.getPhone());
user.setPassword(passwordEncoder.encode(user.getPassword())); user.setBelongingUnit(smsVerifyCodeRequest.getBelongingUnit());
user.setRegStatus(0);
user.setRegTime(new Date()); user.setRegTime(new Date());
user.setNickname(smsVerifyCodeRequest.getRealName());
user.setStatus(1); user.setStatus(1);
user.setOrgid("e90063ced25e3d469860e88d920c082f");
user.setUsertype(1); user.setUsertype(1);
user.setUsername(smsVerifyCodeRequest.getUsername());
user.setGroupCode(smsVerifyCodeRequest.getGroupCode());
user.setCompanyCode(smsVerifyCodeRequest.getCompanyCode());
boolean success = userService.save(user); boolean success = userService.save(user);
// 给注册用户加上默认权限
SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
if (savedUser != null) {
this.addDefaultRole(savedUser.getId(), smsVerifyCodeRequest);
}
if (success) { if (success) {
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
@ -140,6 +186,103 @@ public class SmsVerifyCodeController {
} }
} }
private boolean addDefaultRole(String userId, SmsVerifyCodeRequest smsVerifyCodeRequest) {
if (userId == null || userId.isEmpty()) {
return false;
}
String stationCode = smsVerifyCodeRequest.getStationCode();
String hbrvcdCode = smsVerifyCodeRequest.getHbrvcdCode();
Set<String> selectedStationCodes = new HashSet<>();
if (StringUtils.isNotEmpty(stationCode)) {
selectedStationCodes.addAll(Arrays.asList(stationCode.split(",")));
}
Set<String> selectedBasinCodes = new HashSet<>();
if (StringUtils.isNotEmpty(hbrvcdCode)) {
selectedBasinCodes.addAll(Arrays.asList(hbrvcdCode.split(",")));
}
Set<String> addedStationCodes = new HashSet<>();
for (String basinCode : selectedBasinCodes) {
if (StringUtils.isEmpty(basinCode)) {
continue;
}
List<SdEngInfoBH> allStationsInBasin = engInfoBHService.lambdaQuery()
.eq(SdEngInfoBH::getHbrvcd, basinCode)
.list();
if (allStationsInBasin == null || allStationsInBasin.isEmpty()) {
SysUserDataScope scope = new SysUserDataScope();
scope.setUserId(userId);
scope.setOrgType("HBRVCD");
scope.setOrgId(basinCode);
scope.setStatus(1);
scope.setPermissionType("READ");
sysUserDataScopeService.addDataScope(scope);
continue;
}
Set<String> allStationCodesInBasin = allStationsInBasin.stream()
.map(SdEngInfoBH::getStcd)
.collect(Collectors.toSet());
boolean allStationsSelected = allStationCodesInBasin.containsAll(selectedStationCodes)
&& selectedStationCodes.containsAll(allStationCodesInBasin);
if (allStationsSelected) {
SysUserDataScope scope = new SysUserDataScope();
scope.setUserId(userId);
scope.setOrgType("HBRVCD");
scope.setOrgId(basinCode);
scope.setStatus(1);
scope.setPermissionType("READ");
sysUserDataScopeService.addDataScope(scope);
addedStationCodes.add(basinCode);
} else {
Set<String> stationsInBasinAndSelected = allStationCodesInBasin.stream()
.filter(selectedStationCodes::contains)
.collect(Collectors.toSet());
for (String stationCd : stationsInBasinAndSelected) {
SysUserDataScope scope = new SysUserDataScope();
scope.setUserId(userId);
scope.setOrgType("STATION");
scope.setOrgId(stationCd);
scope.setStatus(1);
scope.setPermissionType("READ");
sysUserDataScopeService.addDataScope(scope);
addedStationCodes.add(stationCd);
}
}
}
Set<String> standaloneStations = selectedStationCodes.stream()
.filter(code -> !addedStationCodes.contains(code))
.collect(Collectors.toSet());
for (String stationCd : standaloneStations) {
if (StringUtils.isEmpty(stationCd)) {
continue;
}
SysUserDataScope scope = new SysUserDataScope();
scope.setUserId(userId);
scope.setOrgType("STATION");
scope.setOrgId(stationCd);
scope.setStatus(1);
scope.setPermissionType("READ");
sysUserDataScopeService.addDataScope(scope);
}
SysUser user = new SysUser();
user.setId(userId);
userService.updateUserRoles( user,"c13481a486c9ee559cf305284df4d207");
// 加上角色权限
return true;
}
/** /**
* 找回密码 * 找回密码
*/ */
@ -168,7 +311,11 @@ public class SmsVerifyCodeController {
if (existUser == null) { if (existUser == null) {
return ResponseResult.error("该手机号未注册"); return ResponseResult.error("该手机号未注册");
} }
try {
password = RsaUtils.decryptByPrivateKey(privateKey, smsVerifyCodeRequest.getPassword());
} catch (Exception e) {
return ResponseResult.error("密码解密失败");
}
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encryptedPassword = passwordEncoder.encode(password); String encryptedPassword = passwordEncoder.encode(password);
@ -183,7 +330,7 @@ public class SmsVerifyCodeController {
/** /**
* 验证验证码是否有效 * 验证验证码是否有效
*/ */
@GetMapping("/verifyCode") @PostMapping("/verifyCode")
@Operation(summary = "验证验证码") @Operation(summary = "验证验证码")
public ResponseResult verifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { public ResponseResult verifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone(); String phone = smsVerifyCodeRequest.getPhone();
@ -212,7 +359,7 @@ public class SmsVerifyCodeController {
return ResponseResult.error("验证码不能为空"); return ResponseResult.error("验证码不能为空");
} }
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_REGISTER); boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN);
if (!verified) { if (!verified) {
return ResponseResult.error("验证码错误或已过期"); return ResponseResult.error("验证码错误或已过期");
} }
@ -226,11 +373,11 @@ public class SmsVerifyCodeController {
return ResponseResult.error("账号已停用"); return ResponseResult.error("账号已停用");
} }
if (user.getRegStatus() != null && user.getRegStatus() == 0) { if (user.getRegStatus() != null && "PENDING".equals(user.getRegStatus())) {
return ResponseResult.error("账号待审核,请联系管理员"); return ResponseResult.error("账号待审核,请联系管理员");
} }
if (user.getRegStatus() != null && user.getRegStatus() == 2) { if (user.getRegStatus() != null && "REJECTED".equals(user.getRegStatus())) {
return ResponseResult.error("账号审核未通过"); return ResponseResult.error("账号审核未通过");
} }
@ -242,7 +389,10 @@ public class SmsVerifyCodeController {
LoginUser loginUser = new LoginUser(); LoginUser loginUser = new LoginUser();
loginUser.setUser(user); loginUser.setUser(user);
loginUser.setUsername(user.getUsername()); loginUser.setUsername(user.getUsername());
//Todo 根据用户查询权限信息 添加到LoginUser中
List<String> permissions =
sysMenuMapper.selectPermsByUserId(user.getId());
loginUser.setPermissions( permissions);
HttpServletRequest request = RequestHolder.getHttpServletRequest(); HttpServletRequest request = RequestHolder.getHttpServletRequest();
SysLog sysLog = new SysLog(); SysLog sysLog = new SysLog();
sysLog.setUsercode(user.getUsername()); sysLog.setUsercode(user.getUsername());
@ -275,7 +425,7 @@ public class SmsVerifyCodeController {
webConfig.loginuserCache().put("login:" + userId, jsonStr); webConfig.loginuserCache().put("login:" + userId, jsonStr);
webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString()); webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString());
map.put("user", user); // map.put("user", user);
return ResponseResult.successData(map); return ResponseResult.successData(map);
} }

View File

@ -6,6 +6,8 @@ import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.datasource.DataSource; import com.yfd.platform.datasource.DataSource;
import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.domain.SysUserRequest;
import com.yfd.platform.system.service.ISmsVerifyCodeService;
import com.yfd.platform.system.service.IUserService; import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -32,6 +34,9 @@ public class UserController {
@Resource @Resource
private IUserService userService; private IUserService userService;
@Resource
private ISmsVerifyCodeService smsVerifyCodeService;
@Log(module = "系统用户", value = "新增系统用户") @Log(module = "系统用户", value = "新增系统用户")
@PostMapping("/addUser") @PostMapping("/addUser")
@Operation(summary = "新增系统用户") @Operation(summary = "新增系统用户")
@ -58,6 +63,7 @@ public class UserController {
return ResponseResult.successData(reslut); return ResponseResult.successData(reslut);
} }
@GetMapping("/queryUsers") @GetMapping("/queryUsers")
@Operation(summary = "查询用户信息") @Operation(summary = "查询用户信息")
@ResponseBody @ResponseBody
@ -155,12 +161,7 @@ public class UserController {
if (StrUtil.isBlank(id)) { if (StrUtil.isBlank(id)) {
ResponseResult.error("参数为空"); ResponseResult.error("参数为空");
} }
boolean ok = userService.resetPassword(id); return userService.resetPassword(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
} }
/*********************************** /***********************************
@ -201,20 +202,27 @@ public class UserController {
return ResponseResult.success(); return ResponseResult.success();
} }
@Log(module = "系统用户", value = "审核用户注册") // @Log(module = "系统用户", value = "审核用户注册")
@PostMapping("/auditUser") @PostMapping("/auditUser")
@Operation(summary = "审核用户注册") @Operation(summary = "审核用户注册")
@ResponseBody @ResponseBody
public ResponseResult auditUser(@RequestParam String userId, public ResponseResult auditUser(@RequestBody SysUserRequest sysUserRequest) {
@RequestParam Integer auditStatus) { String userId = sysUserRequest.getUserId();
String auditStatus = sysUserRequest.getRegStatus();
if (userId == null || userId.isEmpty()) { if (userId == null || userId.isEmpty()) {
return ResponseResult.error("用户ID不能为空"); return ResponseResult.error("用户ID不能为空");
} }
if (auditStatus == null || (auditStatus != 1 && auditStatus != 2)) {
if (StrUtil.isBlank(auditStatus) || ( !"APPROVED".equals(auditStatus)&&!"REJECTED".equals(auditStatus))) {
return ResponseResult.error("审核状态错误1-通过 2-驳回"); return ResponseResult.error("审核状态错误1-通过 2-驳回");
} }
SysUser user = userService.getById(userId);
if (user == null) {
return ResponseResult.error("用户不存在");
}
boolean ok = userService.auditUser(userId, auditStatus); boolean ok = userService.auditUser(userId, auditStatus);
if (ok) { if (ok) {
smsVerifyCodeService.sendAuditNotify(user.getPhone(), auditStatus, sysUserRequest.getCommentInfo());
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
return ResponseResult.error("审核失败"); return ResponseResult.error("审核失败");
@ -224,8 +232,8 @@ public class UserController {
@GetMapping("/queryPendingAuditUsers") @GetMapping("/queryPendingAuditUsers")
@Operation(summary = "查询待审核用户列表") @Operation(summary = "查询待审核用户列表")
@ResponseBody @ResponseBody
public ResponseResult queryPendingAuditUsers(Page<SysUser> page) { public ResponseResult queryPendingAuditUsers(Page<SysUser> page,String name,String regStatus) {
Page<SysUser> result = userService.queryPendingAuditUsers(page); Page<SysUser> result = userService.queryPendingAuditUsers(page,name,regStatus);
return ResponseResult.successData(result); return ResponseResult.successData(result);
} }
} }

View File

@ -22,12 +22,18 @@ public class LoginUser implements UserDetails {
private String username; private String username;
private List<String> permissions; private List<String> permissions=new ArrayList<>();
/**
* 自定义构造函数如果需要特殊逻辑
*/
public LoginUser(SysUser user, List<String> permissions) { public LoginUser(SysUser user, List<String> permissions) {
this.user = user; this.user = user;
// 4. 增加非空判断确保 permissions 永远不为 null
if (permissions != null) {
this.permissions = permissions; this.permissions = permissions;
} }
}
@JSONField(serialize = false) @JSONField(serialize = false)
private List<SimpleGrantedAuthority> authorities; private List<SimpleGrantedAuthority> authorities;

View File

@ -23,6 +23,7 @@ public class SmsVerifyCode implements Serializable {
public static final Integer TYPE_REGISTER = 1; public static final Integer TYPE_REGISTER = 1;
public static final Integer TYPE_FIND_PASSWORD = 2; public static final Integer TYPE_FIND_PASSWORD = 2;
public static final Integer TYPE_LOGIN = 3;
public static final Integer STATUS_UNUSED = 0; public static final Integer STATUS_UNUSED = 0;
public static final Integer STATUS_USED = 1; public static final Integer STATUS_USED = 1;

View File

@ -19,20 +19,35 @@ public class SmsVerifyCodeRequest {
*/ */
private String code; private String code;
/**
* 用户名
*/
private String username;
private String realName;
private String belongingUnit;
/** /**
* 密码 * 密码
*/ */
private String password; private String password;
/** // /**
* 用户 // * 用户
*/ // */
private SysUser user; // private SysUser user;
/** /**
* 流域编号 * 流域编号
*/ */
private String rvcdCode; private String rvcdCode;
/**
* 流域编号
*/
private String hbrvcdCode;
/** /**
* 集团编号 * 集团编号
*/ */

View File

@ -122,15 +122,20 @@ public class SysUser implements Serializable {
private String realName; private String realName;
/** /**
* 注册状态0-待审核 1-已通过 2-已驳回 * 审批状态PENDING待审批 / APPROVED已通过 / REJECTED已驳回
*/ */
private Integer regStatus; private String regStatus;
/** /**
* 审核人ID * 审核人ID
*/ */
private String auditUser; private String auditUser;
/**
* 所属单位
*/
private String belongingUnit;
/** /**
* 审核时间 * 审核时间
*/ */
@ -141,6 +146,15 @@ public class SysUser implements Serializable {
*/ */
private Date regTime; private Date regTime;
/**
* 集团编号
*/
private String groupCode;
/**
* 公司编号
*/
private String companyCode;
@TableField(exist = false) @TableField(exist = false)
List<SysRole> roles; List<SysRole> roles;
} }

View File

@ -0,0 +1,34 @@
package com.yfd.platform.system.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysUserRequest {
/**
* 用户ID
*/
private String userId;
/**
* 用户ID
*/
private List<String> userIds;
/**
* 审核状态
*/
private String regStatus;
/**
* 审批意见
*/
private String commentInfo;
}

View File

@ -62,7 +62,7 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
* userid 用户id * userid 用户id
* 返回值说明: * 返回值说明:
************************************/ ************************************/
String getMaxLevel(@Param("userid") String userid); String getMaxLevel(@Param("userId") String userId);
/*********************************** /***********************************
* 用途说明根据用户id删除所分配的角色 * 用途说明根据用户id删除所分配的角色

View File

@ -37,4 +37,13 @@ public interface ISmsVerifyCodeService extends IService<SmsVerifyCode> {
* 生成6位数字验证码 * 生成6位数字验证码
*/ */
String generateCode(); String generateCode();
/**
* 发送审核结果通知短信
* @param phone 手机号
* @param auditStatus 审核状态 1-通过 2-驳回
* @param reason 驳回原因可选
* @return 是否发送成功
*/
boolean sendAuditNotify(String phone, String auditStatus, String reason);
} }

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.domain.SysUser;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File; import java.io.File;
@ -57,6 +58,9 @@ public interface IUserService extends IService<SysUser> {
List<Map> list(String total, String size, String orgid, String username, List<Map> list(String total, String size, String orgid, String username,
String mobile, String status); String mobile, String status);
@Transactional(rollbackFor = Exception.class)
Map updateUserRoles(SysUser sysUser, String roleids);
/*********************************** /***********************************
* 用途说明根据ID查询用户详情 * 用途说明根据ID查询用户详情
* 参数说明 * 参数说明
@ -97,7 +101,7 @@ public interface IUserService extends IService<SysUser> {
*id 重置密码的 用户id *id 重置密码的 用户id
* 返回值说明: 判断是否重置成功 * 返回值说明: 判断是否重置成功
************************************/ ************************************/
boolean resetPassword(String id) throws Exception; ResponseResult resetPassword(String id) throws Exception;
/*********************************** /***********************************
* 用途说明设置账号状态(管理员) * 用途说明设置账号状态(管理员)
@ -162,7 +166,7 @@ public interface IUserService extends IService<SysUser> {
* auditStatus 审核状态1-通过 2-驳回 * auditStatus 审核状态1-通过 2-驳回
* 返回值说明: 是否审核成功 * 返回值说明: 是否审核成功
************************************/ ************************************/
boolean auditUser(String userId, Integer auditStatus); boolean auditUser(String userId, String auditStatus);
/*********************************** /***********************************
* 用途说明查询待审核用户列表 * 用途说明查询待审核用户列表
@ -170,6 +174,6 @@ public interface IUserService extends IService<SysUser> {
*page 分页参数 *page 分页参数
* 返回值说明: 待审核用户分页列表 * 返回值说明: 待审核用户分页列表
************************************/ ************************************/
Page<SysUser> queryPendingAuditUsers(Page<SysUser> page); Page<SysUser> queryPendingAuditUsers(Page<SysUser> page,String name, String regStatus);
} }

View File

@ -21,7 +21,7 @@ import java.util.Random;
@Service @Service
public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, SmsVerifyCode> implements ISmsVerifyCodeService { public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, SmsVerifyCode> implements ISmsVerifyCodeService {
private static final int CODE_VALID_MINUTES = 1; private static final int CODE_VALID_MINUTES = 5;
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
@Resource @Resource
@ -96,4 +96,28 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
public String generateCode() { public String generateCode() {
return String.format("%06d", RANDOM.nextInt(1000000)); return String.format("%06d", RANDOM.nextInt(1000000));
} }
@Override
public boolean sendAuditNotify(String phone, String auditStatus, String reason) {
if (phone == null || phone.isEmpty()) {
return false;
}
String content;
if ("APPROVED".equals(auditStatus)) {
content = "您的数据填报系统账号已审核通过,现在可以正常登录系统了。";
} else if ("REJECTED".equals(auditStatus)) {
if (reason != null && !reason.isEmpty()) {
content = "您的数据填报系统账号审核未通过,原因:" + reason;
} else {
content = "您的数据填报系统账号审核未通过,请联系管理员。";
}
} else {
return false;
}
try {
return smsSender.send(phone, content);
} catch (Exception e) {
return false;
}
}
} }

View File

@ -1,25 +1,25 @@
package com.yfd.platform.system.service.impl; package com.yfd.platform.system.service.impl;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.config.FileProperties;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysOrganization;
import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysRole;
import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.domain.SysUser;
import com.yfd.platform.system.mapper.SysOrganizationMapper;
import com.yfd.platform.system.mapper.SysRoleMapper; import com.yfd.platform.system.mapper.SysRoleMapper;
import com.yfd.platform.system.mapper.SysUserMapper; import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.IUserService; import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.FileUtil; import com.yfd.platform.utils.FileUtil;
import com.yfd.platform.utils.PasswordGenerator;
import com.yfd.platform.utils.SecurityUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import com.yfd.platform.config.FileSpaceProperties; import com.yfd.platform.config.FileSpaceProperties;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -30,8 +30,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import java.io.File; import java.io.File;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
@ -269,6 +267,46 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
return result; return result;
} }
@Transactional(rollbackFor = Exception.class)
@Override
public Map updateUserRoles(SysUser sysUser, String roleids) {
Map<String, String> result = new HashMap<>();
try {
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
sysUser.setLastmodifydate(currentTime);
// 更新用户信息
boolean ok = this.updateById(sysUser);
if (!ok) {
result.put("status", "error");
result.put("msg", "用户信息修改失败!");
return result;
}
// 处理角色分配
String userId = sysUser.getId();
if (StrUtil.isNotEmpty(roleids)) {
handleUserRoles(userId, roleids);
} else {
// 清空所有角色
sysUserMapper.delRoleUsersByUserid(userId);
}
result.put("status", "sucess");
result.put("msg", "用户信息修改成功!");
} catch (Exception e) {
log.error("更新用户信息失败", e);
result.put("status", "error");
result.put("msg", "操作失败:" + e.getMessage());
throw e; // 抛出异常触发事务回滚
}
return result;
}
/** /**
* 处理用户角色分配增量更新 * 处理用户角色分配增量更新
* @param userId 用户 ID * @param userId 用户 ID
@ -281,7 +319,6 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
// 解析新角色列表 // 解析新角色列表
String[] newRoles = roleIds.split(","); String[] newRoles = roleIds.split(",");
Set<String> newRoleSet = new HashSet<>(Arrays.asList(newRoles));
// 需要新增的角色新角色 - 当前角色 // 需要新增的角色新角色 - 当前角色
for (String roleId : newRoles) { for (String roleId : newRoles) {
@ -295,9 +332,6 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
sysUserMapper.delInRoleUsersByUserid(userId, newRoles); sysUserMapper.delInRoleUsersByUserid(userId, newRoles);
} }
// ... existing code ...
@Override @Override
public Map getOneById(String id) { public Map getOneById(String id) {
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>(); QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
@ -392,17 +426,18 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
* 返回值说明: 判断是重置成功 * 返回值说明: 判断是重置成功
************************************/ ************************************/
@Override @Override
public boolean resetPassword(String id) throws Exception { public ResponseResult resetPassword(String id) throws Exception {
boolean isOk = false;
//根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id
String level = sysUserMapper.getMaxLevel(id); String level = sysUserMapper.getMaxLevel(id);
//判断是否获取级别 //判断是否获取级别
if (StrUtil.isNotEmpty(level)) { if ("admin".equals(SecurityUtils.getCurrentUsername())||StrUtil.isNotEmpty(level)) {
//判断当前用户级别 管理员及以上权限 //判断当前用户级别 管理员及以上权限
if (Integer.parseInt(level) <= 2) { if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) {
SysUser sysUser = sysUserMapper.selectById(id);
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername());
//根据id 修改密码密码修改时间最近修改者最近修改日期 将密码修改为 123456 //根据id 修改密码密码修改时间最近修改者最近修改日期 将密码修改为 123456
String cryptPassword = passwordEncoder.encode("123456"); String cryptPassword = passwordEncoder.encode(password);
updateWrapper.eq("id", id).set("password", cryptPassword).set( updateWrapper.eq("id", id).set("password", cryptPassword).set(
"pwdresettime", "pwdresettime",
new Timestamp(System.currentTimeMillis())).set( new Timestamp(System.currentTimeMillis())).set(
@ -410,10 +445,11 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
new Timestamp(System.currentTimeMillis())).set( new Timestamp(System.currentTimeMillis())).set(
"lastmodifier", getUsername()); "lastmodifier", getUsername());
//是否修改成功 //是否修改成功
isOk = this.update(updateWrapper); this.update(updateWrapper);
return ResponseResult.successData(password);
} }
} }
return isOk; return ResponseResult.error();
} }
/*********************************** /***********************************
@ -429,7 +465,7 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
//根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id
String level = sysUserMapper.getMaxLevel(id); String level = sysUserMapper.getMaxLevel(id);
//判断当前用户级别 管理员及以上权限 //判断当前用户级别 管理员及以上权限
if (Integer.parseInt(level) <= 2) { if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
//根据id修改用户状态最近修改人最近修改时间 //根据id修改用户状态最近修改人最近修改时间
updateWrapper.eq("id", id).set("status", status).set( updateWrapper.eq("id", id).set("status", status).set(
@ -515,7 +551,7 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
Page<SysUser> page) { Page<SysUser> page) {
Page<SysUser> mapPage = sysUserMapper.queryUsers(orgid, Page<SysUser> mapPage = sysUserMapper.queryUsers(orgid,
username, page); username, page);
;mapPage.getRecords().forEach(record -> { mapPage.getRecords().forEach(record -> {
String id = record.getId(); String id = record.getId();
List<SysRole> sysRoles = sysRoleMapper.getRoleByUserId(id); List<SysRole> sysRoles = sysRoleMapper.getRoleByUserId(id);
record.setRoles(sysRoles); record.setRoles(sysRoles);
@ -574,34 +610,45 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
updateWrapper.eq("phone", phone) updateWrapper.eq("phone", phone)
.set("password", encryptedPassword) .set("password", encryptedPassword)
.set("pwdresettime", new Timestamp(System.currentTimeMillis())) .set("pwdresettime", new Timestamp(System.currentTimeMillis()))
.set("lastmodifydate", new Timestamp(System.currentTimeMillis())) .set("lastmodifydate", new Timestamp(System.currentTimeMillis()));
.set("lastmodifier", getUsername());
return this.update(updateWrapper); return this.update(updateWrapper);
} }
@Override @Override
public boolean auditUser(String userId, Integer auditStatus) { public boolean auditUser(String userId, String auditStatus) {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(); LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq("id", userId) updateWrapper.eq(SysUser::getId, userId)
.set("reg_status", auditStatus) .set(SysUser::getRegStatus, auditStatus)
.set("audit_user", getUsername()) .set(SysUser::getAuditUser, SecurityUtils.getUserId())
.set("audit_time", new Timestamp(System.currentTimeMillis())) .set(SysUser::getAuditTime, new Timestamp(System.currentTimeMillis()))
.set("lastmodifydate", new Timestamp(System.currentTimeMillis())) .set(SysUser::getLastmodifydate, new Timestamp(System.currentTimeMillis()))
.set("lastmodifier", getUsername()); .set(SysUser::getLastmodifier, SecurityUtils.getCurrentUsername());
if (auditStatus == 1) { if ("APPROVED".equals(auditStatus)) {
updateWrapper.set("status", 1); updateWrapper.set(SysUser::getStatus, 1);
} else if (auditStatus == 2) { } else if ("REJECTED".equals(auditStatus)) {
updateWrapper.set("status", 0); updateWrapper.set(SysUser::getStatus, 0);
} }
return this.update(updateWrapper); return this.update(updateWrapper);
} }
@Override @Override
public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page) { public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page,String name,String regStatus) {
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getRegStatus, 0); queryWrapper.in(SysUser::getRegStatus, "PENDING","APPROVED","REJECTED");
queryWrapper.eq(ObjectUtil.isNotEmpty(regStatus),SysUser::getRegStatus, regStatus);
queryWrapper.and(StrUtil.isNotBlank(name), wrapper ->
wrapper.like(SysUser::getNickname, name)
.or()
.like(SysUser::getRealName, name)
);
queryWrapper.orderByDesc(SysUser::getRegTime); queryWrapper.orderByDesc(SysUser::getRegTime);
return this.page(page, queryWrapper); Page<SysUser> mapPage = this.page(page, queryWrapper);
mapPage.getRecords().forEach(record -> {
String id = record.getId();
List<SysRole> sysRoles = sysRoleMapper.getRoleByUserId(id);
record.setRoles(sysRoles);
});
return mapPage;
} }
/*********************************** /***********************************

View File

@ -0,0 +1,212 @@
package com.yfd.platform.utils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.SecureRandom;
/**
* 随机密码生成器满足以下规则
* 1. 必须包含大写字母小写字母数字特殊字符中的至少三类
* 2. 不能包含2位及以上相同字符的连续重复如11aa
* 3. 不能包含2位及以上连续递增或递减的数字如1221
* 4. 不能包含2位及以上连续递增或递减的字母如abba忽略大小写
* 5. 不能包含用户名忽略大小写
* 6. 密码的字母部分不能是用户名的子串忽略大小写连续子串
* 7. 密码不能与用户名存在明显关联字母部分不能等于用户名或其反转
* 8. 密码开头和结尾不能是特殊字符
* 9. 密码长度可配置默认10-12位
*/
public class PasswordGenerator {
private static final String LOWERS = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String SPECIALS = "!@#$%^&*()_+-=[]{}|;:,.<>?";
private static final SecureRandom RANDOM = new SecureRandom();
private static final int DEFAULT_MIN_LEN = 10;
private static final int DEFAULT_MAX_LEN = 12;
private static final int MAX_ATTEMPTS = 100;
private static int minLength = DEFAULT_MIN_LEN;
private static int maxLength = DEFAULT_MAX_LEN;
public static void configure(int minLen, int maxLen) {
if (minLen < 6) {
minLen = 6;
}
if (maxLen > 32) {
maxLen = 32;
}
if (minLen > maxLen) {
minLen = maxLen;
}
minLength = minLen;
maxLength = maxLen;
}
public static String generateRandomPassword(String username) {
return generateRandomPassword(username, minLength, maxLength);
}
public static String generateRandomPassword(String username, int minLen, int maxLen) {
int configuredMin = minLen > 0 ? minLen : DEFAULT_MIN_LEN;
int configuredMax = maxLen > 0 ? maxLen : DEFAULT_MAX_LEN;
if (configuredMin > configuredMax) {
configuredMin = configuredMax;
}
for (int attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
int length = configuredMin + RANDOM.nextInt(configuredMax - configuredMin + 1);
String candidate = generateRandomString(length);
if (isValidPassword(candidate, username)) {
return candidate;
}
}
throw new RuntimeException("Unable to generate a valid password after " + MAX_ATTEMPTS + " attempts");
}
private static String generateRandomString(int length) {
String lowerChars = LOWERS;
String upperChars = UPPERS;
String digitChars = DIGITS;
String specialChars = SPECIALS;
StringBuilder sb = new StringBuilder(length);
int firstCharIdx = RANDOM.nextInt(lowerChars.length() + upperChars.length() + digitChars.length());
String firstPool = lowerChars + upperChars + digitChars;
sb.append(firstPool.charAt(firstCharIdx));
for (int i = 1; i < length - 1; i++) {
int choice = RANDOM.nextInt(100);
String charsToUse;
if (choice < 25) {
charsToUse = specialChars;
} else if (choice < 55) {
charsToUse = lowerChars;
} else if (choice < 80) {
charsToUse = upperChars;
} else {
charsToUse = digitChars;
}
int idx = RANDOM.nextInt(charsToUse.length());
sb.append(charsToUse.charAt(idx));
}
int lastCharIdx = RANDOM.nextInt(lowerChars.length() + upperChars.length() + digitChars.length());
String lastPool = lowerChars + upperChars + digitChars;
sb.append(lastPool.charAt(lastCharIdx));
return sb.toString();
}
private static boolean isValidPassword(String password, String username) {
if (password == null || password.length() < minLength) return false;
if (!hasEnoughCategories(password)) return false;
if (hasConsecutiveRepeats(password)) return false;
if (hasSequentialDigits(password)) return false;
if (hasSequentialLetters(password)) return false;
if (!isNormalChar(password.charAt(0))) return false;
if (!isNormalChar(password.charAt(password.length() - 1))) return false;
if (username != null && !username.isEmpty()) {
if (containsIgnoreCase(password, username)) return false;
String lettersOnly = extractLetters(password);
if (containsIgnoreCase(lettersOnly, username)) return false;
if (isObviousRelation(lettersOnly, username)) return false;
}
return true;
}
private static boolean isNormalChar(char c) {
return Character.isLowerCase(c) || Character.isUpperCase(c) || Character.isDigit(c);
}
private static boolean hasEnoughCategories(String s) {
boolean hasLower = false, hasUpper = false, hasDigit = false, hasSpecial = false;
for (char c : s.toCharArray()) {
if (Character.isLowerCase(c)) hasLower = true;
else if (Character.isUpperCase(c)) hasUpper = true;
else if (Character.isDigit(c)) hasDigit = true;
else hasSpecial = true;
}
int cnt = (hasLower ? 1 : 0) + (hasUpper ? 1 : 0) + (hasDigit ? 1 : 0) + (hasSpecial ? 1 : 0);
return cnt >= 3;
}
private static boolean hasConsecutiveRepeats(String s) {
for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) return true;
}
return false;
}
private static boolean hasSequentialDigits(String s) {
for (int i = 0; i < s.length() - 1; i++) {
char c1 = s.charAt(i);
char c2 = s.charAt(i + 1);
if (Character.isDigit(c1) && Character.isDigit(c2)) {
int diff = c2 - c1;
if (Math.abs(diff) == 1) return true;
}
}
return false;
}
private static boolean hasSequentialLetters(String s) {
for (int i = 0; i < s.length() - 1; i++) {
char c1 = s.charAt(i);
char c2 = s.charAt(i + 1);
if (Character.isLetter(c1) && Character.isLetter(c2)) {
char low1 = Character.toLowerCase(c1);
char low2 = Character.toLowerCase(c2);
int diff = low2 - low1;
if (Math.abs(diff) == 1) return true;
}
}
return false;
}
private static boolean containsIgnoreCase(String str, String search) {
if (str == null || search == null) return false;
return str.toLowerCase().contains(search.toLowerCase());
}
private static String extractLetters(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) sb.append(c);
}
return sb.toString();
}
private static boolean isObviousRelation(String lettersOnly, String username) {
String lowerLetters = lettersOnly.toLowerCase();
String lowerUser = username.toLowerCase();
if (lowerLetters.equals(lowerUser)) return true;
String reversedUser = new StringBuilder(lowerUser).reverse().toString();
return lowerLetters.equals(reversedUser);
}
public static void main(String[] args) {
configure(10, 12);
String username = "button";
String resetPwd = generateRandomPassword(username);
PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
String cryptPassword = passwordEncoder.encode(resetPwd);
System.out.println("Generated password: " + resetPwd);
System.out.println("Generated cryptPassword: " + cryptPassword);
System.out.println("Password length: " + resetPwd.length());
System.out.println("First char: '" + resetPwd.charAt(0) + "' (is special: " + !isNormalChar(resetPwd.charAt(0)) + ")");
System.out.println("Last char: '" + resetPwd.charAt(resetPwd.length() - 1) + "' (is special: " + !isNormalChar(resetPwd.charAt(resetPwd.length() - 1)) + ")");
configure(8, 16);
System.out.println("\nAfter configure(8, 16):");
resetPwd = generateRandomPassword(username);
System.out.println("Generated password: " + resetPwd);
System.out.println("Password length: " + resetPwd.length());
}
}

View File

@ -22,10 +22,12 @@ import com.yfd.platform.exception.BadRequestException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -91,4 +93,16 @@ public class SecurityUtils {
return JSONUtil.toList(array,Long.class); return JSONUtil.toList(array,Long.class);
} }
// SecurityUtils.java
public static boolean hasPermission(String permission) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
return authorities != null && authorities.stream()
.anyMatch(auth -> permission.equals(auth.getAuthority()));
}
} }

View File

@ -55,7 +55,7 @@ login:
app: app:
# ZIP导入临时目录配置 # ZIP导入临时目录配置
zip-import: zip-import:
temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\zip_import_temp} temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\qgc-platform\zip_import_temp}
init: init:
enabled: false enabled: false
schema: classpath:db-init/sql/min-schema.sql schema: classpath:db-init/sql/min-schema.sql
@ -82,8 +82,8 @@ ip:
file-space: #项目文档空间 file-space: #项目文档空间
files: D:\demoproject\files\ #单独上传的文件附件 files: D:\qgc-platform\files\ #单独上传的文件附件
system: D:\demoproject\system\ #单独上传的文件 system: D:\qgc-platform\system\ #单独上传的文件
task: task:
pool: pool:

View File

@ -10,12 +10,12 @@ spring:
druid: druid:
master: master:
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.31.190:1521/SDLYZ}"
username: "${DB_MASTER_USERNAME:QGC_REFA}" username: "${DB_MASTER_USERNAME:QGC_REFA}"
password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}"
slave: slave:
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.31.190:1521/SDLYZ}"
username: "${DB_SLAVE_USERNAME:QGC_REFA}" username: "${DB_SLAVE_USERNAME:QGC_REFA}"
password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
@ -32,11 +32,11 @@ spring:
logging: logging:
file: file:
name: logs/projectname.log name: logs/platform-dev.log
level: level:
com.genersoft.iot: debug root: info
com.genersoft.iot.vmp.storager.dao: info com.yfd.platform: info
com.genersoft.iot.vmp.gb28181: info com.yfd.platform.*.mapper: trace
# 在线文档: swagger-ui生产环境建议关闭 # 在线文档: swagger-ui生产环境建议关闭
swagger-ui: swagger-ui:
@ -77,7 +77,7 @@ login:
app: app:
# ZIP导入临时目录配置 # ZIP导入临时目录配置
zip-import: zip-import:
temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\zip_import_temp} temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\qgc-platform\zip_import_temp}
init: init:
enabled: false enabled: false
schema: classpath:db-init/sql/min-schema.sql schema: classpath:db-init/sql/min-schema.sql

View File

@ -10,12 +10,12 @@ spring:
druid: druid:
master: master:
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.31.190:1521/SDLYZ}"
username: "${DB_MASTER_USERNAME:QGC_REFA}" username: "${DB_MASTER_USERNAME:QGC_REFA}"
password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}"
slave: slave:
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.31.190:1521/SDLYZ}"
username: "${DB_SLAVE_USERNAME:QGC_REFA}" username: "${DB_SLAVE_USERNAME:QGC_REFA}"
password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
@ -32,11 +32,11 @@ spring:
logging: logging:
file: file:
name: logs/projectname.log name: logs/platform-dev.log
level: level:
com.genersoft.iot: debug root: info
com.genersoft.iot.vmp.storager.dao: info com.yfd.platform: info
com.genersoft.iot.vmp.gb28181: info com.yfd.platform.*.mapper: trace
# 在线文档: swagger-ui生产环境建议关闭 # 在线文档: swagger-ui生产环境建议关闭
swagger-ui: swagger-ui:
@ -77,7 +77,7 @@ login:
app: app:
# ZIP导入临时目录配置 # ZIP导入临时目录配置
zip-import: zip-import:
temp-dir: ${ZIP_IMPORT_TEMP_DIR:/tmp/zip_import_temp} temp-dir: ${ZIP_IMPORT_TEMP_DIR:/qgc-platform/tmp/zip_import_temp}
init: init:
enabled: false enabled: false
schema: classpath:db-init/sql/min-schema.sql schema: classpath:db-init/sql/min-schema.sql
@ -104,8 +104,8 @@ ip:
file-space: #项目文档空间 file-space: #项目文档空间
files: D:\demoproject\files\ #单独上传的文件附件 files: /qgc-platform/files/ #单独上传的文件附件
system: D:\demoproject\system\ #单独上传的文件 system: /qgc-platform/system/ #单独上传的文件
task: task:
pool: pool:

View File

@ -39,3 +39,6 @@ springdoc:
enabled: true enabled: true
path: /swagger-ui.html path: /swagger-ui.html
packages-to-scan: com.yfd.platform packages-to-scan: com.yfd.platform
attachment:
token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH}

View File

@ -49,9 +49,12 @@
<!--根据用户表 id 查询角色表最大级别--> <!--根据用户表 id 查询角色表最大级别-->
<select id="getMaxLevel" resultType="String"> <select id="getMaxLevel" resultType="String">
SELECT MIN(r."LEVEL") SELECT MIN(TO_NUMBER(t.level_col))
FROM (
SELECT r."LEVEL" AS level_col
FROM sys_role r FROM sys_role r
WHERE r.id IN (SELECT roleid FROM sys_role_users WHERE userid = #{userId}) WHERE r.id IN (SELECT roleid FROM sys_role_users WHERE userid = #{userId})
) t
</select> </select>
<select id="queryUsers" resultType="com.yfd.platform.system.domain.SysUser"> <select id="queryUsers" resultType="com.yfd.platform.system.domain.SysUser">
SELECT DISTINCT SELECT DISTINCT
@ -69,8 +72,10 @@
u.lastmodifydate u.lastmodifydate
FROM FROM
sys_user u sys_user u
where 1=1 WHERE
and u.usertype != 0 1 = 1
AND ( ( u.REG_STATUS != 0 AND u.REG_STATUS != 2 ) OR u.REG_STATUS IS NULL )
AND u.usertype != 0
<if test="orgid != null"> <if test="orgid != null">
and u.orgid = #{orgid} and u.orgid = #{orgid}
</if> </if>
@ -81,14 +86,20 @@
</select> </select>
<select id="getOrganizationByid" resultType="java.util.Map"> <select id="getOrganizationByid" resultType="java.util.Map">
SELECT DISTINCT SELECT DISTINCT
u.id,u.username,u.nickname,u.email,u.phone,u.avatar,o.orgname,o.id oid, u.id AS "id",
op.orgname porgname ,op.id poid u.username AS "username",
FROM u.nickname AS "nickname",
sys_user u u.email AS "email",
u.phone AS "phone",
u.avatar AS "avatar",
o.orgname AS "orgname",
o.id AS "oid",
op.orgname AS "porgname",
op.id AS "poid"
FROM sys_user u
INNER JOIN sys_organization o ON u.orgid = o.id INNER JOIN sys_organization o ON u.orgid = o.id
INNER JOIN sys_organization op ON o.parentid = op.id INNER JOIN sys_organization op ON o.parentid = op.id
WHERE WHERE u.id = #{id}
u.id = #{id}
</select> </select>
<delete id="delRoleUsersByUserid"> <delete id="delRoleUsersByUserid">