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, "createdBy", String.class, SecurityUtils.getUserId());
try {
String userId = SecurityUtils.getUserId();
// 自动填充更新时间
this.strictInsertFill(metaObject, "createdBy", String.class, userId );
// 自动填充更新时间
this.strictInsertFill(metaObject, "updatedBy", String.class, userId);
} catch (Exception e) {
e.printStackTrace();
}
// 自动填充更新时间
this.strictInsertFill(metaObject, "updatedBy", String.class, SecurityUtils.getUserId());
}
/**
@ -41,7 +47,13 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
public void updateFill(MetaObject metaObject) {
// 自动填充更新时间
this.strictUpdateFill(metaObject, "updatedAt", Date.class, new Date());
// 自动填充更新人
this.strictInsertFill(metaObject, "updatedBy", String.class, SecurityUtils.getUserId());
try {
String userId = 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
.requestMatchers("/user/login").anonymous()
.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("/env/**").permitAll()
.requestMatchers("/sw/**").permitAll()

View File

@ -4,6 +4,7 @@ import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import lombok.SneakyThrows;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
@ -17,6 +18,9 @@ public class WebConfig implements WebMvcConfigurer {
@Resource
private FileSpaceProperties fileSpaceProperties;
@Value("${app.zip-import.temp-dir}")
private String platformPath;
@Bean
@ -54,7 +58,8 @@ public class WebConfig implements WebMvcConfigurer {
String systemUrl = "file:" + fileSpaceProperties.getSystem().replace("\\", "/")+"user\\";
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.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.utils.UserNameFillHelper;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.ApprovalChangeLog;
import com.yfd.platform.data.domain.ApprovalLog;
@ -28,6 +29,9 @@ public class ApprovalChangeLogController {
@Resource
private IApprovalChangeLogService approvalChangeLogService;
@Resource
private UserNameFillHelper userNameFillHelper;
@GetMapping("/list")
@Operation(summary = "查询变更记录列表")
public ResponseResult list() {
@ -39,7 +43,8 @@ public class ApprovalChangeLogController {
@Operation(summary = "分页查询变更记录列表(通用)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
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);
}

View File

@ -1,24 +1,35 @@
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.fasterxml.jackson.databind.ObjectMapper;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.FishDraftData;
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.*;
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.IFishImportService;
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.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
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.multipart.MultipartFile;
@ -33,6 +44,7 @@ import java.util.*;
@RestController
@RequestMapping("/data/fishDraft")
@Tag(name = "过鱼数据")
@Slf4j
public class FishDraftDataController {
@Resource
@ -47,10 +59,13 @@ public class FishDraftDataController {
@Resource
private ObjectMapper objectMapper;
@Resource
private AttachmentUploadService attachmentUploadService;
@PostMapping("/page")
@Operation(summary = "分页查询过鱼数据(关联电站和设施)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) {
Page<FishDraftDataVO> result = fishDraftDataService.queryPageList( dataSourceRequest);
Page<FishDraftDataVO> result = fishDraftDataService.queryPageList(dataSourceRequest);
return ResponseResult.successData(result);
}
@ -109,6 +124,45 @@ public class FishDraftDataController {
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")
@Operation(summary = "更新草稿")
public ResponseResult updateDraft(@RequestBody FishDraftData fishDraftData) {
@ -134,7 +188,7 @@ public class FishDraftDataController {
@PostMapping("/submitDraft")
@Operation(summary = "提交草稿")
public ResponseResult submitDraft(@RequestParam String id,
@RequestParam String operatorId) {
@RequestParam String operatorId) {
boolean result = fishDraftDataService.submitDraft(id, operatorId);
return result ? ResponseResult.success("提交成功") : ResponseResult.error("提交失败");
}
@ -161,7 +215,6 @@ public class FishDraftDataController {
}
@PostMapping("/lockDraft")
@Operation(summary = "锁定草稿")
public ResponseResult lockDraft(@RequestParam String id) {
@ -207,18 +260,22 @@ public class FishDraftDataController {
@PostMapping("/importZip")
@Operation(summary = "导入ZIP过鱼数据每个用户同时只能进行一次导入")
public ResponseResult importZip(@RequestParam("file") MultipartFile file) {
log.info("开始导入ZIP文件");
if (file == null || file.isEmpty()) {
return ResponseResult.error("请上传文件");
}
log.info("开始上传文件");
String fileName = file.getOriginalFilename();
if (fileName == null || (!fileName.endsWith(".zip"))) {
return ResponseResult.error("请上传ZIP文件(.zip)");
}
log.info("开始处理文件");
String uploadUserId = SecurityUtils.getUserId();
if (importTaskService.hasImportingTask(uploadUserId)) {
return ResponseResult.error("您有正在进行的导入任务,请等待完成后重试");
}
log.info("开始保存导入任务");
String importNo = "IMP" + System.currentTimeMillis();
String taskId = UUID.randomUUID().toString();
@ -232,8 +289,10 @@ public class FishDraftDataController {
task.setStatus("UPLOADED");
task.setUploadUserId(uploadUserId);
task.setUploadTime(new Date());
log.info("保存导入任务成功");
importTaskService.save(task);
log.info("开始保存文件");
FishImportRequest request = new FishImportRequest();
request.setImportNo(importNo);
request.setUploadUserId(uploadUserId);
@ -243,7 +302,7 @@ public class FishDraftDataController {
result.setTaskId(taskId);
String status = "VALIDATED";
if ("1".equals(result.getCode())) {
status="FAILED";
status = "FAILED";
}
importTaskService.updateStatus(taskId, status, null);
importTaskService.updateProgress(taskId, result.getTotalCount(), result.getSuccessCount(), result.getFailedCount());
@ -262,10 +321,281 @@ 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")
@Operation(summary = "取消导入任务")
public ResponseResult cancelImport(@RequestBody FishImportRequest fishImportRequest) {
boolean result = importTaskService.cancelTask(fishImportRequest.getTaskId(),SecurityUtils.getUserId());
boolean result = importTaskService.cancelTask(fishImportRequest.getTaskId(), SecurityUtils.getUserId());
return result ? ResponseResult.success("取消成功") : ResponseResult.error("取消失败");
}
@ -392,15 +722,11 @@ public class FishDraftDataController {
}
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("excelFileName", importResult.getExcelFileName() != null ?
importResult.getExcelFileName() : "");
map.put("failedRowDetails", importResult.getFailedRows() != null ?
importResult.getFailedRows() : new ArrayList<>());
map.put("rows", importResult.getRows() != null ?
importResult.getRows() : new ArrayList<>());
return map;
}
@ -414,4 +740,316 @@ public class FishDraftDataController {
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;
import com.baomidou.mybatisplus.annotation.*;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -59,12 +61,14 @@ public class ApprovalChangeLog implements Serializable {
/**
* 操作人ID
*/
@UserIdField
private String operatorId;
/**
* 操作人名称
*/
@TableField(exist = false)
@UserNameField
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;
/**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回
* 状态DRAFT未提交 / PENDING已提交 / APPROVED已通过 / REJECTED已驳回
*/
private String status;
@ -221,6 +221,12 @@ public class FishDraftData implements Serializable {
@TableField(exist = false)
private String stnm;
/**
* 电站编码名称
*/
@TableField(exist = false)
private String rstcd;
/**
* 鱼类名称
*/

View File

@ -12,11 +12,15 @@ import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class FishImportResult {
private List<FishImportRow> successRows;
private List<FishImportRow> failedRows;
public static final String STATUS_SUCCESS = "SUCCESS";
public static final String STATUS_FAILED = "FAILED";
private List<FishImportRow> rows;
private List<String> unrecognizedFields;
private Map<String, String> imageFiles;
private Map<String, String> videoFiles;
// public Map<String, String> images;
// public Map<String, String> videos;
private String tempDir;
private String excelFileName;
private String excelFilePath;
@ -29,11 +33,24 @@ public class FishImportResult {
private String taskId;
public FishImportResult() {
this.successRows = new ArrayList<>();
this.failedRows = new ArrayList<>();
this.rows = new ArrayList<>();
this.unrecognizedFields = new ArrayList<>();
this.imageFiles = 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
@ -47,6 +64,8 @@ public class FishImportResult {
private List<Map<String, String>> picpthList;
private List<String> vdpthsWarnings;
private List<String> picpthsWarnings;
private String status;
public FishImportRow() {
this.unrecognizedFields = new ArrayList<>();
this.warnings = new ArrayList<>();
@ -57,13 +76,16 @@ public class FishImportResult {
}
public FishImportRow(int rowIndex) {
this();
this.rowIndex = rowIndex;
this.unrecognizedFields = new ArrayList<>();
this.warnings = new ArrayList<>();
this.vdpthsWarnings = new ArrayList<>();
this.picpthsWarnings = new ArrayList<>();
this.vdpthList = new ArrayList<>();
this.picpthList = new ArrayList<>();
}
public boolean isSuccess() {
return STATUS_SUCCESS.equals(status);
}
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;
/**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回
* 状态DRAFT未提交 / PENDING已提交 / APPROVED已通过 / REJECTED已驳回
*/
private String status;

View File

@ -2,6 +2,7 @@ package com.yfd.platform.data.service;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@ -27,6 +28,10 @@ import java.util.stream.Collectors;
@Slf4j
@Service
public class AttachmentUploadService {
@Value("${attachment.token}")
private String token;
// 定义一个固定的线程池用于文件上传建议根据服务器性能调整核心线程数
private static final ExecutorService UPLOAD_EXECUTOR = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
@ -260,4 +265,65 @@ public class AttachmentUploadService {
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);
void fillUserNames(List<ApprovalChangeLog> list);
// void fillUserNames(List<ApprovalChangeLog> list);
/**
* 根据草稿数据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.FishImportResult;
import com.yfd.platform.data.utils.ZipFileUtil;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
@ -18,4 +19,33 @@ public interface IFishImportService {
FishImportResult parseAndMapExcelFromPath(FishImportRequest request);
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) {
return approvalChangeLogMapper.selectByApprovalId(approvalId);
}
@Override
public void fillUserNames(List<ApprovalChangeLog> list) {
if (list == null || list.isEmpty()) {
return;
}
Set<String> userIds = new HashSet<>();
for (ApprovalChangeLog vo : list) {
if (StrUtil.isNotBlank(vo.getApprovalId())) {
userIds.add(vo.getApprovalId());
}
if (StrUtil.isNotBlank(vo.getOperatorId())) {
userIds.add(vo.getOperatorId());
}
}
if (userIds.isEmpty()) {
return;
}
Map<String, String> userNameMap = new HashMap<>();
List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
for (SysUser user : users) {
userNameMap.put(user.getId(), user.getNickname());
}
for (ApprovalChangeLog vo : list) {
if (StrUtil.isNotBlank(vo.getApprovalId())) {
vo.setApprovalName(userNameMap.get(vo.getApprovalId()));
}
if (StrUtil.isNotBlank(vo.getOperatorId())) {
vo.setOperatorName(userNameMap.get(vo.getOperatorId()));
}
}
}
// @Override
// public void fillUserNames(List<ApprovalChangeLog> list) {
// if (list == null || list.isEmpty()) {
// return;
// }
//
// Set<String> userIds = new HashSet<>();
// for (ApprovalChangeLog vo : list) {
// if (StrUtil.isNotBlank(vo.getApprovalId())) {
// userIds.add(vo.getApprovalId());
// }
// if (StrUtil.isNotBlank(vo.getOperatorId())) {
// userIds.add(vo.getOperatorId());
// }
// }
//
// if (userIds.isEmpty()) {
// return;
// }
//
// Map<String, String> userNameMap = new HashMap<>();
// List<SysUser> users = sysUserMapper.selectBatchIds(userIds);
// for (SysUser user : users) {
// userNameMap.put(user.getId(), user.getNickname());
// }
//
// for (ApprovalChangeLog vo : list) {
// if (StrUtil.isNotBlank(vo.getApprovalId())) {
// vo.setApprovalName(userNameMap.get(vo.getApprovalId()));
// }
// if (StrUtil.isNotBlank(vo.getOperatorId())) {
// vo.setOperatorName(userNameMap.get(vo.getOperatorId()));
// }
//
// }
// }
@Override
public List<ApprovalChangeLog> getByDataId(String dataId) {
return approvalChangeLogMapper.selectByDataId(dataId);

View File

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

View File

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

View File

@ -1,5 +1,6 @@
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.FishImportRequest;
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.env.domain.*;
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.ISysDictionaryService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
@ -26,9 +26,9 @@ import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class FishImportServiceImpl implements IFishImportService {
@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<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_CODE_TO_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_CODE_TO_NAME_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 String DICT_CODE_FISH = "FISH_TYPE";
@ -146,7 +153,6 @@ public class FishImportServiceImpl implements IFishImportService {
return result;
}
List<String> unrecognizedHeaders = new ArrayList<>();
Map<Integer, String> columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING);
int totalRows = sheet.getLastRowNum();
@ -156,29 +162,26 @@ public class FishImportServiceImpl implements IFishImportService {
continue;
}
FishImportResult.FishImportRow importRow = parseRow(row, columnIndexMap, i);
FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i);
result.setTotalCount(result.getTotalCount() + 1);
if (importRow.getData() != null && importRow.getWarnings().isEmpty()) {
result.getSuccessRows().add(importRow);
result.addSuccessRow(importRow);
result.setSuccessCount(result.getSuccessCount() + 1);
} else {
result.getFailedRows().add(importRow);
result.addFailedRow(importRow);
result.setFailedCount(result.getFailedCount() + 1);
}
}
result.setSummary(String.format("共解析%d条数据失败%d条未识别字段%s",
result.getSuccessCount(), result.getFailedCount(),
unrecognizedHeaders.isEmpty() ? "" : String.join(", ", unrecognizedHeaders)));
result.setSummary(String.format("共解析%d条数据失败%d条",
result.getSuccessCount(), result.getFailedCount()));
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);
FishDraftData data = new FishDraftData();
data.setId(UUID.randomUUID().toString());
List<String> missingRequiredFields = new ArrayList<>();
for (Map.Entry<Integer, String> entry : columnIndexMap.entrySet()) {
Integer columnIndex = entry.getKey();
String fieldName = entry.getValue();
@ -188,15 +191,17 @@ public class FishImportServiceImpl implements IFishImportService {
switch (fieldName) {
case "stationName":
if (!StringUtils.hasText(cellValue)) {
importRow.getWarnings().add("ennm");
importRow.getWarnings().add("rstcd");
data.setEnnm(cellValue.trim());
data.setRstcd(cellValue);
} else {
String stcd = resolveStationCode(cellValue.trim());
if (stcd == null) {
importRow.getWarnings().add("ennm");
importRow.getWarnings().add("rstcd");
data.setEnnm(cellValue.trim());
} else {
data.setEnnm(cellValue.trim());
data.setRstcd(stcd);
}
}
break;
@ -274,12 +279,12 @@ public class FishImportServiceImpl implements IFishImportService {
break;
case "wt":
if (!StringUtils.hasText(cellValue)) {
importRow.getWarnings().add(fieldName);
// importRow.getWarnings().add(fieldName);
data.setWt(parseBigDecimal(cellValue));
} else {
BigDecimal wt = parseBigDecimal(cellValue);
if (wt == null) {
importRow.getWarnings().add(fieldName);
// importRow.getWarnings().add(fieldName);
data.setWt(parseBigDecimal(cellValue));
}
data.setWt(wt);
@ -318,17 +323,54 @@ public class FishImportServiceImpl implements IFishImportService {
data.setMouth(parseInteger(cellValue));
break;
case "vdpth":
data.setVdpth(cellValue.trim());
data.setVdpthName(cellValue.trim());
String vdpth = 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;
case "picpth":
data.setPicpth(cellValue.trim());
data.setPicpthName(cellValue.trim());
String picpth = 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;
case "isfs":
if (StringUtils.hasText(cellValue)) {
String isfs = resolveIsfs(cellValue.trim(), importRow);
data.setIsfs("1".equals(isfs) ? 1 : 0);
} else {
importRow.getWarnings().add("isfs");
}
break;
case "sourceType":
@ -336,7 +378,8 @@ public class FishImportServiceImpl implements IFishImportService {
break;
case "stnm":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("stcd");
importRow.getWarnings().add("stcd");
data.setStcd(cellValue);
} else {
String stcd = resolveFpssCode(cellValue.trim());
if (stcd == null) {
@ -344,7 +387,7 @@ public class FishImportServiceImpl implements IFishImportService {
data.setStcd(cellValue.trim());
data.setStnm(cellValue.trim());
} else {
data.setStnm(stcd);
data.setStnm(cellValue.trim());
data.setStcd(stcd);
}
}
@ -357,10 +400,41 @@ public class FishImportServiceImpl implements IFishImportService {
// importRow.getWarnings().add("字段[" + fieldName + "]解析异常: " + e.getMessage());
}
}
validateStationFpssRelation(data, importRow);
importRow.setData(data);
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() {
if (STATION_NAME_CACHE.isEmpty()) {
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());
}
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());
}
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());
}
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());
}
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());
}
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());
}
}
}
}
}
private String resolveStationCode(String stationName) {
public String resolveStationCode(String stationName) {
if (stationName == null) {
return null;
}
@ -434,14 +523,14 @@ public class FishImportServiceImpl implements IFishImportService {
return STATION_NAME_CACHE.get(lowerName);
}
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 null;
}
private String resolveFpssCode(String name) {
public String resolveFpssCode(String name) {
if (name == null) {
return null;
}
@ -450,14 +539,56 @@ public class FishImportServiceImpl implements IFishImportService {
return FPSS_BH_CACHE.get(lowerName);
}
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 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) {
return null;
}
@ -473,7 +604,28 @@ public class FishImportServiceImpl implements IFishImportService {
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) {
return null;
}
@ -482,14 +634,35 @@ public class FishImportServiceImpl implements IFishImportService {
return BASE_NAME_CACHE.get(lowerName);
}
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 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) {
return null;
}
@ -498,13 +671,56 @@ public class FishImportServiceImpl implements IFishImportService {
return RIVER_NAME_CACHE.get(lowerName);
}
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 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) {
if (fishName == null) {
return null;
@ -536,7 +752,7 @@ public class FishImportServiceImpl implements IFishImportService {
return facilityName;
}
private String resolveDirection(String direction, FishImportResult.FishImportRow importRow) {
public String resolveDirection(String direction, FishImportResult.FishImportRow importRow) {
if (direction == null) {
return null;
}
@ -555,14 +771,14 @@ public class FishImportServiceImpl implements IFishImportService {
return direction;
}
private String resolveIsfs(String value, FishImportResult.FishImportRow importRow) {
public String resolveIsfs(String value, FishImportResult.FishImportRow importRow) {
if (value == null) {
return null;
}
String lowerName = value.toLowerCase().trim();
if (lowerName.equals("")) {
return "1";
} else if (lowerName.equals("") ) {
} else if (lowerName.equals("")) {
return "0";
}
importRow.getWarnings().add("isfs");
@ -697,6 +913,7 @@ public class FishImportServiceImpl implements IFishImportService {
/**
* 解析 BigDecimal 类型数据
*
* @param value 字符串数值
* @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)) {
return "IMPORT";
}
@ -732,6 +949,7 @@ public class FishImportServiceImpl implements IFishImportService {
FishImportResult result = new FishImportResult();
try {
log.info("开始解析ZIP文件...");
ZipFileUtil.ZipContent zipContent = ZipFileUtil.extractZipToTemp(file);
if (zipContent.excelFilePath == null) {
@ -739,22 +957,23 @@ public class FishImportServiceImpl implements IFishImportService {
ZipFileUtil.cleanupTempDir(zipContent.tempDir);
return result;
}
result.setTempDir(zipContent.tempDir);
result.setImageFiles(zipContent.images);
result.setVideoFiles(zipContent.videos);
try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) {
Sheet sheet = workbook.getSheetAt(0);
result = parseSheet(sheet, result);
}
result.setImageFiles(zipContent.images);
result.setVideoFiles(zipContent.videos);
result.setTempDir(zipContent.tempDir);
result.setExcelFileName(zipContent.excelFileName);
result.setExcelFilePath(zipContent.excelFilePath);
processAttachments(result, zipContent);
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s",
zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir));
// result.setVideos(zipContent.videos);
// result.setImages(zipContent.images);
log.info("ZIP文件解析完成");
// processAttachments(result, zipContent);
//
// log.info("ZIP文件处理完成");
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频",
zipContent.images.size(), zipContent.videos.size()));
return result;
@ -766,8 +985,9 @@ public class FishImportServiceImpl implements IFishImportService {
}
}
private void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) {
for (FishImportResult.FishImportRow importRow : result.getFailedRows()) {
@Override
public void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) {
for (FishImportResult.FishImportRow importRow : result.getRows()) {
FishDraftData data = importRow.getData();
if (data == null) {
continue;
@ -777,32 +997,12 @@ public class FishImportServiceImpl implements IFishImportService {
String picpth = data.getPicpth();
if (StringUtils.hasText(vdpth)) {
String uploadedVdpth = processVideoAttachments(importRow,vdpth, zipContent.videos);
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();
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);
String uploadedPicpth = processImageAttachments(importRow, picpth, zipContent.images);
data.setPicpth(uploadedPicpth);
}
}
@ -849,7 +1049,7 @@ public class FishImportServiceImpl implements IFishImportService {
return String.join(",", attachmentIds);
}
private String processImageAttachments(FishImportResult.FishImportRow importRow,String imageNames, Map<String, String> imageMap) {
private String processImageAttachments(FishImportResult.FishImportRow importRow, String imageNames, Map<String, String> imageMap) {
if (imageNames == null || imageNames.isEmpty() || imageMap == null || imageMap.isEmpty()) {
return imageNames;
}

View File

@ -1,10 +1,15 @@
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.extension.plugins.pagination.Page;
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.mapper.ImportTaskMapper;
import com.yfd.platform.data.service.AttachmentUploadService;
import com.yfd.platform.data.service.IImportTaskService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@ -25,6 +30,12 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
@Resource
private ImportTaskMapper importTaskMapper;
@Resource
private ObjectMapper objectMapper;
@Resource
AttachmentUploadService attachmentUploadService;
@Override
public Page<ImportTask> queryPageList(Page<ImportTask> page, String bizType, String status, String uploadUserId) {
return this.page(page, this.lambdaQuery()
@ -125,7 +136,21 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
}
importTask.setStatus("CONFIRMED");
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
@ -157,6 +182,32 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
if ("CONFIRMED".equals(currentStatus) || "FAILED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) {
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.setErrorMsg("用户取消: " + operatorId);
importTask.setUpdatedAt(new Date());

View File

@ -1,5 +1,6 @@
package com.yfd.platform.data.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@ -18,6 +19,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Component
@Slf4j
public class ZipFileUtil {
private static String tempBaseDir;
@ -35,9 +37,9 @@ public class ZipFileUtil {
}
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return "D:\\zip_import_temp";
return "D:\\qgc-platform\\zip_import_temp";
} 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);
Path tempDirPath = Paths.get(baseTempDir, "zip_" + taskId);
log.info("extractZipToTemp: {}", tempDirPath);
Files.createDirectories(tempDirPath);
content.tempDir = tempDirPath.toString();
File zipFile = new File(tempDirPath.toFile(), "upload.zip");
file.transferTo(zipFile);
try {
log.info("--------------isValidZipFile------------");
if (!isValidZipFile(zipFile)) {
log.info("--------------文件不是有效的ZIP格式或已损坏------------");
throw new IOException("文件不是有效的ZIP格式或已损坏");
}
@ -107,6 +112,7 @@ public class ZipFileUtil {
}
}
log.error("extractZipToTemp: {}", lastException.getMessage());
throw lastException != null ? lastException : new IOException("无法解析ZIP文件");
} 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.config.ResponseResult;
import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.domain.SdEngInfoBHRequest;
import com.yfd.platform.env.service.ISdEngInfoBHService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -69,18 +70,16 @@ public class SdEngInfoBHController {
return ResponseResult.successData(engInfoBHService.getByRvcd(rvcd));
}
@GetMapping("/dropdown")
@PostMapping("/dropdown")
@Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)")
public ResponseResult dropdown(@RequestParam(required = false) String baseId,
@RequestParam(required = false) String ennm) {
return ResponseResult.successData(engInfoBHService.selectForDropdown(baseId, ennm));
public ResponseResult dropdown(@RequestBody SdEngInfoBHRequest sdEngInfoBHRequest) {
return ResponseResult.successData(engInfoBHService.selectForDropdown(sdEngInfoBHRequest));
}
@GetMapping("/regDropdown")
@PostMapping("/regDropdown")
@Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)注册")
public ResponseResult regDropdown(@RequestParam(required = false) String baseId,
@RequestParam(required = false) String ennm) {
return ResponseResult.successData(engInfoBHService.selectRegDropdown(baseId, ennm));
public ResponseResult regDropdown(@RequestBody SdEngInfoBHRequest sdEngInfoBHRequest) {
return ResponseResult.successData(engInfoBHService.selectRegDropdown(sdEngInfoBHRequest));
}
@Log(module = "电站管理", value = "新增电站")

View File

@ -1,6 +1,7 @@
package com.yfd.platform.env.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.common.DataSourceRequest;
@ -55,8 +56,8 @@ public class SdFishDictoryBController {
@Operation(summary = "根据名称查询所有鱼类字典")
public ResponseResult listByName(@RequestParam(required = false) String name) {
return ResponseResult.successData(sdFishDictoryBService.list(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SdFishDictoryB>()
.eq(StrUtil.isNotBlank(name), SdFishDictoryB::getName, name)
new LambdaQueryWrapper<SdFishDictoryB>()
.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);
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")
@Operation(summary = "下拉框列表查询")
@Operation(summary = "下拉框列表查询(注册)")
public ResponseResult regDropdown(
@RequestParam(required = false) String hbrvnm,
@RequestParam(required = false) String baseid) {

View File

@ -66,16 +66,20 @@ public class SdHycdDicController {
@Operation(summary = "下拉框列表查询")
public ResponseResult selectForDropdown(
@RequestParam(required = false) String hynm,
@RequestParam(required = false) Integer grd) {
return ResponseResult.successData(hycdDicService.selectForDropdown(hynm, grd));
@RequestParam(required = false) Integer grd,
@RequestParam(required = false) Integer lx,
@RequestParam(required = false) String phycd) {
return ResponseResult.successData(hycdDicService.selectForDropdown(hynm, grd,lx,phycd));
}
@GetMapping("/regDropdown")
@Operation(summary = "下拉框列表查询(注册)")
public ResponseResult regDropdown(
@RequestParam(required = false) String hynm,
@RequestParam(required = false) Integer grd) {
return ResponseResult.successData(hycdDicService.regDropdown(hynm, grd));
@RequestParam(required = false) Integer 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
*/
private BigDecimal v;
private String v;
/**
* 仿自然通道断面形状
@ -293,7 +293,7 @@ public class SdFpssBH implements Serializable {
/**
* 升鱼机集鱼槽流量单位m3/s
*/
private BigDecimal syjq;
private String syjq;
/**
* 升鱼机断面尺寸**单位m
@ -303,7 +303,7 @@ public class SdFpssBH implements Serializable {
/**
* 升鱼机集鱼槽水深单位m
*/
private BigDecimal syjwdp;
private String syjwdp;
/**
* 设计过鱼规模单位

View File

@ -49,15 +49,6 @@ public class SdHycdDic implements Serializable {
*/
private Integer orderIndex;
/**
* 中心经度
*/
private String lgtd;
/**
* 中心纬度
*/
private String lttd;
/**
* 所属国家关联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:公司
*/
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.service.IService;
import com.yfd.platform.env.domain.SdEngInfoBH;
import com.yfd.platform.env.domain.SdEngInfoBHRequest;
import java.util.List;
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();
@ -56,5 +57,5 @@ public interface ISdEngInfoBHService extends IService<SdEngInfoBH> {
*/
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.yfd.platform.env.domain.SdFishDictoryB;
import java.util.List;
public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
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);
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.mapper.SysUserDataScopeMapper;
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.service.ISdEngInfoBHService;
import com.yfd.platform.utils.SecurityUtils;
@ -65,9 +66,15 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
}
@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<>();
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)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getOrderIndex);
@ -143,9 +150,15 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
}
@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<>();
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)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getOrderIndex);

View File

@ -1,5 +1,6 @@
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.extension.plugins.pagination.Page;
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.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper, SdFishDictoryB> implements ISdFishDictoryBService {
@ -62,4 +66,146 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper,
.eq(SdFishDictoryB::getIsDeleted, 0);
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
public List<SdHycdDic> selectForDropdown(String hynm, Integer grd) {
public List<SdHycdDic> selectForDropdown(String hynm, Integer grd, Integer lx,String phycd) {
return this.lambdaQuery()
.like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm)
.eq(phycd != null, SdHycdDic::getPhycd, phycd)
.eq(grd != null, SdHycdDic::getGrd, grd)
.eq(lx != null, SdHycdDic::getLx, lx)
.orderByAsc(SdHycdDic::getOrderIndex)
.list();
}
@Override
public List<SdHycdDic> regDropdown(String hynm, Integer grd) {
public List<SdHycdDic> regDropdown(String hynm, Integer grd,Integer lx,String phycd) {
return this.lambdaQuery()
.like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm)
.eq(phycd != null, SdHycdDic::getPhycd, phycd)
.eq(grd != null, SdHycdDic::getGrd, grd)
.eq(lx != null, SdHycdDic::getLx, lx)
.orderByAsc(SdHycdDic::getOrderIndex)
.list();
}

View File

@ -4,11 +4,18 @@ import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.yfd.platform.config.ResponseResult;
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.mapper.SysMenuMapper;
import com.yfd.platform.system.service.ISmsVerifyCodeService;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.RequestHolder;
import com.yfd.platform.utils.RsaUtils;
import com.yfd.platform.utils.StringUtils;
import io.swagger.v3.oas.annotations.Operation;
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.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
@ -48,6 +55,18 @@ public class SmsVerifyCodeController {
@Resource
private ISysLogService sysLogService;
@Resource
private SysMenuMapper sysMenuMapper;
@Resource
private ISysUserDataScopeService sysUserDataScopeService;
@Resource
private ISdEngInfoBHService engInfoBHService;
@Resource
private ISdHbrvDicService hbrvDicService;
@Value("${rsa.private_key}")
private String privateKey;
@ -59,26 +78,42 @@ public class SmsVerifyCodeController {
public ResponseResult sendVerifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone();
Integer type = smsVerifyCodeRequest.getType();
if (phone == null || phone.isEmpty()) {
return ResponseResult.error("手机号不能为空");
}
if (type == null || (!type.equals(SmsVerifyCode.TYPE_REGISTER) && !type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD))) {
return ResponseResult.error("类型错误1-注册 2-找回密码");
if (type == null) {
return ResponseResult.error("类型不能为空1-注册 2-找回密码 3-登录");
}
// 1. 注册验证码校验
if (type.equals(SmsVerifyCode.TYPE_REGISTER)) {
SysUser existUser = userService.getUserByPhone(phone);
if (existUser != null) {
return ResponseResult.error("该手机号已注册");
}
}
if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) {
// 2. 找回密码验证码校验
else if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) {
SysUser existUser = userService.getUserByPhone(phone);
if (existUser == null) {
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);
if (code == null) {
@ -88,51 +123,62 @@ public class SmsVerifyCodeController {
return ResponseResult.success();
}
/**
* 注册用户
*/
@PostMapping("/register")
@Operation(summary = "注册用户")
@Transactional
public ResponseResult register(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
SysUser user = smsVerifyCodeRequest.getUser();
String code = smsVerifyCodeRequest.getCode();
if (user.getPhone() == null || user.getPhone().isEmpty()) {
if (smsVerifyCodeRequest.getPhone() == null || smsVerifyCodeRequest.getPhone().isEmpty()) {
return ResponseResult.error("手机号不能为空");
}
if (user.getUsername() == null || user.getUsername().isEmpty()) {
if (smsVerifyCodeRequest.getUsername() == null || smsVerifyCodeRequest.getUsername().isEmpty()) {
return ResponseResult.error("用户名不能为空");
}
if (user.getPassword() == null || user.getPassword().isEmpty()) {
if (smsVerifyCodeRequest.getPassword() == null || smsVerifyCodeRequest.getPassword().isEmpty()) {
return ResponseResult.error("密码不能为空");
}
if (code == null || code.isEmpty()) {
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) {
return ResponseResult.error("验证码错误或已过期");
}
SysUser existUser = userService.getUserByPhone(user.getPhone());
SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
if (existUser != null) {
return ResponseResult.error("该手机号已注册");
}
SysUser user = new SysUser();
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) {
return ResponseResult.error("密码解密失败");
}
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setRegStatus(0);
user.setRegStatus("PENDING");
user.setPhone(smsVerifyCodeRequest.getPhone());
user.setBelongingUnit(smsVerifyCodeRequest.getBelongingUnit());
user.setRegTime(new Date());
user.setNickname(smsVerifyCodeRequest.getRealName());
user.setStatus(1);
user.setOrgid("e90063ced25e3d469860e88d920c082f");
user.setUsertype(1);
user.setUsername(smsVerifyCodeRequest.getUsername());
user.setGroupCode(smsVerifyCodeRequest.getGroupCode());
user.setCompanyCode(smsVerifyCodeRequest.getCompanyCode());
boolean success = userService.save(user);
// 给注册用户加上默认权限
SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
if (savedUser != null) {
this.addDefaultRole(savedUser.getId(), smsVerifyCodeRequest);
}
if (success) {
return ResponseResult.success();
} 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) {
return ResponseResult.error("该手机号未注册");
}
try {
password = RsaUtils.decryptByPrivateKey(privateKey, smsVerifyCodeRequest.getPassword());
} catch (Exception e) {
return ResponseResult.error("密码解密失败");
}
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encryptedPassword = passwordEncoder.encode(password);
@ -183,7 +330,7 @@ public class SmsVerifyCodeController {
/**
* 验证验证码是否有效
*/
@GetMapping("/verifyCode")
@PostMapping("/verifyCode")
@Operation(summary = "验证验证码")
public ResponseResult verifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone();
@ -212,7 +359,7 @@ public class SmsVerifyCodeController {
return ResponseResult.error("验证码不能为空");
}
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_REGISTER);
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN);
if (!verified) {
return ResponseResult.error("验证码错误或已过期");
}
@ -226,11 +373,11 @@ public class SmsVerifyCodeController {
return ResponseResult.error("账号已停用");
}
if (user.getRegStatus() != null && user.getRegStatus() == 0) {
if (user.getRegStatus() != null && "PENDING".equals(user.getRegStatus())) {
return ResponseResult.error("账号待审核,请联系管理员");
}
if (user.getRegStatus() != null && user.getRegStatus() == 2) {
if (user.getRegStatus() != null && "REJECTED".equals(user.getRegStatus())) {
return ResponseResult.error("账号审核未通过");
}
@ -242,7 +389,10 @@ public class SmsVerifyCodeController {
LoginUser loginUser = new LoginUser();
loginUser.setUser(user);
loginUser.setUsername(user.getUsername());
//Todo 根据用户查询权限信息 添加到LoginUser中
List<String> permissions =
sysMenuMapper.selectPermsByUserId(user.getId());
loginUser.setPermissions( permissions);
HttpServletRequest request = RequestHolder.getHttpServletRequest();
SysLog sysLog = new SysLog();
sysLog.setUsercode(user.getUsername());
@ -275,7 +425,7 @@ public class SmsVerifyCodeController {
webConfig.loginuserCache().put("login:" + userId, jsonStr);
webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString());
map.put("user", user);
// map.put("user", user);
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.datasource.DataSource;
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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -32,6 +34,9 @@ public class UserController {
@Resource
private IUserService userService;
@Resource
private ISmsVerifyCodeService smsVerifyCodeService;
@Log(module = "系统用户", value = "新增系统用户")
@PostMapping("/addUser")
@Operation(summary = "新增系统用户")
@ -58,6 +63,7 @@ public class UserController {
return ResponseResult.successData(reslut);
}
@GetMapping("/queryUsers")
@Operation(summary = "查询用户信息")
@ResponseBody
@ -155,12 +161,7 @@ public class UserController {
if (StrUtil.isBlank(id)) {
ResponseResult.error("参数为空");
}
boolean ok = userService.resetPassword(id);
if (ok) {
return ResponseResult.success();
} else {
return ResponseResult.error();
}
return userService.resetPassword(id);
}
/***********************************
@ -201,20 +202,27 @@ public class UserController {
return ResponseResult.success();
}
@Log(module = "系统用户", value = "审核用户注册")
// @Log(module = "系统用户", value = "审核用户注册")
@PostMapping("/auditUser")
@Operation(summary = "审核用户注册")
@ResponseBody
public ResponseResult auditUser(@RequestParam String userId,
@RequestParam Integer auditStatus) {
public ResponseResult auditUser(@RequestBody SysUserRequest sysUserRequest) {
String userId = sysUserRequest.getUserId();
String auditStatus = sysUserRequest.getRegStatus();
if (userId == null || userId.isEmpty()) {
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-驳回");
}
SysUser user = userService.getById(userId);
if (user == null) {
return ResponseResult.error("用户不存在");
}
boolean ok = userService.auditUser(userId, auditStatus);
if (ok) {
smsVerifyCodeService.sendAuditNotify(user.getPhone(), auditStatus, sysUserRequest.getCommentInfo());
return ResponseResult.success();
} else {
return ResponseResult.error("审核失败");
@ -224,8 +232,8 @@ public class UserController {
@GetMapping("/queryPendingAuditUsers")
@Operation(summary = "查询待审核用户列表")
@ResponseBody
public ResponseResult queryPendingAuditUsers(Page<SysUser> page) {
Page<SysUser> result = userService.queryPendingAuditUsers(page);
public ResponseResult queryPendingAuditUsers(Page<SysUser> page,String name,String regStatus) {
Page<SysUser> result = userService.queryPendingAuditUsers(page,name,regStatus);
return ResponseResult.successData(result);
}
}

View File

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

View File

@ -23,6 +23,7 @@ public class SmsVerifyCode implements Serializable {
public static final Integer TYPE_REGISTER = 1;
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_USED = 1;

View File

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

View File

@ -122,15 +122,20 @@ public class SysUser implements Serializable {
private String realName;
/**
* 注册状态0-待审核 1-已通过 2-已驳回
* 审批状态PENDING待审批 / APPROVED已通过 / REJECTED已驳回
*/
private Integer regStatus;
private String regStatus;
/**
* 审核人ID
*/
private String auditUser;
/**
* 所属单位
*/
private String belongingUnit;
/**
* 审核时间
*/
@ -141,6 +146,15 @@ public class SysUser implements Serializable {
*/
private Date regTime;
/**
* 集团编号
*/
private String groupCode;
/**
* 公司编号
*/
private String companyCode;
@TableField(exist = false)
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
* 返回值说明:
************************************/
String getMaxLevel(@Param("userid") String userid);
String getMaxLevel(@Param("userId") String userId);
/***********************************
* 用途说明根据用户id删除所分配的角色

View File

@ -37,4 +37,13 @@ public interface ISmsVerifyCodeService extends IService<SmsVerifyCode> {
* 生成6位数字验证码
*/
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.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysUser;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
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,
String mobile, String status);
@Transactional(rollbackFor = Exception.class)
Map updateUserRoles(SysUser sysUser, String roleids);
/***********************************
* 用途说明根据ID查询用户详情
* 参数说明
@ -97,7 +101,7 @@ public interface IUserService extends IService<SysUser> {
*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-驳回
* 返回值说明: 是否审核成功
************************************/
boolean auditUser(String userId, Integer auditStatus);
boolean auditUser(String userId, String auditStatus);
/***********************************
* 用途说明查询待审核用户列表
@ -170,6 +174,6 @@ public interface IUserService extends IService<SysUser> {
*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
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();
@Resource
@ -96,4 +96,28 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
public String generateCode() {
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;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.config.FileProperties;
import com.yfd.platform.config.ResponseResult;
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.SysUser;
import com.yfd.platform.system.mapper.SysOrganizationMapper;
import com.yfd.platform.system.mapper.SysRoleMapper;
import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.FileUtil;
import com.yfd.platform.utils.PasswordGenerator;
import com.yfd.platform.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import com.yfd.platform.config.FileSpaceProperties;
import jakarta.annotation.Resource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -30,8 +30,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import java.io.File;
import java.sql.Timestamp;
import java.util.*;
@ -269,6 +267,46 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
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
@ -281,7 +319,6 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
// 解析新角色列表
String[] newRoles = roleIds.split(",");
Set<String> newRoleSet = new HashSet<>(Arrays.asList(newRoles));
// 需要新增的角色新角色 - 当前角色
for (String roleId : newRoles) {
@ -295,9 +332,6 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
sysUserMapper.delInRoleUsersByUserid(userId, newRoles);
}
// ... existing code ...
@Override
public Map getOneById(String id) {
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
@ -392,17 +426,18 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
* 返回值说明: 判断是重置成功
************************************/
@Override
public boolean resetPassword(String id) throws Exception {
boolean isOk = false;
public ResponseResult resetPassword(String id) throws Exception {
//根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户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<>();
String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername());
//根据id 修改密码密码修改时间最近修改者最近修改日期 将密码修改为 123456
String cryptPassword = passwordEncoder.encode("123456");
String cryptPassword = passwordEncoder.encode(password);
updateWrapper.eq("id", id).set("password", cryptPassword).set(
"pwdresettime",
new Timestamp(System.currentTimeMillis())).set(
@ -410,10 +445,11 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
new Timestamp(System.currentTimeMillis())).set(
"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
String level = sysUserMapper.getMaxLevel(id);
//判断当前用户级别 管理员及以上权限
if (Integer.parseInt(level) <= 2) {
if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
//根据id修改用户状态最近修改人最近修改时间
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> mapPage = sysUserMapper.queryUsers(orgid,
username, page);
;mapPage.getRecords().forEach(record -> {
mapPage.getRecords().forEach(record -> {
String id = record.getId();
List<SysRole> sysRoles = sysRoleMapper.getRoleByUserId(id);
record.setRoles(sysRoles);
@ -574,34 +610,45 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
updateWrapper.eq("phone", phone)
.set("password", encryptedPassword)
.set("pwdresettime", new Timestamp(System.currentTimeMillis()))
.set("lastmodifydate", new Timestamp(System.currentTimeMillis()))
.set("lastmodifier", getUsername());
.set("lastmodifydate", new Timestamp(System.currentTimeMillis()));
return this.update(updateWrapper);
}
@Override
public boolean auditUser(String userId, Integer auditStatus) {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", userId)
.set("reg_status", auditStatus)
.set("audit_user", getUsername())
.set("audit_time", new Timestamp(System.currentTimeMillis()))
.set("lastmodifydate", new Timestamp(System.currentTimeMillis()))
.set("lastmodifier", getUsername());
if (auditStatus == 1) {
updateWrapper.set("status", 1);
} else if (auditStatus == 2) {
updateWrapper.set("status", 0);
public boolean auditUser(String userId, String auditStatus) {
LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SysUser::getId, userId)
.set(SysUser::getRegStatus, auditStatus)
.set(SysUser::getAuditUser, SecurityUtils.getUserId())
.set(SysUser::getAuditTime, new Timestamp(System.currentTimeMillis()))
.set(SysUser::getLastmodifydate, new Timestamp(System.currentTimeMillis()))
.set(SysUser::getLastmodifier, SecurityUtils.getCurrentUsername());
if ("APPROVED".equals(auditStatus)) {
updateWrapper.set(SysUser::getStatus, 1);
} else if ("REJECTED".equals(auditStatus)) {
updateWrapper.set(SysUser::getStatus, 0);
}
return this.update(updateWrapper);
}
@Override
public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page) {
public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page,String name,String regStatus) {
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);
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 org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.Collection;
import java.util.List;
/**
@ -91,4 +93,16 @@ public class SecurityUtils {
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:
# ZIP导入临时目录配置
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:
enabled: false
schema: classpath:db-init/sql/min-schema.sql
@ -82,8 +82,8 @@ ip:
file-space: #项目文档空间
files: D:\demoproject\files\ #单独上传的文件附件
system: D:\demoproject\system\ #单独上传的文件
files: D:\qgc-platform\files\ #单独上传的文件附件
system: D:\qgc-platform\system\ #单独上传的文件
task:
pool:

View File

@ -10,12 +10,12 @@ spring:
druid:
master:
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}"
password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}"
slave:
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}"
password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
@ -31,12 +31,12 @@ spring:
max-request-size: 100MB
logging:
file:
name: logs/projectname.log
level:
com.genersoft.iot: debug
com.genersoft.iot.vmp.storager.dao: info
com.genersoft.iot.vmp.gb28181: info
file:
name: logs/platform-dev.log
level:
root: info
com.yfd.platform: info
com.yfd.platform.*.mapper: trace
# 在线文档: swagger-ui生产环境建议关闭
swagger-ui:
@ -77,7 +77,7 @@ login:
app:
# ZIP导入临时目录配置
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:
enabled: false
schema: classpath:db-init/sql/min-schema.sql

View File

@ -10,12 +10,12 @@ spring:
druid:
master:
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}"
password: "${DB_MASTER_PASSWORD:Y4M4K1oCkL8U}"
slave:
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}"
password: "${DB_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
@ -31,12 +31,12 @@ spring:
max-request-size: 100MB
logging:
file:
name: logs/projectname.log
level:
com.genersoft.iot: debug
com.genersoft.iot.vmp.storager.dao: info
com.genersoft.iot.vmp.gb28181: info
file:
name: logs/platform-dev.log
level:
root: info
com.yfd.platform: info
com.yfd.platform.*.mapper: trace
# 在线文档: swagger-ui生产环境建议关闭
swagger-ui:
@ -77,7 +77,7 @@ login:
app:
# ZIP导入临时目录配置
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:
enabled: false
schema: classpath:db-init/sql/min-schema.sql
@ -104,8 +104,8 @@ ip:
file-space: #项目文档空间
files: D:\demoproject\files\ #单独上传的文件附件
system: D:\demoproject\system\ #单独上传的文件
files: /qgc-platform/files/ #单独上传的文件附件
system: /qgc-platform/system/ #单独上传的文件
task:
pool:

View File

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

View File

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