This commit is contained in:
扈兆增 2026-04-24 15:32:02 +08:00
commit bb2173047f
51 changed files with 3702 additions and 120 deletions

View File

@ -0,0 +1,19 @@
package com.yfd.platform.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.yfd.platform.utils.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
@ -13,6 +14,7 @@ import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时自动填充
*/
@ -25,6 +27,11 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
// 自动填充更新时间
this.strictInsertFill(metaObject, "updatedAt", Date.class, now);
// 自动填充更新时间
this.strictInsertFill(metaObject, "createdBy", String.class, SecurityUtils.getUserId());
// 自动填充更新时间
this.strictInsertFill(metaObject, "updatedBy", String.class, SecurityUtils.getUserId());
}
/**
@ -34,5 +41,7 @@ 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());
}
}

View File

@ -54,4 +54,6 @@ public class SwaggerConfig {
.packagesToScan("com.yfd.platform.env.controller")
.build();
}
}

View File

@ -1,8 +1,12 @@
package com.yfd.platform.data.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.ApprovalChangeLog;
import com.yfd.platform.data.domain.ApprovalLog;
import com.yfd.platform.data.service.IApprovalChangeLogService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@ -31,6 +35,13 @@ public class ApprovalChangeLogController {
return ResponseResult.successData(list);
}
@PostMapping("/queryPageList")
@Operation(summary = "分页查询变更记录列表(通用)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<ApprovalChangeLog> approvalChangeLogPage = DataSourceRequestUtil.executeQuery(request, ApprovalChangeLog.class, approvalChangeLogService);
return ResponseResult.successData(approvalChangeLogPage);
}
@GetMapping("/getByApprovalId")
@Operation(summary = "根据审批批次ID查询变更记录")
public ResponseResult getByApprovalId(@RequestParam String approvalId) {

View File

@ -1,8 +1,12 @@
package com.yfd.platform.data.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.ApprovalLog;
import com.yfd.platform.data.domain.ApprovalMain;
import com.yfd.platform.data.service.IApprovalLogService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@ -31,6 +35,14 @@ public class ApprovalLogController {
return ResponseResult.successData(list);
}
@PostMapping("/queryPageList")
@Operation(summary = "分页查询审批日志列表(通用)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<ApprovalLog> approvalLogPage = DataSourceRequestUtil.executeQuery(request, ApprovalLog.class, approvalLogService);
return ResponseResult.successData(approvalLogPage);
}
@GetMapping("/getByApprovalId")
@Operation(summary = "根据审批批次ID查询日志")
public ResponseResult getByApprovalId(@RequestParam String approvalId) {

View File

@ -1,9 +1,11 @@
package com.yfd.platform.data.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.data.domain.ApprovalMain;
import com.yfd.platform.data.service.IApprovalMainService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@ -36,6 +38,15 @@ public class ApprovalMainController {
return ResponseResult.successData(result);
}
@PostMapping("/queryPageList")
@Operation(summary = "分页查询审批列表(通用)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<ApprovalMain> approvalMainPage = DataSourceRequestUtil.executeQuery(request, ApprovalMain.class, approvalMainService);
return ResponseResult.successData(approvalMainPage);
}
@GetMapping("/getById")
@Operation(summary = "根据ID查询审批")
public ResponseResult getById(@RequestParam Long id) {

View File

@ -1,20 +1,30 @@
package com.yfd.platform.data.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
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.vo.FishDraftDataVO;
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.utils.KendoUtil;
import com.yfd.platform.utils.QgcQueryWrapperUtil;
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 org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* <p>
@ -29,48 +39,36 @@ public class FishDraftDataController {
@Resource
private IFishDraftDataService fishDraftDataService;
// @GetMapping("/page")
// @Operation(summary = "分页查询过鱼数据")
// public ResponseResult queryPageList(
// @RequestParam(defaultValue = "1") Integer current,
// @RequestParam(defaultValue = "10") Integer size,
// @RequestParam(required = false) String stcd,
// @RequestParam(required = false) String status,
// @RequestParam(required = false) String ftp) {
// Page<FishDraftData> page = new Page<>(current, size);
// Page<FishDraftData> result = fishDraftDataService.queryPageList(page, stcd, status, ftp);
// return ResponseResult.successData(result);
// }
@Resource
private IFishImportService fishImportService;
@Resource
private IImportTaskService importTaskService;
@PostMapping("/page")
@Operation(summary = "分页查询过鱼数据")
@Operation(summary = "分页查询过鱼数据(关联电站和设施)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) {
Page page = KendoUtil.getPage(dataSourceRequest);
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd");
String status = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "status");
String ftp = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "ftp");
Page<FishDraftData> result = fishDraftDataService.queryPageList(page, stcd, status, ftp);
Page<FishDraftDataVO> result = fishDraftDataService.queryPageList( dataSourceRequest);
return ResponseResult.successData(result);
}
@GetMapping("/list")
@Operation(summary = "查询过鱼数据列表")
public ResponseResult list() {
List<FishDraftData> list = fishDraftDataService.list();
@PostMapping("/list")
@Operation(summary = "查询过鱼数据列表(关联电站和设施,不分页)")
public ResponseResult list(@RequestBody DataSourceRequest dataSourceRequest) {
List<FishDraftDataVO> list = fishDraftDataService.queryJoinList(dataSourceRequest);
return ResponseResult.successData(list);
}
@GetMapping("/getById")
@Operation(summary = "根据ID查询")
public ResponseResult getById(@RequestParam Long id) {
public ResponseResult getById(@RequestParam String id) {
FishDraftData fishDraftData = fishDraftDataService.getById(id);
return ResponseResult.successData(fishDraftData);
}
@GetMapping("/getByApprovalId")
@Operation(summary = "根据审批批次ID查询")
public ResponseResult getByApprovalId(@RequestParam Long approvalId) {
public ResponseResult getByApprovalId(@RequestParam String approvalId) {
List<FishDraftData> list = fishDraftDataService.getByApprovalId(approvalId);
return ResponseResult.successData(list);
}
@ -96,6 +94,19 @@ public class FishDraftDataController {
return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败");
}
@PostMapping("/batchSaveDraft")
@Operation(summary = "批量保存草稿")
public ResponseResult saveDraft(@RequestBody List<FishDraftData> fishDraftDataList) {
fishDraftDataList.forEach(fishDraftData -> {
fishDraftData.setStatus("DRAFT");
fishDraftData.setDeletedFlag(0);
fishDraftData.setLockFlag(0);
});
boolean result = fishDraftDataService.saveBatch(fishDraftDataList);
return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败");
}
@PostMapping("/updateDraft")
@Operation(summary = "更新草稿")
public ResponseResult updateDraft(@RequestBody FishDraftData fishDraftData) {
@ -105,15 +116,22 @@ public class FishDraftDataController {
@PostMapping("/removeDraft")
@Operation(summary = "删除草稿(软删除)")
public ResponseResult removeDraft(@RequestParam Long id,
public ResponseResult removeDraft(@RequestParam String id,
@RequestParam String operatorId) {
boolean result = fishDraftDataService.removeDraft(id, operatorId);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
@PostMapping("/batchRemoveDraft")
@Operation(summary = "批量删除草稿(软删除)")
public ResponseResult batchRemoveDraft(@RequestBody List<String> ids) {
boolean result = fishDraftDataService.batchRemoveDraft(ids);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
@PostMapping("/submitDraft")
@Operation(summary = "提交草稿")
public ResponseResult submitDraft(@RequestParam Long id,
public ResponseResult submitDraft(@RequestParam String id,
@RequestParam String operatorId) {
boolean result = fishDraftDataService.submitDraft(id, operatorId);
return result ? ResponseResult.success("提交成功") : ResponseResult.error("提交失败");
@ -121,22 +139,37 @@ public class FishDraftDataController {
@PostMapping("/submitDrafts")
@Operation(summary = "批量提交草稿")
public ResponseResult submitDrafts(@RequestBody List<Long> ids,
@RequestParam String operatorId) {
boolean result = fishDraftDataService.submitDrafts(ids, operatorId);
public ResponseResult submitDrafts(@RequestBody List<String> ids) {
boolean result = fishDraftDataService.submitDrafts(ids);
return result ? ResponseResult.success("提交成功") : ResponseResult.error("提交失败");
}
@PostMapping("/batchApprove")
@Operation(summary = "批量审批通过")
public ResponseResult batchApprove(@RequestBody BatchApproveRequest request) {
boolean result = fishDraftDataService.batchApprove(request.getIds(), request.getApproveComment());
return result ? ResponseResult.success("审批通过") : ResponseResult.error("审批失败");
}
@PostMapping("/reject")
@Operation(summary = "审批驳回")
public ResponseResult batchReject(@RequestBody BatchRejectRequest request) {
boolean result = fishDraftDataService.batchReject(request.getId(), request.getRejectReason());
return result ? ResponseResult.success("驳回成功") : ResponseResult.error("驳回失败");
}
@PostMapping("/lockDraft")
@Operation(summary = "锁定草稿")
public ResponseResult lockDraft(@RequestParam Long id) {
public ResponseResult lockDraft(@RequestParam String id) {
boolean result = fishDraftDataService.lockDraft(id);
return result ? ResponseResult.success("锁定成功") : ResponseResult.error("锁定失败");
}
@PostMapping("/unlockDraft")
@Operation(summary = "解锁草稿")
public ResponseResult unlockDraft(@RequestParam Long id) {
public ResponseResult unlockDraft(@RequestParam String id) {
boolean result = fishDraftDataService.unlockDraft(id);
return result ? ResponseResult.success("解锁成功") : ResponseResult.error("解锁失败");
}
@ -144,24 +177,106 @@ public class FishDraftDataController {
@PostMapping("/add")
@Operation(summary = "新增过鱼数据")
public ResponseResult add(@RequestBody FishDraftData fishDraftData) {
fishDraftData.setCreatedAt(new Date());
fishDraftData.setUpdatedAt(new Date());
boolean result = fishDraftDataService.save(fishDraftData);
return result ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败");
}
@PostMapping("/update")
@Operation(summary = "修改过鱼数据")
@Operation(summary = "审批人修改过鱼数据(记录变更日志)")
public ResponseResult update(@RequestBody FishDraftData fishDraftData) {
fishDraftData.setUpdatedAt(new Date());
boolean result = fishDraftDataService.updateById(fishDraftData);
boolean result = fishDraftDataService.updateByIdWithLog(fishDraftData);
return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
}
@PostMapping("/delete")
@Operation(summary = "删除过鱼数据")
public ResponseResult delete(@RequestParam Long id) {
public ResponseResult delete(@RequestParam String id) {
boolean result = fishDraftDataService.removeById(id);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
@PostMapping("/batchDelete")
@Operation(summary = "批量删除过鱼数据")
public ResponseResult batchDelete(@RequestBody List<String> ids) {
boolean result = fishDraftDataService.removeByIds(ids);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
@PostMapping("/importZip")
@Operation(summary = "导入ZIP过鱼数据每个用户同时只能进行一次导入")
public ResponseResult importZip(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return ResponseResult.error("请上传文件");
}
String fileName = file.getOriginalFilename();
if (fileName == null || (!fileName.endsWith(".zip"))) {
return ResponseResult.error("请上传ZIP文件(.zip)");
}
String uploadUserId = SecurityUtils.getUserId();
if (importTaskService.hasImportingTask(uploadUserId)) {
return ResponseResult.error("您有正在进行的导入任务,请等待完成后重试");
}
String importNo = "IMP" + System.currentTimeMillis();
String taskId = UUID.randomUUID().toString();
try {
ImportTask task = new ImportTask();
task.setId(taskId);
task.setImportNo(importNo);
task.setBizType("FISH");
task.setFileName(fileName);
task.setFileSize(file.getSize());
task.setStatus("UPLOADED");
task.setUploadUserId(uploadUserId);
task.setUploadTime(new Date());
importTaskService.save(task);
FishImportRequest request = new FishImportRequest();
request.setImportNo(importNo);
request.setUploadUserId(uploadUserId);
request.setBizType("FISH");
FishImportResult result = fishImportService.parseAndMapZip(file, uploadUserId);
importTaskService.updateStatus(taskId, "VALIDATED", null);
importTaskService.updateProgress(taskId, result.getTotalCount(), result.getSuccessCount(), result.getFailedCount());
return ResponseResult.successData(result);
} catch (Exception e) {
importTaskService.markFailed(taskId, "导入失败: " + e.getMessage());
return ResponseResult.error("导入失败: " + e.getMessage());
}
}
@PostMapping("/cancelImport")
@Operation(summary = "取消导入任务")
public ResponseResult cancelImport(@RequestParam String taskId,
@RequestParam String operatorId) {
boolean result = importTaskService.cancelTask(taskId, operatorId);
return result ? ResponseResult.success("取消成功") : ResponseResult.error("取消失败");
}
@GetMapping("/checkImportStatus")
@Operation(summary = "检查用户导入状态")
public ResponseResult checkImportStatus(@RequestParam String uploadUserId) {
boolean hasTask = importTaskService.hasImportingTask(uploadUserId);
ImportTask currentTask = importTaskService.getCurrentTaskByUserId(uploadUserId);
return ResponseResult.successData(java.util.Map.of(
"hasImportingTask", hasTask,
"currentTask", currentTask
));
}
@PostMapping("/cleanupTemp")
@Operation(summary = "清理临时文件")
public ResponseResult cleanupTemp(@RequestParam String tempDir) {
try {
com.yfd.platform.data.utils.ZipFileUtil.cleanupTempDir(tempDir);
return ResponseResult.success("清理成功");
} catch (Exception e) {
return ResponseResult.error("清理失败: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.data.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 批量审批请求参数
*/
@Data
@Schema(description = "批量审批请求参数")
public class BatchApproveRequest {
@Schema(description = "草稿数据ID列表")
private List<String> ids;
@Schema(description = "审批意见")
private String approveComment;
}

View File

@ -0,0 +1,18 @@
package com.yfd.platform.data.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 审批驳回请求参数
*/
@Data
@Schema(description = "审批驳回请求参数")
public class BatchRejectRequest {
@Schema(description = "草稿数据ID")
private String id;
@Schema(description = "驳回原因")
private String rejectReason;
}

View File

@ -41,6 +41,7 @@ public class FishDraftData implements Serializable {
*/
private String ftp;
/**
* 鱼类全长
*/
@ -105,7 +106,7 @@ public class FishDraftData implements Serializable {
/**
* 审批批次ID
*/
private Long approvalId;
private String approvalId;
/**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回
@ -125,28 +126,10 @@ public class FishDraftData implements Serializable {
/**
* 水温
*/
@TableField(exist = false)
// @TableField(exist = false)
private BigDecimal wt;
/**
* 电站名称
*/
@TableField(exist = false)
private String engName;
/**
* 基地名称
*/
@TableField(exist = false)
private String baseName;
/**
* 设施名称
*/
@TableField(exist = false)
private String fPname;
/**
* 审批完成时间
@ -177,6 +160,7 @@ public class FishDraftData implements Serializable {
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
private String createdBy;
/**
@ -188,5 +172,44 @@ public class FishDraftData implements Serializable {
/**
* 更新人
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updatedBy;
/**
* 所属基地编码
*/
@TableField(exist = false)
private String baseId;
/**
* 电站名称
*/
@TableField(exist = false)
private String engName;
/**
* 基地名称
*/
@TableField(exist = false)
private String baseName;
/**
* 流域编码
*/
@TableField(exist = false)
private String rvcd;
/**
* 设施名称
*/
@TableField(exist = false)
private String fpname;
/**
* 鱼类名称
*/
@TableField(exist = false)
private String ftpName;
}

View File

@ -0,0 +1,20 @@
package com.yfd.platform.data.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
@Data
public class FishImportRequest implements Serializable {
private String filePath;
private String importNo;
private String bizType = "FISH";
private String uploadUserId;
private Map<String, String> columnMapping;
}

View File

@ -0,0 +1,47 @@
package com.yfd.platform.data.domain;
import lombok.Data;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Data
public class FishImportResult {
private List<FishImportRow> successRows;
private List<FishImportRow> failedRows;
private List<String> unrecognizedFields;
private Map<String, String> imageFiles;
private Map<String, String> videoFiles;
private String tempDir;
private String excelFileName;
private String excelFilePath;
private int totalCount;
private int successCount;
private int failedCount;
private String summary;
public FishImportResult() {
this.successRows = new ArrayList<>();
this.failedRows = new ArrayList<>();
this.unrecognizedFields = new ArrayList<>();
this.imageFiles = new LinkedHashMap<>();
this.videoFiles = new LinkedHashMap<>();
}
@Data
public static class FishImportRow {
private int rowIndex;
private FishDraftData data;
private List<String> unrecognizedFields;
private List<String> warnings;
public FishImportRow(int rowIndex) {
this.rowIndex = rowIndex;
this.unrecognizedFields = new ArrayList<>();
this.warnings = new ArrayList<>();
}
}
}

View File

@ -83,7 +83,7 @@ public class ImportTask implements Serializable {
/**
* 上传人ID
*/
private Long uploadUserId;
private String uploadUserId;
/**
* 上传时间

View File

@ -0,0 +1,219 @@
package com.yfd.platform.data.domain.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 过鱼数据关联查询VO
* </p>
*/
@Data
public class FishDraftDataVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private String id;
/**
* 过鱼设施编码
*/
private String stcd;
/**
* 填报时间
*/
private Date tm;
/**
* 鱼类
*/
private String ftp;
/**
* 鱼类名称
*/
private String ftpName;
/**
* 鱼类全长
*/
private String fsz;
/**
* 过鱼数量
*/
private Integer fcnt;
/**
* 平均体重
*/
private String fwet;
/**
* 水温
*/
private BigDecimal wt;
/**
* 开始日期
*/
private Date strdt;
/**
* 结束日期
*/
private Date enddt;
/**
* 游向上行/下行/上行折返/下行折返
*/
private String direction;
/**
* 年份
*/
private Integer yr;
/**
* 主要月份
*/
private Integer mouth;
/**
* 过鱼视频文件路径
*/
private String vdpth;
/**
* 图片文件路径
*/
private String picpth;
/**
* 是否鱼苗0否 1是
*/
private Integer isfs;
/**
* 数据来源MANUAL手工 / IMPORT导入 / AUTO自动
*/
private String sourceType;
/**
* 审批批次ID
*/
private String approvalId;
/**
* 状态DRAFT未提交 / SUBMITTED已提交 / APPROVED已通过 / REJECTED已驳回
*/
private String status;
/**
* 锁定标识1锁定不可编辑 0可编辑
*/
private Integer lockFlag;
/**
* 提交审批时间
*/
private Date submitTime;
/**
* 审批完成时间
*/
private Date approveTime;
/**
* 删除标记0未删除 1已删除
*/
private Integer deletedFlag;
/**
* 删除人
*/
private String deletedBy;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 创建时间
*/
private Date createdAt;
/**
* 创建人
*/
private String createdBy;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 更新人
*/
private String updatedBy;
/**
* 设施名称过鱼设施表
*/
private String stnm;
/**
* 过鱼设施类型过鱼设施表
*/
private String sttp;
/**
* 所属电站编码过鱼设施表
*/
private String rstcd;
/**
* 电站名称电站表
*/
private String ennm;
/**
* 所属基地编码电站表
*/
private String baseId;
/**
* 所属基地名称电站表
*/
private String baseName;
/**
* 流域编码电站表
*/
private String rvcd;
/**
* 电站经度电站表
*/
private Double lgtd;
/**
* 电站纬度电站表
*/
private Double lttd;
/**
* 排序字段
*/
private Integer orderIndex;
}

View File

@ -1,7 +1,9 @@
package com.yfd.platform.data.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.data.domain.FishDraftData;
import com.yfd.platform.data.domain.vo.FishDraftDataVO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@ -14,11 +16,36 @@ import java.util.List;
*/
public interface FishDraftDataMapper extends BaseMapper<FishDraftData> {
/**
* 关联查询过鱼数据分页
*/
Page<FishDraftDataVO> selectJoinPage(Page<FishDraftDataVO> page,
@Param("stcd") String stcd,
@Param("rstcd") String rstcd,
@Param("baseId") String baseId,
@Param("direction") String direction,
@Param("status") String status,
@Param("ftp") String ftp,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 关联查询过鱼数据不分页
*/
List<FishDraftDataVO> selectJoinList(@Param("stcd") String stcd,
@Param("rstcd") String rstcd,
@Param("baseId") String baseId,
@Param("direction") String direction,
@Param("status") String status,
@Param("ftp") String ftp,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 根据审批批次ID查询草稿数据
*/
@Select("SELECT * FROM FISH_DRAFT_DATA WHERE APPROVAL_ID = #{approvalId} ORDER BY TM DESC")
List<FishDraftData> selectByApprovalId(@Param("approvalId") Long approvalId);
List<FishDraftData> selectByApprovalId(@Param("approvalId") String approvalId);
/**
* 根据状态查询草稿数据

View File

@ -36,7 +36,17 @@ public interface ImportTaskMapper extends BaseMapper<ImportTask> {
* 根据上传人查询
*/
@Select("SELECT * FROM IMPORT_TASK WHERE UPLOAD_USER_ID = #{uploadUserId} ORDER BY CREATED_AT DESC")
List<ImportTask> selectByUploadUserId(@Param("uploadUserId") Long uploadUserId);
List<ImportTask> selectByUploadUserId(@Param("uploadUserId") String uploadUserId);
@Select("<script>" +
"SELECT * FROM IMPORT_TASK WHERE UPLOAD_USER_ID = #{uploadUserId} AND STATUS IN " +
"<foreach item='status' collection='statuses' open='(' separator=',' close=')'>" +
"#{status}" +
"</foreach>" +
" ORDER BY CREATED_AT DESC" +
"</script>")
List<ImportTask> selectByUserIdAndStatuses(@Param("uploadUserId") String uploadUserId,
@Param("statuses") List<String> statuses);
/**
* 查询过期的任务

View File

@ -2,7 +2,9 @@ package com.yfd.platform.data.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.data.domain.FishDraftData;
import com.yfd.platform.data.domain.vo.FishDraftDataVO;
import java.util.List;
@ -14,14 +16,19 @@ import java.util.List;
public interface IFishDraftDataService extends IService<FishDraftData> {
/**
* 分页查询草稿数据
* 分页查询草稿数据关联电站和设施表
*/
Page<FishDraftData> queryPageList(Page<FishDraftData> page, String stcd, String status, String ftp);
Page<FishDraftDataVO> queryPageList(DataSourceRequest dataSourceRequest);
/**
* 查询草稿数据列表关联电站和设施表不分页
*/
List<FishDraftDataVO> queryJoinList(DataSourceRequest dataSourceRequest);
/**
* 根据审批批次ID查询
*/
List<FishDraftData> getByApprovalId(Long approvalId);
List<FishDraftData> getByApprovalId(String approvalId);
/**
* 根据状态查询
@ -46,25 +53,42 @@ public interface IFishDraftDataService extends IService<FishDraftData> {
/**
* 删除草稿软删除
*/
boolean removeDraft(Long id, String operatorId);
boolean removeDraft(String id, String operatorId);
/**
* 提交草稿
*/
boolean submitDraft(Long id, String operatorId);
boolean submitDraft(String id, String operatorId);
/**
* 批量提交草稿
*/
boolean submitDrafts(List<Long> ids, String operatorId);
boolean submitDrafts(List<String> ids);
/**
* 批量审批通过
*/
boolean batchApprove(List<String> ids, String approveComment);
/**
* 批量审批驳回
*/
boolean batchReject(String id, String rejectReason);
/**
* 锁定草稿
*/
boolean lockDraft(Long id);
boolean lockDraft(String id);
/**
* 解锁草稿
*/
boolean unlockDraft(Long id);
boolean unlockDraft(String id);
boolean batchRemoveDraft(List<String> ids);
/**
* 审批人修改数据并记录变更日志
*/
boolean updateByIdWithLog(FishDraftData fishDraftData);
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.data.service;
import com.yfd.platform.data.domain.FishImportRequest;
import com.yfd.platform.data.domain.FishImportResult;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* <p>
* 过鱼数据Excel导入服务接口
* </p>
*/
public interface IFishImportService {
FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream);
FishImportResult parseAndMapExcelFromPath(FishImportRequest request);
FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId);
}

View File

@ -0,0 +1,40 @@
package com.yfd.platform.data.service;
import com.yfd.platform.data.domain.FishImportResult;
import java.io.InputStream;
/**
* <p>
* 过鱼数据ZIP导入服务接口
* </p>
*/
public interface IFishZipImportService {
/**
* 解析过鱼数据ZIP文件并映射字段
*
* @param importTaskId 导入任务ID
* @param inputStream ZIP文件输入流
* @param uploadUserId 上传用户ID
* @return 解析结果
*/
FishImportResult parseAndMapZip(String importTaskId, InputStream inputStream, String uploadUserId);
/**
* 检查用户是否有正在进行的导入任务
*
* @param uploadUserId 上传用户ID
* @return true表示有任务在进行false表示可以开始新任务
*/
boolean hasImportingTask(String uploadUserId);
/**
* 取消导入任务
*
* @param importTaskId 任务ID
* @param operatorId 操作人ID
* @return 是否成功
*/
boolean cancelImportTask(String importTaskId, String operatorId);
}

View File

@ -62,4 +62,19 @@ public interface IImportTaskService extends IService<ImportTask> {
* 删除过期任务
*/
boolean deleteExpiredTasks();
/**
* 检查用户是否有正在进行的导入任务
*/
boolean hasImportingTask(String uploadUserId);
/**
* 取消导入任务
*/
boolean cancelTask(String taskId, String operatorId);
/**
* 获取用户当前正在进行的导入任务
*/
ImportTask getCurrentTaskByUserId(String uploadUserId);
}

View File

@ -1,19 +1,30 @@
package com.yfd.platform.data.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.data.domain.ApprovalMain;
import com.yfd.platform.data.domain.FishDraftData;
import com.yfd.platform.data.domain.vo.FishDraftDataVO;
import com.yfd.platform.data.mapper.FishDraftDataMapper;
import com.yfd.platform.data.service.IApprovalChangeLogService;
import com.yfd.platform.data.service.IApprovalLogService;
import com.yfd.platform.data.service.IApprovalMainService;
import com.yfd.platform.data.service.IFishDraftDataService;
import com.yfd.platform.utils.KendoUtil;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
* <p>
@ -32,19 +43,52 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
@Resource
private IApprovalChangeLogService approvalChangeLogService;
@Resource
private IApprovalLogService approvalLogService;
@Resource
private ObjectMapper objectMapper;
@Override
public Page<FishDraftData> queryPageList(Page<FishDraftData> page, String stcd, String status, String ftp) {
return this.page(page, this.lambdaQuery()
.eq(StringUtils.hasText(stcd), FishDraftData::getStcd, stcd)
.eq(StringUtils.hasText(status), FishDraftData::getStatus, status)
.like(StringUtils.hasText(ftp), FishDraftData::getFtp, ftp)
.eq(FishDraftData::getDeletedFlag, 0)
.orderByDesc(FishDraftData::getTm)
.getWrapper());
public Page<FishDraftDataVO> queryPageList(DataSourceRequest dataSourceRequest) {
Page<FishDraftDataVO> page = KendoUtil.getPage(dataSourceRequest);
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd");
String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "rstcd");
String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId");
String ftp = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "ftp");
String direction = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "direction");
String status = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "status");
String TM = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "TM");
String startTime=null;
String endTime=null;
// 如果 startTime endTime 为空尝试从 TM 字段解析
if (StrUtil.isNotBlank(TM)&& TM.split( ",").length==2) {
startTime=TM.split(",")[0];
endTime=TM.split(",")[1];
}
Page<FishDraftDataVO> resultPage = fishDraftDataMapper.selectJoinPage(
page, stcd, rstcd, baseId, direction, status, ftp, startTime, endTime);
return resultPage;
}
@Override
public List<FishDraftData> getByApprovalId(Long approvalId) {
public List<FishDraftDataVO> queryJoinList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd");
String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "rstcd");
String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId");
String direction = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "direction");
String status = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "status");
String ftp = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "ftp");
String startTime = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "startTime");
String endTime = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "endTime");
return fishDraftDataMapper.selectJoinList(stcd, rstcd, baseId, direction, status, ftp, startTime, endTime);
}
@Override
public List<FishDraftData> getByApprovalId(String approvalId) {
return fishDraftDataMapper.selectByApprovalId(approvalId);
}
@ -64,8 +108,6 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
fishDraftData.setStatus("DRAFT");
fishDraftData.setDeletedFlag(0);
fishDraftData.setLockFlag(0);
fishDraftData.setCreatedAt(new Date());
fishDraftData.setUpdatedAt(new Date());
return this.save(fishDraftData);
}
@ -76,74 +118,274 @@ public class FishDraftDataServiceImpl extends ServiceImpl<FishDraftDataMapper, F
if (existing == null || existing.getLockFlag() == 1) {
return false;
}
fishDraftData.setStatus("DRAFT");
fishDraftData.setUpdatedAt(new Date());
return this.updateById(fishDraftData);
boolean isSubmitted = existing.getApprovalId() != null && StrUtil.isNotBlank(existing.getApprovalId());
try {
String beforeJson = objectMapper.writeValueAsString(existing);
fishDraftData.setStatus(existing.getStatus());
boolean result = this.updateById(fishDraftData);
if (result && isSubmitted) {
FishDraftData after = this.getById(fishDraftData.getId());
String afterJson = objectMapper.writeValueAsString(after);
String changeJson = buildChangeJson(beforeJson, afterJson, existing, after);
approvalChangeLogService.logChange(
existing.getApprovalId(),
fishDraftData.getId(),
"FISH",
"UPDATE",
changeJson,
SecurityUtils.getUserId()
);
}
return result;
} catch (Exception e) {
throw new RuntimeException("记录变更日志失败", e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean removeDraft(Long id, String operatorId) {
public boolean removeDraft(String id, String operatorId) {
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData == null || fishDraftData.getLockFlag() == 1) {
return false;
}
fishDraftData.setDeletedFlag(1);
fishDraftData.setDeletedBy(operatorId);
fishDraftData.setDeletedAt(new Date());
fishDraftData.setUpdatedAt(new Date());
return this.updateById(fishDraftData);
}
@Override
public boolean batchRemoveDraft(List<String> ids) {
long count = this.count(new LambdaQueryWrapper<FishDraftData>().in(FishDraftData::getId, ids).eq(FishDraftData::getLockFlag, 1));
if(count > 0){
return false;
}
LambdaUpdateWrapper<FishDraftData> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(FishDraftData::getId, ids);
updateWrapper.set(FishDraftData::getDeletedFlag, 1);
String userId = SecurityUtils.getUserId();
updateWrapper.set(FishDraftData::getDeletedBy,userId );
return this.update(updateWrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submitDraft(Long id, String operatorId) {
public boolean submitDraft(String id, String operatorId) {
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData == null || fishDraftData.getLockFlag() == 1) {
return false;
}
ApprovalMain approvalMain = new ApprovalMain();
approvalMain.setApprovalNo("APR" + System.currentTimeMillis());
approvalMain.setBizType("FISH");
approvalMain.setDataCount(1);
approvalMain.setApplyUserId(operatorId);
approvalMain.setApplyTime(new Date());
approvalMain.setStatus("PENDING");
approvalMainService.save(approvalMain);
fishDraftData.setApprovalId(approvalMain.getId());
fishDraftData.setStatus("SUBMITTED");
fishDraftData.setSubmitTime(new Date());
fishDraftData.setUpdatedAt(new Date());
return this.updateById(fishDraftData);
boolean result = this.updateById(fishDraftData);
if (result) {
approvalLogService.logSubmit(approvalMain.getId(), operatorId, "提交草稿");
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submitDrafts(List<Long> ids, String operatorId) {
for (Long id : ids) {
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData != null && fishDraftData.getLockFlag() == 0) {
fishDraftData.setStatus("SUBMITTED");
fishDraftData.setSubmitTime(new Date());
fishDraftData.setUpdatedAt(new Date());
this.updateById(fishDraftData);
public boolean submitDrafts(List<String> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
String operatorId = SecurityUtils.getUserId();
ApprovalMain approvalMain = new ApprovalMain();
approvalMain.setApprovalNo("APR" + System.currentTimeMillis());
approvalMain.setBizType("FISH");
approvalMain.setDataCount(ids.size());
approvalMain.setApplyUserId(operatorId);
approvalMain.setApplyTime(new Date());
approvalMain.setStatus("PENDING");
approvalMainService.save(approvalMain);
LambdaUpdateWrapper<FishDraftData> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(FishDraftData::getId, ids);
updateWrapper.eq(FishDraftData::getLockFlag, 0);
updateWrapper.set(FishDraftData::getApprovalId, approvalMain.getId());
updateWrapper.set(FishDraftData::getStatus, "SUBMITTED");
updateWrapper.set(FishDraftData::getSubmitTime, new Date());
this.update(updateWrapper);
approvalLogService.logSubmit(approvalMain.getId(), operatorId, "批量提交草稿,共" + ids.size() + "");
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean batchApprove(List<String> ids, String approveComment) {
if (ids == null || ids.isEmpty()) {
return false;
}
Date now = new Date();
String operatorId = SecurityUtils.getUserId();
List<FishDraftData> dataList = this.listByIds(ids);
Set<String> processedApprovalIds = new HashSet<>();
List<String> validIds = new ArrayList<>();
for (FishDraftData fishDraftData : dataList) {
if ("SUBMITTED".equals(fishDraftData.getStatus())) {
validIds.add(fishDraftData.getId());
if (fishDraftData.getApprovalId() != null) {
processedApprovalIds.add(fishDraftData.getApprovalId());
}
}
}
if (!validIds.isEmpty()) {
LambdaUpdateWrapper<FishDraftData> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(FishDraftData::getId, validIds);
updateWrapper.set(FishDraftData::getStatus, "APPROVED");
updateWrapper.set(FishDraftData::getApproveTime, now);
updateWrapper.set(FishDraftData::getUpdatedBy, operatorId);
this.update(updateWrapper);
for (String approvalId : processedApprovalIds) {
ApprovalMain approvalMain = approvalMainService.getById(approvalId);
approvalLogService.logApprove(approvalId, SecurityUtils.getUserId(), approveComment);
if (approvalMain != null) {
approvalMain.setStatus("APPROVED");
approvalMain.setApproverId(operatorId);
approvalMain.setApproveTime(now);
approvalMain.setRemark(approveComment);
approvalMainService.updateById(approvalMain);
}
}
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean batchReject(String id, String rejectReason) {
if (StrUtil.isBlank(id)) {
return false;
}
if (StrUtil.isBlank(rejectReason)) {
throw new IllegalArgumentException("驳回原因不能为空");
}
Date now = new Date();
String operatorId = SecurityUtils.getUserId();
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData != null && "SUBMITTED".equals(fishDraftData.getStatus())) {
fishDraftData.setStatus("REJECTED");
fishDraftData.setApproveTime(now);
fishDraftData.setUpdatedBy(operatorId);
boolean result = this.updateById(fishDraftData);
if (result && fishDraftData.getApprovalId() != null) {
approvalLogService.logReject(fishDraftData.getApprovalId(), operatorId, rejectReason);
ApprovalMain approvalMain = approvalMainService.getById(fishDraftData.getApprovalId());
if (approvalMain != null) {
approvalMain.setStatus("REJECTED");
approvalMain.setApproverId(operatorId);
approvalMain.setApproveTime(now);
approvalMain.setRemark(rejectReason);
approvalMainService.updateById(approvalMain);
}
}
return result;
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean lockDraft(Long id) {
public boolean lockDraft(String id) {
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData == null) {
return false;
}
fishDraftData.setLockFlag(1);
fishDraftData.setUpdatedAt(new Date());
return this.updateById(fishDraftData);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean unlockDraft(Long id) {
public boolean unlockDraft(String id) {
FishDraftData fishDraftData = this.getById(id);
if (fishDraftData == null) {
return false;
}
fishDraftData.setLockFlag(0);
fishDraftData.setUpdatedAt(new Date());
return this.updateById(fishDraftData);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateByIdWithLog(FishDraftData fishDraftData) {
FishDraftData existing = this.getById(fishDraftData.getId());
if (existing == null) {
return false;
}
if (existing.getApprovalId() == null || StrUtil.isBlank(existing.getApprovalId())) {
return this.updateById(fishDraftData);
}
try {
String beforeJson = objectMapper.writeValueAsString(existing);
boolean result = this.updateById(fishDraftData);
if (result) {
FishDraftData after = this.getById(fishDraftData.getId());
String afterJson = objectMapper.writeValueAsString(after);
String changeJson = buildChangeJson(beforeJson, afterJson, existing, after);
approvalChangeLogService.logChange(
existing.getApprovalId(),
fishDraftData.getId(),
"FISH",
"UPDATE",
changeJson,
SecurityUtils.getUserId()
);
}
return result;
} catch (Exception e) {
throw new RuntimeException("记录变更日志失败", e);
}
}
private String buildChangeJson(String beforeJson, String afterJson, FishDraftData before, FishDraftData after) {
try {
Map<String, Object> changeInfo = new LinkedHashMap<>();
changeInfo.put("before", objectMapper.readTree(beforeJson));
changeInfo.put("after", objectMapper.readTree(afterJson));
List<String> changedFields = new ArrayList<>();
if (!Objects.equals(before.getStcd(), after.getStcd())) changedFields.add("stcd");
if (!Objects.equals(before.getTm(), after.getTm())) changedFields.add("tm");
if (!Objects.equals(before.getFtp(), after.getFtp())) changedFields.add("ftp");
if (!Objects.equals(before.getFsz(), after.getFsz())) changedFields.add("fsz");
if (!Objects.equals(before.getFcnt(), after.getFcnt())) changedFields.add("fcnt");
if (!Objects.equals(before.getFwet(), after.getFwet())) changedFields.add("fwet");
if (!Objects.equals(before.getStrdt(), after.getStrdt())) changedFields.add("strdt");
if (!Objects.equals(before.getEnddt(), after.getEnddt())) changedFields.add("enddt");
if (!Objects.equals(before.getDirection(), after.getDirection())) changedFields.add("direction");
if (!Objects.equals(before.getYr(), after.getYr())) changedFields.add("yr");
if (!Objects.equals(before.getMouth(), after.getMouth())) changedFields.add("mouth");
if (!Objects.equals(before.getVdpth(), after.getVdpth())) changedFields.add("vdpth");
if (!Objects.equals(before.getPicpth(), after.getPicpth())) changedFields.add("picpth");
if (!Objects.equals(before.getIsfs(), after.getIsfs())) changedFields.add("isfs");
if (!Objects.equals(before.getSourceType(), after.getSourceType())) changedFields.add("sourceType");
if (!Objects.equals(before.getStatus(), after.getStatus())) changedFields.add("status");
changeInfo.put("changed_fields", changedFields);
return objectMapper.writeValueAsString(changeInfo);
} catch (Exception e) {
return "{}";
}
}
}

View File

@ -0,0 +1,737 @@
package com.yfd.platform.data.service.impl;
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.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 org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class FishImportServiceImpl implements IFishImportService {
@Resource
private SdEngInfoBHMapper engInfoBHMapper;
@Resource
private SdHydrobaseMapper hydrobaseMapper;
@Resource
private SdRvcdDicMapper rvcdDicMapper;
@Resource
private SdFpssBHMapper fpssBHMapper;
@Resource
private SdFishDictoryBMapper fishDictoryBMapper;
@Resource
private ISysDictionaryService sysDictionaryService;
@Resource
private ISysDictionaryItemsService sysDictionaryItemsService;
private static final Map<String, String> EXCEL_COLUMN_MAPPING = new LinkedHashMap<>();
private static final Map<Integer, String> EXCEL_COLUMN_INDEX_MAPPING = new LinkedHashMap<>();
private static final Map<String, String> STATION_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> BASE_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> RIVER_NAME_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FISH_DICT_CACHE = new LinkedHashMap<>();
private static final Map<String, String> FPSS_BH_CACHE = new LinkedHashMap<>();
private static final Map<String, String> DIRECTION_DICT_CACHE = new LinkedHashMap<>();
private static final Map<String, String> ISFS_DICT_CACHE = new LinkedHashMap<>();
private static final String DICT_CODE_FISH = "FISH_TYPE";
private static final String DICT_CODE_DIRECTION = "FISH_DIRECTION";
private static final String DICT_CODE_ISFS = "YES_NO";
static {
EXCEL_COLUMN_MAPPING.put("电站名称", "stcd");
EXCEL_COLUMN_MAPPING.put("基地名称", "baseId");
EXCEL_COLUMN_MAPPING.put("流域名称", "rvcd");
EXCEL_COLUMN_MAPPING.put("数据时间", "tm");
EXCEL_COLUMN_MAPPING.put("过鱼时间", "tm");
EXCEL_COLUMN_MAPPING.put("鱼类", "ftp");
EXCEL_COLUMN_MAPPING.put("鱼种类", "ftp");
EXCEL_COLUMN_MAPPING.put("鱼类全长", "fsz");
EXCEL_COLUMN_MAPPING.put("过鱼数量", "fcnt");
EXCEL_COLUMN_MAPPING.put("过鱼数量(尾)", "fcnt");
EXCEL_COLUMN_MAPPING.put("平均体重", "fwet");
EXCEL_COLUMN_MAPPING.put("开始日期", "strdt");
EXCEL_COLUMN_MAPPING.put("结束日期", "enddt");
EXCEL_COLUMN_MAPPING.put("游向", "direction");
EXCEL_COLUMN_MAPPING.put("水温", "wt");
EXCEL_COLUMN_MAPPING.put("年份", "yr");
EXCEL_COLUMN_MAPPING.put("月份", "mouth");
EXCEL_COLUMN_MAPPING.put("过鱼视频文件路径", "vdpth");
EXCEL_COLUMN_MAPPING.put("图片文件路径", "picpth");
EXCEL_COLUMN_MAPPING.put("是否鱼苗", "isfs");
EXCEL_COLUMN_MAPPING.put("数据来源", "sourceType");
EXCEL_COLUMN_MAPPING.put("过鱼设施名称", "fpname");
EXCEL_COLUMN_INDEX_MAPPING.put(0, "baseName");
EXCEL_COLUMN_INDEX_MAPPING.put(1, "stationName");
EXCEL_COLUMN_INDEX_MAPPING.put(2, "fpname");
EXCEL_COLUMN_INDEX_MAPPING.put(3, "tm");
EXCEL_COLUMN_INDEX_MAPPING.put(4, "ftp");
EXCEL_COLUMN_INDEX_MAPPING.put(5, "isfs");
EXCEL_COLUMN_INDEX_MAPPING.put(6, "direction");
EXCEL_COLUMN_INDEX_MAPPING.put(7, "fcnt");
EXCEL_COLUMN_INDEX_MAPPING.put(8, "fsz");
EXCEL_COLUMN_INDEX_MAPPING.put(9, "fwet");
EXCEL_COLUMN_INDEX_MAPPING.put(10, "wt");
}
@Override
public FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream) {
FishImportResult result = new FishImportResult();
try (Workbook workbook = new XSSFWorkbook(inputStream)) {
Sheet sheet = workbook.getSheetAt(0);
return parseSheet(sheet, result);
} catch (IOException e) {
result.setSummary("Excel文件解析失败: " + e.getMessage());
return result;
}
}
@Override
public FishImportResult parseAndMapExcelFromPath(FishImportRequest request) {
FishImportResult result = new FishImportResult();
try (InputStream inputStream = request.getFilePath().startsWith("http")
? new java.net.URL(request.getFilePath()).openStream()
: new java.io.FileInputStream(request.getFilePath())) {
return parseAndMapExcel(request, inputStream);
} catch (IOException e) {
result.setSummary("读取文件失败: " + e.getMessage());
return result;
}
}
private FishImportResult parseSheet(Sheet sheet, FishImportResult result) {
loadStationAndBaseCache();
Row headerRow = sheet.getRow(0);
if (headerRow == null) {
result.setSummary("Excel文件没有表头");
return result;
}
List<String> unrecognizedHeaders = new ArrayList<>();
Map<Integer, String> columnIndexMap = new HashMap<>(EXCEL_COLUMN_INDEX_MAPPING);
int totalRows = sheet.getLastRowNum();
result.setTotalCount(totalRows);
for (int i = 1; i <= totalRows; i++) {
Row row = sheet.getRow(i);
if (row == null || isRowEmpty(row)) {
continue;
}
FishImportResult.FishImportRow importRow = parseRow(row, columnIndexMap, i);
if (importRow.getData() != null && importRow.getWarnings().isEmpty()) {
result.getSuccessRows().add(importRow);
result.setSuccessCount(result.getSuccessCount() + 1);
} else {
result.getFailedRows().add(importRow);
result.setFailedCount(result.getFailedCount() + 1);
}
}
result.setSummary(String.format("共解析%d条数据成功%d条失败%d条未识别字段%s",
result.getTotalCount(), result.getSuccessCount(), result.getFailedCount(),
unrecognizedHeaders.isEmpty() ? "" : String.join(", ", unrecognizedHeaders)));
return result;
}
private FishImportResult.FishImportRow parseRow(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();
Cell cell = row.getCell(columnIndex);
String cellValue = getCellStringValue(cell);
try {
switch (fieldName) {
case "stationName":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("电站名称");
} else {
String stcd = resolveStationCode(cellValue.trim());
if (stcd == null) {
importRow.getWarnings().add(fieldName);
data.setEngName(cellValue.trim());
} else {
data.setEngName(cellValue.trim());
}
}
break;
case "baseName":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("水电基地");
} else {
String baseId = resolveBaseCode(cellValue.trim());
if (baseId == null) {
importRow.getWarnings().add(fieldName);
data.setBaseId(cellValue.trim());
data.setBaseName(cellValue.trim());
} else {
data.setBaseId(baseId);
data.setBaseName(cellValue.trim());
}
}
break;
case "rvcd":
if (StringUtils.hasText(cellValue)) {
String rvcd = resolveRiverCode(cellValue.trim());
if (rvcd == null) {
importRow.getWarnings().add(fieldName);
} else {
data.setRvcd(rvcd);
}
}
break;
case "tm":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("过鱼时间");
} else {
Date tm = parseDate(cellValue);
if (tm == null) {
importRow.getWarnings().add("过鱼时间格式错误: " + cellValue);
}
data.setTm(tm);
}
break;
case "ftp":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("鱼种类");
} else {
String stcd = resolveFishDictCode(cellValue.trim());
if (stcd == null) {
importRow.getWarnings().add(fieldName);
data.setFtp(cellValue.trim());
data.setFtpName(cellValue.trim());
} else {
data.setFtp(stcd);
data.setFtpName(cellValue.trim());
}
}
break;
case "fsz":
data.setFsz(cellValue.trim());
break;
case "fcnt":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("过鱼数量");
} else {
Integer fcnt = parseInteger(cellValue);
if (fcnt == null) {
importRow.getWarnings().add(fieldName);
data.setFcnt(parseInteger(cellValue));
}
data.setFcnt(fcnt);
}
break;
case "fwet":
data.setFwet(cellValue.trim());
break;
case "strdt":
data.setStrdt(parseDate(cellValue));
break;
case "enddt":
data.setEnddt(parseDate(cellValue));
break;
case "direction":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("游向");
} else {
String direction = resolveDirection(cellValue.trim(), importRow);
data.setDirection(direction);
}
break;
case "yr":
data.setYr(parseInteger(cellValue));
break;
case "mouth":
data.setMouth(parseInteger(cellValue));
break;
case "vdpth":
data.setVdpth(cellValue.trim());
break;
case "picpth":
data.setPicpth(cellValue.trim());
break;
case "isfs":
if (StringUtils.hasText(cellValue)) {
String isfs = resolveIsfs(cellValue.trim(), importRow);
data.setIsfs("".equals(isfs) ? 1 : 0);
}
break;
case "sourceType":
data.setSourceType(parseSourceType(cellValue.trim()));
break;
case "fpname":
if (!StringUtils.hasText(cellValue)) {
missingRequiredFields.add("过鱼设施名称");
} else {
String stcd = resolveFpssCode(cellValue.trim());
if (stcd == null) {
importRow.getWarnings().add(fieldName);
data.setStcd(cellValue.trim());
data.setFpname(cellValue.trim());
} else {
data.setFpname(stcd);
data.setStcd(stcd);
}
}
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
// importRow.getWarnings().add("字段[" + fieldName + "]解析异常: " + e.getMessage());
}
}
importRow.setData(data);
return importRow;
}
private void loadStationAndBaseCache() {
if (STATION_NAME_CACHE.isEmpty()) {
List<SdEngInfoBH> stationList = engInfoBHMapper.selectList(null);
for (SdEngInfoBH station : stationList) {
if (StringUtils.hasText(station.getEnnm())) {
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 (BASE_NAME_CACHE.isEmpty()) {
List<SdHydrobase> baseList = hydrobaseMapper.selectList(null);
for (SdHydrobase base : baseList) {
if (StringUtils.hasText(base.getBasename())) {
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 (RIVER_NAME_CACHE.isEmpty()) {
List<SdRvcdDic> riverList = rvcdDicMapper.selectList(null);
for (SdRvcdDic river : riverList) {
if (StringUtils.hasText(river.getRvnm())) {
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 (FISH_DICT_CACHE.isEmpty()) {
List<SdFishDictoryB> sdFishDictoryBS = fishDictoryBMapper.selectList(null);
for (SdFishDictoryB fishDictoryB : sdFishDictoryBS) {
if (StringUtils.hasText(fishDictoryB.getName())) {
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 (FPSS_BH_CACHE.isEmpty()) {
List<SdFpssBH> sdFpssBHS = fpssBHMapper.selectList(null);
for (SdFpssBH sdFpssBH : sdFpssBHS) {
if (StringUtils.hasText(sdFpssBH.getStnm())) {
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());
}
}
}
}
private String resolveStationCode(String stationName) {
if (stationName == null) {
return null;
}
String lowerName = stationName.toLowerCase().trim();
if (STATION_NAME_CACHE.containsKey(lowerName)) {
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())) {
return entry.getValue();
}
}
return null;
}
private String resolveFpssCode(String name) {
if (name == null) {
return null;
}
String lowerName = name.toLowerCase().trim();
if (FPSS_BH_CACHE.containsKey(lowerName)) {
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())) {
return entry.getValue();
}
}
return null;
}
private String resolveFishDictCode(String name) {
if (name == null) {
return null;
}
String lowerName = name.toLowerCase().trim();
if (FISH_DICT_CACHE.containsKey(lowerName)) {
return FISH_DICT_CACHE.get(lowerName);
}
for (Map.Entry<String, String> entry : FISH_DICT_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) {
return entry.getValue();
}
}
return null;
}
private String resolveBaseCode(String baseName) {
if (baseName == null) {
return null;
}
String lowerName = baseName.toLowerCase().trim();
if (BASE_NAME_CACHE.containsKey(lowerName)) {
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())) {
return entry.getValue();
}
}
return null;
}
private String resolveRiverCode(String riverName) {
if (riverName == null) {
return null;
}
String lowerName = riverName.toLowerCase().trim();
if (RIVER_NAME_CACHE.containsKey(lowerName)) {
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())) {
return entry.getValue();
}
}
return null;
}
private String validateFishType(String fishName, FishImportResult.FishImportRow importRow) {
if (fishName == null) {
return null;
}
String lowerName = fishName.toLowerCase().trim();
if (!FISH_DICT_CACHE.isEmpty()) {
if (FISH_DICT_CACHE.containsKey(lowerName)) {
return FISH_DICT_CACHE.get(lowerName);
}
for (Map.Entry<String, String> entry : FISH_DICT_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) {
return entry.getValue();
}
}
}
importRow.getWarnings().add("鱼种类【" + fishName + "】未在字典中找到匹配,请手动确认");
return fishName;
}
private String validateFishFacility(String facilityName, FishImportResult.FishImportRow importRow) {
if (facilityName == null) {
return null;
}
String lowerName = facilityName.toLowerCase().trim();
importRow.getWarnings().add("过鱼设施【" + facilityName + "】暂无可用字典验证,请手动确认");
return facilityName;
}
private String resolveDirection(String direction, FishImportResult.FishImportRow importRow) {
if (direction == null) {
return null;
}
String lowerName = direction.toLowerCase().trim();
if (!DIRECTION_DICT_CACHE.isEmpty()) {
if (DIRECTION_DICT_CACHE.containsKey(lowerName)) {
return DIRECTION_DICT_CACHE.get(lowerName);
}
for (Map.Entry<String, String> entry : DIRECTION_DICT_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) {
return entry.getValue();
}
}
}
if (lowerName.contains("上行") && lowerName.contains("折返")) {
return "上行折返";
} else if (lowerName.contains("下行") && lowerName.contains("折返")) {
return "下行折返";
} else if (lowerName.contains("上行")) {
return "上行";
} else if (lowerName.contains("下行")) {
return "下行";
}
importRow.getWarnings().add("无法识别的游向: " + direction + ",请手动选择");
return direction;
}
private String resolveIsfs(String value, FishImportResult.FishImportRow importRow) {
if (value == null) {
return null;
}
String lowerName = value.toLowerCase().trim();
if (!ISFS_DICT_CACHE.isEmpty()) {
if (ISFS_DICT_CACHE.containsKey(lowerName)) {
return ISFS_DICT_CACHE.get(lowerName);
}
for (Map.Entry<String, String> entry : ISFS_DICT_CACHE.entrySet()) {
if (entry.getKey().contains(lowerName) || lowerName.contains(entry.getKey())) {
return entry.getValue();
}
}
}
if (lowerName.equals("1") || lowerName.equals("") || lowerName.equals("yes") || lowerName.equals("true")) {
return "";
} else if (lowerName.equals("0") || lowerName.equals("") || lowerName.equals("no") || lowerName.equals("false")) {
return "";
}
importRow.getWarnings().add("无法识别的【是否鱼苗】值: " + value + ",将默认设置为【否】");
return "";
}
// private void loadDirectionDict() {
// if (DIRECTION_DICT_CACHE.isEmpty()) {
// try {
// SysDictionary dict = sysDictionaryService.getByDictCode(DICT_CODE_DIRECTION);
// if (dict != null) {
// List<SysDictionaryItems> items = sysDictionaryItemsService.listByDictId(dict.getId());
// for (SysDictionaryItems item : items) {
// if (StringUtils.hasText(item.getItemName())) {
// DIRECTION_DICT_CACHE.put(item.getItemName().trim().toLowerCase(), item.getItemName());
// }
// }
// }
// } catch (Exception e) {
// }
// }
// }
//
// private void loadIsfsDict() {
// if (ISFS_DICT_CACHE.isEmpty()) {
// try {
// SysDictionary dict = sysDictionaryService.getByDictCode(DICT_CODE_ISFS);
// if (dict != null) {
// List<SysDictionaryItems> items = sysDictionaryItemsService.listByDictId(dict.getId());
// for (SysDictionaryItems item : items) {
// if (StringUtils.hasText(item.getItemName())) {
// ISFS_DICT_CACHE.put(item.getItemName().trim().toLowerCase(), item.getItemName());
// }
// }
// }
// } catch (Exception e) {
// }
// }
// }
// private void loadFishDict() {
// if (FISH_DICT_CACHE.isEmpty()) {
// try {
// SysDictionary dict = sysDictionaryService.getByDictCode(DICT_CODE_FISH);
// if (dict != null) {
// List<SysDictionaryItems> items = sysDictionaryItemsService.listByDictId(dict.getId());
// for (SysDictionaryItems item : items) {
// if (StringUtils.hasText(item.getItemName())) {
// FISH_DICT_CACHE.put(item.getItemName().trim().toLowerCase(), item.getItemCode());
// }
// if (StringUtils.hasText(item.getItemCode())) {
// FISH_DICT_CACHE.put(item.getItemCode().trim().toLowerCase(), item.getItemCode());
// }
// }
// }
// } catch (Exception e) {
// }
// }
// }
private String getCellStringValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
return cell.getLocalDateTimeCellValue().toString();
}
return String.valueOf((long) cell.getNumericCellValue());
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
try {
return cell.getStringCellValue();
} catch (Exception e) {
return String.valueOf(cell.getNumericCellValue());
}
default:
return "";
}
}
private boolean isRowEmpty(Row row) {
for (int i = 0; i < row.getLastCellNum(); i++) {
Cell cell = row.getCell(i);
if (cell != null && StringUtils.hasText(getCellStringValue(cell))) {
return false;
}
}
return true;
}
private Date parseDate(String dateStr) {
if (!StringUtils.hasText(dateStr)) {
return null;
}
String[] patterns = {
"yyyy-MM-dd HH:mm:ss",
"yyyy-MM-dd",
"yyyy/MM/dd",
"yyyy.MM.dd",
"yyyyMMdd"
};
for (String pattern : patterns) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
sdf.setLenient(false);
return sdf.parse(dateStr);
} catch (ParseException ignored) {
}
}
return null;
}
private Integer parseInteger(String value) {
if (!StringUtils.hasText(value)) {
return null;
}
try {
return Integer.parseInt(value.trim());
} catch (NumberFormatException e) {
try {
return (int) Double.parseDouble(value.trim());
} catch (NumberFormatException ex) {
return null;
}
}
}
private String parseSourceType(String value) {
if (!StringUtils.hasText(value)) {
return "IMPORT";
}
String v = value.toLowerCase();
if (v.contains("手工") || v.contains("manual") || v.contains("录入")) {
return "MANUAL";
} else if (v.contains("自动") || v.contains("auto") || v.contains("采集")) {
return "AUTO";
} else if (v.contains("导入") || v.contains("import")) {
return "IMPORT";
}
return "IMPORT";
}
@Override
public FishImportResult parseAndMapZip(MultipartFile file, String uploadUserId) {
FishImportResult result = new FishImportResult();
try {
ZipFileUtil.ZipContent zipContent = ZipFileUtil.extractZipToTemp(file);
if (zipContent.excelFilePath == null) {
result.setSummary("ZIP文件中未找到Excel文件");
ZipFileUtil.cleanupTempDir(zipContent.tempDir);
return result;
}
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);
result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s",
zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir));
return result;
} catch (Exception e) {
result.setSummary("ZIP文件解析失败: " + e.getMessage());
return result;
}
}
}

View File

@ -137,4 +137,38 @@ public class ImportTaskServiceImpl extends ServiceImpl<ImportTaskMapper, ImportT
List<String> ids = expiredTasks.stream().map(ImportTask::getId).toList();
return this.removeByIds(ids);
}
@Override
public boolean hasImportingTask(String uploadUserId) {
List<String> activeStatuses = List.of("UPLOADED", "PARSING", "VALIDATING");
List<ImportTask> tasks = importTaskMapper.selectByUserIdAndStatuses(uploadUserId, activeStatuses);
return tasks != null && !tasks.isEmpty();
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean cancelTask(String taskId, String operatorId) {
ImportTask importTask = this.getById(taskId);
if (importTask == null) {
return false;
}
String currentStatus = importTask.getStatus();
if ("CONFIRMED".equals(currentStatus) || "FAILED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) {
return false;
}
importTask.setStatus("CANCELLED");
importTask.setErrorMsg("用户取消: " + operatorId);
importTask.setUpdatedAt(new Date());
return this.updateById(importTask);
}
@Override
public ImportTask getCurrentTaskByUserId(String uploadUserId) {
List<String> activeStatuses = List.of("UPLOADED", "PARSING", "VALIDATING");
List<ImportTask> tasks = importTaskMapper.selectByUserIdAndStatuses(uploadUserId, activeStatuses);
if (tasks == null || tasks.isEmpty()) {
return null;
}
return tasks.get(0);
}
}

View File

@ -0,0 +1,219 @@
package com.yfd.platform.data.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class ZipFileUtil {
public static final String DEFAULT_TEMP_BASE = "D:\\zip_import_temp";
public static class ZipContent {
public String excelFileName;
public String excelFilePath;
public Map<String, String> images;
public Map<String, String> videos;
public Map<String, String> otherFiles;
public String tempDir;
public ZipContent() {
this.images = new HashMap<>();
this.videos = new HashMap<>();
this.otherFiles = new HashMap<>();
}
public InputStream getExcelStream() throws IOException {
if (excelFilePath == null) {
return null;
}
return new FileInputStream(excelFilePath);
}
}
public static String getDefaultTempDir() {
return DEFAULT_TEMP_BASE;
}
public static ZipContent extractZipToTemp(MultipartFile file) throws IOException {
return extractZipToTemp(file, DEFAULT_TEMP_BASE);
}
public static ZipContent extractZipToTemp(MultipartFile file, String baseTempDir) throws IOException {
ZipContent content = new ZipContent();
String taskId = UUID.randomUUID().toString().substring(0, 8);
Path tempDirPath = Paths.get(baseTempDir, "zip_" + taskId);
Files.createDirectories(tempDirPath);
content.tempDir = tempDirPath.toString();
File zipFile = new File(tempDirPath.toFile(), "upload.zip");
file.transferTo(zipFile);
try {
if (!isValidZipFile(zipFile)) {
throw new IOException("文件不是有效的ZIP格式或已损坏");
}
IOException lastException = null;
Charset[] charsets = new Charset[]{
StandardCharsets.UTF_8,
Charset.forName("GBK"),
StandardCharsets.ISO_8859_1,
Charset.forName("GB18030")
};
for (Charset charset : charsets) {
try {
content = extractFromZipFile(zipFile, tempDirPath.toFile(), charset);
content.tempDir = tempDirPath.toString();
return content;
} catch (IOException e) {
lastException = e;
content = new ZipContent();
content.tempDir = tempDirPath.toString();
}
}
throw lastException != null ? lastException : new IOException("无法解析ZIP文件");
} finally {
if (zipFile.exists()) {
zipFile.delete();
}
}
}
private static boolean isValidZipFile(File file) {
if (file == null || file.length() < 4) {
return false;
}
try (FileInputStream fis = new FileInputStream(file)) {
byte[] signature = new byte[4];
int read = fis.read(signature);
if (read != 4) {
return false;
}
return signature[0] == 0x50 && signature[1] == 0x4B &&
signature[2] == 0x03 && signature[3] == 0x04;
} catch (IOException e) {
return false;
}
}
private static ZipContent extractFromZipFile(File zipFile, File tempDir, Charset charset) throws IOException {
ZipContent content = new ZipContent();
try (ZipFile zip = new ZipFile(zipFile, charset)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entry.isDirectory()) {
continue;
}
try (InputStream is = zip.getInputStream(entry)) {
String lowerName = entryName.toLowerCase();
if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
String excelPath = saveFileToDir(is, tempDir, "excel", getFileName(entryName));
content.excelFileName = getFileName(entryName);
content.excelFilePath = excelPath;
} else if (isImageFile(lowerName)) {
String folder = "images";
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
content.images.put(entryName, path);
} else if (isVideoFile(lowerName)) {
String folder = "videos";
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
content.videos.put(entryName, path);
} else {
String folder = "others";
String path = saveFileToDir(is, tempDir, folder, getFileName(entryName));
content.otherFiles.put(entryName, path);
}
}
}
}
return content;
}
private static String getFileName(String entryName) {
if (entryName == null) return "";
int lastSep = Math.max(entryName.lastIndexOf('/'), entryName.lastIndexOf('\\'));
return lastSep >= 0 ? entryName.substring(lastSep + 1) : entryName;
}
private static String saveFileToDir(InputStream is, File tempDir, String subFolder, String fileName) throws IOException {
File folder = new File(tempDir, subFolder);
if (!folder.exists()) {
folder.mkdirs();
}
File file = new File(folder, fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
return file.getAbsolutePath();
}
private static boolean isImageFile(String fileName) {
return fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") ||
fileName.endsWith(".png") || fileName.endsWith(".gif") ||
fileName.endsWith(".bmp") || fileName.endsWith(".webp");
}
private static boolean isVideoFile(String fileName) {
return fileName.endsWith(".mp4") || fileName.endsWith(".avi") ||
fileName.endsWith(".mov") || fileName.endsWith(".wmv") ||
fileName.endsWith(".flv") || fileName.endsWith(".mkv");
}
public static void cleanupTempDir(String tempDir) {
if (tempDir == null || tempDir.isEmpty()) {
return;
}
File dir = new File(tempDir);
if (dir.exists()) {
deleteDirectory(dir);
}
}
private static void deleteDirectory(File dir) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteDirectory(file);
} else {
file.delete();
}
}
}
dir.delete();
}
public static String getFileExtension(String fileName) {
if (fileName == null) return "";
int lastDot = fileName.lastIndexOf('.');
return lastDot >= 0 ? fileName.substring(lastDot + 1).toLowerCase() : "";
}
}

View File

@ -69,6 +69,13 @@ public class SdEngInfoBHController {
return ResponseResult.successData(engInfoBHService.getByRvcd(rvcd));
}
@GetMapping("/dropdown")
@Operation(summary = "电站下拉列表(根据基地编码筛选 + 支持名称模糊搜索)")
public ResponseResult dropdown(@RequestParam(required = false) String baseId,
@RequestParam(required = false) String ennm) {
return ResponseResult.successData(engInfoBHService.selectForDropdown(baseId, ennm));
}
@Log(module = "电站管理", value = "新增电站")
@PostMapping("/add")
@Operation(summary = "新增电站")

View File

@ -0,0 +1,92 @@
package com.yfd.platform.env.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.env.domain.SdFishDictoryB;
import com.yfd.platform.env.service.ISdFishDictoryBService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* 鱼类字典表 前端控制器
* </p>
*/
@RestController
@RequestMapping("/env/fishDictory")
@Tag(name = "鱼类字典管理")
public class SdFishDictoryBController {
@Resource
private ISdFishDictoryBService sdFishDictoryBService;
@PostMapping("/queryPageList")
@Operation(summary = "分页查询鱼类字典列表(支持动态过滤和排序)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<SdFishDictoryB> page = DataSourceRequestUtil.executeQuery(
request,
SdFishDictoryB.class,
sdFishDictoryBService
);
return ResponseResult.successData(page);
}
@PostMapping("/list")
@Operation(summary = "查询鱼类字典列表(支持动态过滤和排序,不分页)")
public ResponseResult list(@RequestBody DataSourceRequest request) {
List<SdFishDictoryB> list = DataSourceRequestUtil.executeList(
request,
SdFishDictoryB.class,
sdFishDictoryBService
);
return ResponseResult.successData(list);
}
@GetMapping("/listByName")
@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)
));
}
@GetMapping("/getById")
@Operation(summary = "根据ID查询鱼类字典")
public ResponseResult getById(@RequestParam String id) {
return ResponseResult.successData(sdFishDictoryBService.getById(id));
}
@Log(module = "鱼类字典管理", value = "新增鱼类字典")
@PostMapping("/add")
@Operation(summary = "新增鱼类字典")
public ResponseResult add(@RequestBody SdFishDictoryB fishDictoryB) {
boolean result = sdFishDictoryBService.add(fishDictoryB);
return result ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败");
}
@Log(module = "鱼类字典管理", value = "修改鱼类字典")
@PostMapping("/update")
@Operation(summary = "修改鱼类字典")
public ResponseResult update(@RequestBody SdFishDictoryB fishDictoryB) {
boolean result = sdFishDictoryBService.updateById(fishDictoryB);
return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
}
@Log(module = "鱼类字典管理", value = "删除鱼类字典")
@PostMapping("/delete")
@Operation(summary = "删除鱼类字典")
public ResponseResult delete(@RequestParam String id) {
boolean result = sdFishDictoryBService.deleteById(id);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
}

View File

@ -0,0 +1,91 @@
package com.yfd.platform.env.controller;
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.SdFpssBH;
import com.yfd.platform.env.service.ISdFpssBHService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* 过鱼设施表 前端控制器
* </p>
*/
@RestController
@RequestMapping("/env/fpss")
@Tag(name = "过鱼设施管理")
public class SdFpssBHController {
@Resource
private ISdFpssBHService sdFpssBHService;
@GetMapping("/queryPageList")
@Operation(summary = "分页查询过鱼设施列表")
public ResponseResult queryPageList(
@RequestParam(required = false) String stcd,
@RequestParam(required = false) String sttp,
@RequestParam(required = false) String rstcd,
@RequestParam(required = false) Integer usfl,
@RequestParam(defaultValue = "1") Long pageNum,
@RequestParam(defaultValue = "10") Long pageSize) {
Page<SdFpssBH> page = new Page<>(pageNum, pageSize);
Page<SdFpssBH> result = sdFpssBHService.selectPage(stcd, sttp, rstcd, usfl, page);
return ResponseResult.successData(result);
}
@GetMapping("/list")
@Operation(summary = "查询所有过鱼设施")
public ResponseResult list() {
return ResponseResult.successData(sdFpssBHService.list());
}
@GetMapping("/getById")
@Operation(summary = "根据编码查询过鱼设施")
public ResponseResult getById(@RequestParam String stcd, @RequestParam String sttp) {
return ResponseResult.successData(sdFpssBHService.getDetail(stcd, sttp));
}
@GetMapping("/getByRstcd")
@Operation(summary = "根据电站编码查询过鱼设施")
public ResponseResult getByRstcd(@RequestParam String rstcd) {
return ResponseResult.successData(sdFpssBHService.getByRstcd(rstcd));
}
@GetMapping("/dropdown")
@Operation(summary = "设施下拉列表(根据电站编码筛选 + 支持名称模糊搜索 + 支持基地编码筛选)")
public ResponseResult dropdown(@RequestParam(required = false) String rstcd,
@RequestParam(required = false) String stnm,
@RequestParam(required = false) String baseId) {
return ResponseResult.successData(sdFpssBHService.selectForDropdown(rstcd, stnm, baseId));
}
@Log(module = "过鱼设施管理", value = "新增过鱼设施")
@PostMapping("/add")
@Operation(summary = "新增过鱼设施")
public ResponseResult add(@RequestBody SdFpssBH sdFpssBH) {
boolean result = sdFpssBHService.add(sdFpssBH);
return result ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败");
}
@Log(module = "过鱼设施管理", value = "修改过鱼设施")
@PostMapping("/update")
@Operation(summary = "修改过鱼设施")
public ResponseResult update(@RequestBody SdFpssBH sdFpssBH) {
boolean result = sdFpssBHService.updateById(sdFpssBH);
return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
}
@Log(module = "过鱼设施管理", value = "删除过鱼设施")
@PostMapping("/delete")
@Operation(summary = "删除过鱼设施")
public ResponseResult delete(@RequestParam String stcd, @RequestParam String sttp) {
boolean result = sdFpssBHService.deleteById(stcd, sttp);
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
}

View File

@ -7,9 +7,9 @@ import com.yfd.platform.env.domain.SdHydrobase;
import com.yfd.platform.env.service.ISdHydrobaseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
@ -62,6 +62,12 @@ public class SdHydrobaseController {
return ResponseResult.successData(hydrobaseService.getById(baseid));
}
@GetMapping("/dropdown")
@Operation(summary = "基地下拉列表(支持名称模糊搜索)")
public ResponseResult dropdown(@RequestParam(required = false) String basename) {
return ResponseResult.successData(hydrobaseService.selectForDropdown(basename));
}
// @Log(module = "基地管理", value = "新增基地")
@PostMapping("/add")
@Operation(summary = "新增基地")

View File

@ -0,0 +1,272 @@
package com.yfd.platform.env.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 鱼类字典信息表
* </p>
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("SD_FISHDICTORY_B")
public class SdFishDictoryB implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(type = IdType.INPUT)
private String id;
/**
* 编码
*/
private String code;
/**
* 名称
*/
private String name;
/**
* 英文名称
*/
private String nameEn;
/**
* 俗名
*/
private String alias;
/**
* LOGO
*/
private String logo;
/**
* 介绍
*/
private String introduce;
/**
* 介绍弹窗图片
*/
private String inffile;
/**
*
*/
private String orders;
/**
*
*/
private String family;
/**
*
*/
private String genus;
/**
*
*/
private String species;
/**
* 分类1=淡水 2=海水
*/
private Integer type;
/**
* 成鱼大小单位cm
*/
private String fsz;
/**
* 是否珍稀鱼类0= 1=
*/
private Integer rare;
/**
* 物种来源1=本土物种 2=外来物种
*/
private Integer specOrigin;
/**
* 保护类型1=濒危 2=极危 3=近危 4=易危 5=重点保护 6=无危 7=国家二级 8=市二级保护
*/
private Integer ptype;
/**
* 所属流域
*/
private String rvcd;
/**
* 洄游习性
*/
private String habitMigrat;
/**
* 摄食习性
*/
private String feedingHabit;
/**
* 产卵特性
*/
private String spawnCharact;
/**
* 主要食物
*/
private String food;
/**
* 觅食时段
*/
private String timeFeed;
/**
* 产地及产期
*/
private String orignDate;
/**
* 适宜温度单位
*/
private String pretemp;
/**
* 适宜流速单位m/s
*/
private String flowRate;
/**
* 适宜水深单位m
*/
private String depth;
/**
* 适宜底质
*/
private String botmMater;
/**
* 水质要求1= 2= 3= 4= 5= 6=劣质V
*/
private String wqtq;
/**
* 主要生活环境 1=流水生境 2=静缓流生境 3=洞穴生境
*/
private Integer habitat;
/**
* 种群现状 1=优势种 2=常见种 3=少见种 4=记录种
*/
private Integer situation;
/**
* 资源类型 1=保护鱼类 2=特有鱼类 3=重要经济鱼类 4=濒危状况
*/
private Integer resourceType;
/**
* 形态描述
*/
private String shapedesc;
/**
* 保护级别
*/
private String protectlvl;
/**
* 栖息习性
*/
private String habitation;
/**
* 附件
*/
private String fid;
/**
* 描述
*/
private String description;
/**
* 是否启用0=禁用 1=启用
*/
private Integer enable;
/**
* 系统内置项0= 1=
*/
private Integer internal;
/**
* 排序
*/
private Integer orderIndex;
/**
* 创建人关联SYS_USER.ID
*/
private String recordUser;
/**
* 创建时间
*/
private Date recordTime;
/**
* 更新人关联SYS_USER.ID
*/
private String modifyUser;
/**
* 更新时间
*/
private Date modifyTime;
/**
* 是否已删除0=未删除 1=已删除
*/
private Integer isDeleted;
/**
* 删除人关联SYS_USER.ID
*/
private String deleteUser;
/**
* 删除时间
*/
private Date deleteTime;
/**
* 产卵月份多个月份以逗号分隔
*/
private String spawnMonth;
/**
* 数据来源
*/
private String vlsr;
/**
* 数据来源时间
*/
private Date vlsrTm;
}

View File

@ -0,0 +1,382 @@
package com.yfd.platform.env.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p>
* 过鱼设施工程信息表
* </p>
*/
@Data
@TableName("SD_FPSS_B_H")
public class SdFpssBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 过鱼设施编码
*/
@TableId(type = IdType.INPUT)
private String stcd;
/**
* 设施名称
*/
private String stnm;
/**
* 数据时间
*/
private Date tm;
/**
* 过鱼设施类型字典编码sd_fpss_b_h.sttp
* FP_1=鱼道 FP_2=仿自然通道 FP_3=集运鱼系统 FP_4=升鱼机 FP_5=其它过鱼方式 FP_6=网捕过坝
*/
private String sttp;
/**
* 所属建设阶段 字典编码common.blprd
* 1001000=规划 1002000=预可研 1003000=环评 1004000=可研 1005000=在建 1006000=招标设计
* 1007000=施工详图 1009000=建设 1010000=蓄水阶段环保验收 1011000=竣工 1012000=竣工环保验收 1013000=环境影响后评价
*/
private Integer blprd;
/**
* 经度单位(°)
*/
private BigDecimal lgtd;
/**
* 纬度单位(°)
*/
private BigDecimal lttd;
/**
* 高程单位m
*/
private BigDecimal elev;
/**
* 站址/位置
*/
private String stlc;
/**
* 是否启用 字典编码common.enabled 0=禁用 1=启用
*/
private Integer usfl;
/**
* 数据是否接入 字典编码common.yn 0= 1=
*/
private Integer dtin;
/**
* 数据接入时间
*/
private Date dtinTm;
/**
* 排序按照业务规则"升序"
*/
private Integer orderIndex;
/**
* 所属电站编码关联SD_ENGINFO_B_H.STCD
*/
private String rstcd;
/**
* 规划设计日期
*/
private Date stdsdt;
/**
* 计划开工日期
*/
private Date pststdt;
/**
* 计划完工日期
*/
private Date pesstdt;
/**
* 开工日期
*/
private Date swdt;
/**
* 建成日期
*/
private Date jcdt;
/**
* 退役/拆除日期
*/
private Date wddt;
/**
* 建设状态分类0=未建/规划(3,4,5,6,为空) 1=在建(2,7,8) 2=已建(1,10,11)
*/
private Integer bldsttCode;
/**
* 简介
*/
private String introduce;
/**
* LOGO
*/
private String logo;
/**
* 介绍弹窗图片
*/
private String inffile;
/**
* 投资单位亿元
*/
private BigDecimal inv;
/**
* 鱼道型式
*/
private String ydxs;
/**
* 鱼道总长度单位m
*/
private BigDecimal ydzcd;
/**
* 鱼道进口运行设计水位单位m
*/
private BigDecimal ydjkz;
/**
* 鱼道进口数量单位
*/
private Integer ydjkcnt;
/**
* 鱼道或仿自然通道-进口高程单位m
*/
private BigDecimal jkhg;
/**
* 鱼道进口诱鱼型式
*/
private String ydyyxs;
/**
* 鱼道出口运行设计水位单位m
*/
private BigDecimal ydckz;
/**
* 鱼道出口数量单位
*/
private Integer ydckcnt;
/**
* 鱼道或仿自然通道-出口高程单位m
*/
private BigDecimal ckhg;
/**
* 鱼道池室设计流速单位m/s
*/
private BigDecimal ydcsv;
/**
* 鱼道每级池室长单位m
*/
private Integer ydcscd;
/**
* 鱼道每级池室宽单位m
*/
private Integer ydcskd;
/**
* 鱼道池室坡度
*/
private String ydcspd;
/**
* 鱼道池室数量单位
*/
private Integer ydcscnt;
/**
* 鱼道休息池个数
*/
private Integer ydxxccnt;
/**
* 鱼道或仿自然通道-流速单位m/s
*/
private BigDecimal v;
/**
* 仿自然通道断面形状
*/
private String fzrdmxz;
/**
* 仿自然通道长度*宽度
*/
private String fzrtdsz;
/**
* 仿自然通道运行水深单位m
*/
private BigDecimal fzryxwdp;
/**
* 仿自然通道坡降
*/
private BigDecimal fzrpj;
/**
* 集运鱼系统或升鱼机-上游码头位置
*/
private String symtlc;
/**
* 集运鱼系统或升鱼机-上游码头型式
*/
private String symtxs;
/**
* 集运鱼系统或升鱼机-下游码头位置
*/
private String xymtlc;
/**
* 集运鱼系统或升鱼机-下游码头型式
*/
private String xymtxs;
/**
* 集运鱼系统或升鱼机-集诱鱼方式
*/
private String jyfs;
/**
* 集运鱼系统或升鱼机-运鱼设施方式
*/
private String yyfs;
/**
* 升鱼机集鱼槽数量单位
*/
private Integer syjcnt;
/**
* 升鱼机集鱼槽进口高程单位m
*/
private BigDecimal syjhg;
/**
* 升鱼机集鱼槽流量单位m3/s
*/
private BigDecimal syjq;
/**
* 升鱼机断面尺寸**单位m
*/
private String syjsz;
/**
* 升鱼机集鱼槽水深单位m
*/
private BigDecimal syjwdp;
/**
* 设计过鱼规模单位
*/
private Long sjgycnt;
/**
* 主要过鱼对象{[code:鱼编码1,name:鱼名称1数量],[code:鱼编码2,name:鱼名称2]...}
*/
private String zygydx;
/**
* 主要过鱼对象描述
*/
private String zygydxms;
/**
* 兼顾过鱼对象{[code:鱼编码1,name:鱼名称1数量],[code:鱼编码2,name:鱼名称2]...}
*/
private String jggydx;
/**
* 兼顾过鱼对象描述
*/
private String jggydxms;
/**
* 过鱼时间
*/
private String gytm;
/**
* 运行时间
*/
private String yxtm;
/**
* 主要过鱼月份多个月份用,隔开
*/
private String fpssmn;
/**
* 数据监测频次单位min
*/
private Integer dtfrqcy;
/**
* 基本特性参数文字描述
*/
private String jbtxcs;
/**
* 设施是否实现鱼类上行 0= 1=
*/
private Integer isUp;
/**
* 设施是否实现鱼类下行 0= 1=
*/
private Integer isDown;
/**
* 备注
*/
private String remark;
/**
* 数据来源
*/
private String vlsr;
/**
* 数据来源时间
*/
private Date vlsrTm;
}

View File

@ -0,0 +1,9 @@
package com.yfd.platform.env.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.env.domain.SdFishDictoryB;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SdFishDictoryBMapper extends BaseMapper<SdFishDictoryB> {
}

View File

@ -0,0 +1,26 @@
package com.yfd.platform.env.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.env.domain.SdFpssBH;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface SdFpssBHMapper extends BaseMapper<SdFpssBH> {
@Select("<script>" +
"SELECT F.* FROM SD_FPSS_B_H F " +
"LEFT JOIN SD_ENGINFO_B_H E ON F.RSTCD = E.STCD " +
"WHERE 1=1 " +
"<if test='baseId != null and baseId != \"\"'> AND E.BASE_ID = #{baseId} </if>" +
"<if test='rstcd != null and rstcd != \"\"'> AND F.RSTCD = #{rstcd} </if>" +
"<if test='stnm != null and stnm != \"\"'> AND F.STNM LIKE '%' || #{stnm} || '%' </if>" +
"ORDER BY F.ORDER_INDEX DESC" +
"</script>")
List<SdFpssBH> selectForDropdownWithBaseId(@Param("rstcd") String rstcd,
@Param("stnm") String stnm,
@Param("baseId") String baseId);
}

View File

@ -33,6 +33,11 @@ public interface ISdEngInfoBHService extends IService<SdEngInfoBH> {
*/
List<SdEngInfoBH> getByRvcd(String rvcd);
/**
* 电站下拉列表根据基地编码筛选 + 支持名称模糊搜索
*/
List<SdEngInfoBH> selectForDropdown(String baseId, String ennm);
/**
* 新增电站
*/

View File

@ -0,0 +1,18 @@
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.SdFishDictoryB;
public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
Page<SdFishDictoryB> selectPage(String name, String code, Integer type, Integer rare, Page<SdFishDictoryB> page);
boolean add(SdFishDictoryB fishDictoryB);
boolean updateById(SdFishDictoryB fishDictoryB);
boolean deleteById(String id);
SdFishDictoryB getById(String id);
}

View File

@ -0,0 +1,27 @@
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.SdFpssBH;
import java.util.List;
public interface ISdFpssBHService extends IService<SdFpssBH> {
Page<SdFpssBH> selectPage(String stcd, String sttp, String rstcd, Integer usfl, Page<SdFpssBH> page);
List<SdFpssBH> getByRstcd(String rstcd);
/**
* 设施下拉列表根据电站编码筛选 + 支持名称模糊搜索 + 支持基地编码筛选
*/
List<SdFpssBH> selectForDropdown(String rstcd, String stnm, String baseId);
boolean add(SdFpssBH sdFpssBH);
boolean updateById(SdFpssBH sdFpssBH);
boolean deleteById(String stcd, String sttp);
SdFpssBH getDetail(String stcd, String sttp);
}

View File

@ -28,6 +28,11 @@ public interface ISdHydrobaseService extends IService<SdHydrobase> {
*/
List<SdHydrobase> getRootList();
/**
* 基地下拉列表支持名称模糊搜索
*/
List<SdHydrobase> selectForDropdown(String basename);
/**
* 新增基地
*/

View File

@ -7,6 +7,7 @@ import com.yfd.platform.env.mapper.SdEngInfoBHMapper;
import com.yfd.platform.env.service.ISdEngInfoBHService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@ -48,6 +49,16 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
return engInfoBHMapper.selectByRvcd(rvcd);
}
@Override
public List<SdEngInfoBH> selectForDropdown(String baseId, String ennm) {
return this.lambdaQuery()
.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId)
.like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getOrderIndex)
.list();
}
@Override
public boolean addEngInfo(SdEngInfoBH engInfo) {
return this.save(engInfo);

View File

@ -0,0 +1,65 @@
package com.yfd.platform.env.service.impl;
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.yfd.platform.env.domain.SdFishDictoryB;
import com.yfd.platform.env.mapper.SdFishDictoryBMapper;
import com.yfd.platform.env.service.ISdFishDictoryBService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper, SdFishDictoryB> implements ISdFishDictoryBService {
@Override
public Page<SdFishDictoryB> selectPage(String name, String code, Integer type, Integer rare, Page<SdFishDictoryB> page) {
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFishDictoryB::getIsDeleted, 0);
if (StringUtils.hasText(name)) {
wrapper.like(SdFishDictoryB::getName, name);
}
if (StringUtils.hasText(code)) {
wrapper.eq(SdFishDictoryB::getCode, code);
}
if (type != null) {
wrapper.eq(SdFishDictoryB::getType, type);
}
if (rare != null) {
wrapper.eq(SdFishDictoryB::getRare, rare);
}
wrapper.orderByDesc(SdFishDictoryB::getOrderIndex);
return page(page, wrapper);
}
@Override
public boolean add(SdFishDictoryB fishDictoryB) {
fishDictoryB.setIsDeleted(0);
return save(fishDictoryB);
}
@Override
public boolean updateById(SdFishDictoryB fishDictoryB) {
return updateById(fishDictoryB);
}
@Override
public boolean deleteById(String id) {
SdFishDictoryB entity = getById(id);
if (entity != null) {
entity.setIsDeleted(1);
return updateById(entity);
}
return false;
}
@Override
public SdFishDictoryB getById(String id) {
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFishDictoryB::getId, id)
.eq(SdFishDictoryB::getIsDeleted, 0);
return getOne(wrapper);
}
}

View File

@ -0,0 +1,86 @@
package com.yfd.platform.env.service.impl;
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.yfd.platform.env.domain.SdFpssBH;
import com.yfd.platform.env.mapper.SdFpssBHMapper;
import com.yfd.platform.env.service.ISdFpssBHService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class SdFpssBHServiceImpl extends ServiceImpl<SdFpssBHMapper, SdFpssBH> implements ISdFpssBHService {
@Override
public Page<SdFpssBH> selectPage(String stcd, String sttp, String rstcd, Integer usfl, Page<SdFpssBH> page) {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.hasText(stcd)) {
wrapper.like(SdFpssBH::getStcd, stcd);
}
if (StringUtils.hasText(sttp)) {
wrapper.eq(SdFpssBH::getSttp, sttp);
}
if (StringUtils.hasText(rstcd)) {
wrapper.eq(SdFpssBH::getRstcd, rstcd);
}
if (usfl != null) {
wrapper.eq(SdFpssBH::getUsfl, usfl);
}
wrapper.orderByDesc(SdFpssBH::getOrderIndex);
return page(page, wrapper);
}
@Override
public List<SdFpssBH> getByRstcd(String rstcd) {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFpssBH::getRstcd, rstcd);
return list(wrapper);
}
@Override
public List<SdFpssBH> selectForDropdown(String rstcd, String stnm, String baseId) {
if (StringUtils.hasText(baseId)) {
return baseMapper.selectForDropdownWithBaseId(rstcd, stnm, baseId);
} else {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.hasText(rstcd), SdFpssBH::getRstcd, rstcd)
.like(StringUtils.hasText(stnm), SdFpssBH::getStnm, stnm)
.orderByDesc(SdFpssBH::getOrderIndex);
return list(wrapper);
}
}
@Override
public boolean add(SdFpssBH sdFpssBH) {
return save(sdFpssBH);
}
@Override
public boolean updateById(SdFpssBH sdFpssBH) {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFpssBH::getStcd, sdFpssBH.getStcd())
.eq(SdFpssBH::getSttp, sdFpssBH.getSttp());
return update(sdFpssBH, wrapper);
}
@Override
public boolean deleteById(String stcd, String sttp) {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFpssBH::getStcd, stcd)
.eq(SdFpssBH::getSttp, sttp);
return remove(wrapper);
}
@Override
public SdFpssBH getDetail(String stcd, String sttp) {
LambdaQueryWrapper<SdFpssBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFpssBH::getStcd, stcd)
.eq(SdFpssBH::getSttp, sttp);
return getOne(wrapper);
}
}

View File

@ -6,6 +6,7 @@ import com.yfd.platform.env.domain.SdHydrobase;
import com.yfd.platform.env.mapper.SdHydrobaseMapper;
import com.yfd.platform.env.service.ISdHydrobaseService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@ -42,6 +43,14 @@ public class SdHydrobaseServiceImpl extends ServiceImpl<SdHydrobaseMapper, SdHyd
.list();
}
@Override
public List<SdHydrobase> selectForDropdown(String basename) {
return this.lambdaQuery()
.like(StringUtils.hasText(basename), SdHydrobase::getBasename, basename)
.orderByAsc(SdHydrobase::getOrderIndex)
.list();
}
@Override
public boolean addHydrobase(SdHydrobase hydrobase) {
return this.save(hydrobase);

View File

@ -4,8 +4,10 @@ import cn.hutool.core.util.StrUtil;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysDictionary;
import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.system.service.ISysDictionaryService;
import com.yfd.platform.system.service.ISysDictionaryItemsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.util.StringUtils;
@ -31,6 +33,9 @@ public class SysDictionaryController {
@Resource
private ISysDictionaryService sysDictionaryService;
@Resource
private ISysDictionaryItemsService sysDictionaryItemsService;
/**********************************
* 用途说明: 获取数据字典列表
* 参数说明 dictType 字典类型
@ -139,4 +144,18 @@ public class SysDictionaryController {
}
@GetMapping("/getDictItemsByCode")
@Operation(summary = "根据字典编号查询字典项列表")
public ResponseResult getDictItemsByCode(@RequestParam String dictCode) {
if (StrUtil.isBlank(dictCode)) {
return ResponseResult.error("字典编号不能为空");
}
SysDictionary sysDictionary = sysDictionaryService.getByDictCode(dictCode);
if (sysDictionary == null) {
return ResponseResult.error("未找到对应的字典");
}
List<SysDictionaryItems> items = sysDictionaryItemsService.listByDictId(sysDictionary.getId());
return ResponseResult.successData(items);
}
}

View File

@ -44,4 +44,11 @@ public interface ISysDictionaryItemsService extends IService<SysDictionaryItems>
* 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败
***********************************/
void exportExcel(List<SysDictionaryItems> records, HttpServletResponse response);
/**********************************
* 用途说明: 根据字典ID查询字典项列表
* 参数说明 dictId 字典ID
* 返回值说明: List<SysDictionaryItems> 字典项列表
***********************************/
List<SysDictionaryItems> listByDictId(String dictId);
}

View File

@ -42,4 +42,11 @@ public interface ISysDictionaryService extends IService<SysDictionary> {
* 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败
***********************************/
boolean changeDictOrder(String fromID, String toID);
/**********************************
* 用途说明: 根据字典编号查询字典
* 参数说明 dictCode 字典编号
* 返回值说明: SysDictionary 字典对象
***********************************/
SysDictionary getByDictCode(String dictCode);
}

View File

@ -120,4 +120,11 @@ public class SysDictionaryItemsServiceImpl extends ServiceImpl<SysDictionaryItem
}
}
@Override
public List<SysDictionaryItems> listByDictId(String dictId) {
LambdaQueryWrapper<SysDictionaryItems> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysDictionaryItems::getDictId, dictId).orderByAsc(SysDictionaryItems::getOrderNo);
return sysDictionaryItemsMapper.selectList(queryWrapper);
}
}

View File

@ -111,4 +111,11 @@ public class SysDictionaryServiceImpl extends ServiceImpl<SysDictionaryMapper
return fromBool && toBool;
}
@Override
public SysDictionary getByDictCode(String dictCode) {
LambdaQueryWrapper<SysDictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysDictionary::getDictCode, dictCode);
return sysDictionaryMapper.selectOne(queryWrapper);
}
}

View File

@ -0,0 +1,302 @@
package com.yfd.platform.utils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class DataSourceRequestUtil {
private static final Pattern SAFE_IDENTIFIER = Pattern.compile("^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*$");
public static <T> Page<T> getPage(DataSourceRequest request) {
if (request == null) {
return null;
}
int take = request.getTake();
int skip = request.getSkip();
if (take <= 0) {
return null;
}
Page<T> page = new Page<>();
page.setSize((long) take);
page.setCurrent(skip / take + 1L);
return page;
}
public static <T> QueryWrapper<T> buildWrapper(DataSourceRequest request, Class<T> entityClass) {
return buildWrapper(request, entityClass, null, null);
}
public static <T> QueryWrapper<T> buildWrapper(DataSourceRequest request, Class<T> entityClass,
Map<String, String> fieldMapping,
List<String> excludeFields) {
QueryWrapper<T> wrapper = new QueryWrapper<>();
if (request == null || entityClass == null) {
return wrapper;
}
List<String> excludes = excludeFields != null ? excludeFields : new ArrayList<>();
applyFilters(request.getFilter(), wrapper, entityClass, fieldMapping, excludes, "and");
applySort(request.getSort(), wrapper, entityClass);
return wrapper;
}
public static <T> QueryWrapper<T> buildQueryWrapper(DataSourceRequest request, Class<T> entityClass) {
return buildQueryWrapper(request, entityClass, null, null);
}
public static <T> QueryWrapper<T> buildQueryWrapper(DataSourceRequest request, Class<T> entityClass,
Map<String, String> fieldMapping,
List<String> excludeFields) {
QueryWrapper<T> wrapper = new QueryWrapper<>();
if (request == null || entityClass == null) {
return wrapper;
}
List<String> excludes = excludeFields != null ? excludeFields : new ArrayList<>();
applyFilters(request.getFilter(), wrapper, entityClass, fieldMapping, excludes, "and");
applySort(request.getSort(), wrapper, entityClass);
return wrapper;
}
public static <T> Page<T> executeQuery(DataSourceRequest request, Class<T> entityClass,
com.baomidou.mybatisplus.extension.service.IService<T> service) {
return executeQuery(request, entityClass, service, null, null);
}
public static <T> Page<T> executeQuery(DataSourceRequest request, Class<T> entityClass,
com.baomidou.mybatisplus.extension.service.IService<T> service,
Map<String, String> fieldMapping,
List<String> excludeFields) {
if (request == null || service == null) {
return new Page<>();
}
QueryWrapper<T> wrapper = buildQueryWrapper(request, entityClass, fieldMapping, excludeFields);
Page<T> page = getPage(request);
if (page != null) {
return service.page(page, wrapper);
} else {
List<T> list = service.list(wrapper);
Page<T> resultPage = new Page<>();
resultPage.setRecords(list);
resultPage.setTotal(list.size());
resultPage.setSize((long) list.size());
resultPage.setCurrent(1L);
return resultPage;
}
}
public static <T> List<T> executeList(DataSourceRequest request, Class<T> entityClass,
com.baomidou.mybatisplus.extension.service.IService<T> service) {
return executeList(request, entityClass, service, null, null);
}
public static <T> List<T> executeList(DataSourceRequest request, Class<T> entityClass,
com.baomidou.mybatisplus.extension.service.IService<T> service,
Map<String, String> fieldMapping,
List<String> excludeFields) {
if (request == null || service == null) {
return new ArrayList<>();
}
QueryWrapper<T> wrapper = buildQueryWrapper(request, entityClass, fieldMapping, excludeFields);
return service.list(wrapper);
}
private static <T> void applyFilters(DataSourceRequest.FilterDescriptor filter,
QueryWrapper<T> wrapper,
Class<T> entityClass,
Map<String, String> fieldMapping,
List<String> excludeFields,
String parentLogic) {
if (filter == null) {
return;
}
List<DataSourceRequest.FilterDescriptor> filters = filter.getFilters();
if (CollectionUtil.isEmpty(filters)) {
String field = filter.getField();
if (StrUtil.isBlank(field)) {
return;
}
if (excludeFields.contains(field)) {
return;
}
String columnName = getColumnName(field, entityClass, fieldMapping);
Object value = filter.getValue();
String operator = filter.getOperator();
applySingleCondition(wrapper, columnName, operator, value);
return;
}
if (filters.size() == 1) {
applyFilters(filters.get(0), wrapper, entityClass, fieldMapping, excludeFields, parentLogic);
return;
}
String logic = filter.getLogic();
boolean isAnd = "and".equalsIgnoreCase(logic);
List<QueryWrapper<T>> conditionGroups = new ArrayList<>();
List<String> logics = new ArrayList<>();
for (int i = 0; i < filters.size(); i++) {
QueryWrapper<T> subWrapper = new QueryWrapper<>();
applyFilters(filters.get(i), subWrapper, entityClass, fieldMapping, excludeFields, logic);
if (hasConditions(subWrapper)) {
conditionGroups.add(subWrapper);
if (i > 0) {
logics.add(isAnd ? "and" : "or");
}
}
}
for (int i = 0; i < conditionGroups.size(); i++) {
if (i == 0) {
mergeWrapper(wrapper, conditionGroups.get(i));
} else {
String lgc = logics.get(i - 1);
if ("or".equalsIgnoreCase(lgc)) {
wrapper.or();
}
mergeWrapper(wrapper, conditionGroups.get(i));
}
}
}
private static <T> boolean hasConditions(QueryWrapper<T> wrapper) {
return wrapper instanceof QueryWrapper && !wrapper.getExpression().getNormal().isEmpty();
}
private static <T> void mergeWrapper(QueryWrapper<T> target, QueryWrapper<T> source) {
target.getExpression().getNormal().addAll(source.getExpression().getNormal());
}
private static <T> void applySingleCondition(QueryWrapper<T> wrapper, String columnName,
String operator, Object value) {
if (columnName == null) {
return;
}
String op = operator != null ? operator.trim().toLowerCase() : "eq";
switch (op) {
case "eq" -> wrapper.eq(columnName, value);
case "neq", "<>" -> wrapper.ne(columnName, value);
case "gt" -> wrapper.gt(columnName, value);
case "gte", ">=" -> wrapper.ge(columnName, value);
case "lt" -> wrapper.lt(columnName, value);
case "lte", "<=" -> wrapper.le(columnName, value);
case "contains" -> wrapper.like(columnName, value);
case "notcontains" -> wrapper.notLike(columnName, value);
case "startswith" -> wrapper.likeRight(columnName, value);
case "endswith" -> wrapper.likeLeft(columnName, value);
case "isnull" -> wrapper.isNull(columnName);
case "isnotnull" -> wrapper.isNotNull(columnName);
case "isempty" -> wrapper.eq(columnName, "");
case "isnotempty" -> wrapper.ne(columnName, "");
case "in" -> {
if (value instanceof Iterable) {
wrapper.in(columnName, (Iterable<?>) value);
} else if (value instanceof Object[]) {
wrapper.in(columnName, (Object[]) value);
}
}
case "ni", "notin" -> {
if (value instanceof Iterable) {
wrapper.notIn(columnName, (Iterable<?>) value);
} else if (value instanceof Object[]) {
wrapper.notIn(columnName, (Object[]) value);
}
}
default -> wrapper.eq(columnName, value);
}
}
private static <T> void applySort(List<DataSourceRequest.SortDescriptor> sorts,
QueryWrapper<T> wrapper,
Class<T> entityClass) {
if (CollectionUtil.isEmpty(sorts)) {
return;
}
for (DataSourceRequest.SortDescriptor sort : sorts) {
if (sort == null || StrUtil.isBlank(sort.getField())) {
continue;
}
String columnName = getColumnName(sort.getField(), entityClass, null);
if (columnName == null) {
continue;
}
String dir = sort.getDir();
if ("desc".equalsIgnoreCase(dir)) {
wrapper.orderByDesc(columnName);
} else {
wrapper.orderByAsc(columnName);
}
}
}
private static <T> String getColumnName(String property, Class<T> entityClass,
Map<String, String> fieldMapping) {
if (property == null || property.isBlank()) {
return null;
}
if (fieldMapping != null && fieldMapping.containsKey(property)) {
return fieldMapping.get(property);
}
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
if (tableInfo == null) {
return requireSafeIdentifier(property);
}
if (property.equals(tableInfo.getKeyProperty())) {
return tableInfo.getKeyColumn();
}
List<TableFieldInfo> fieldInfos = tableInfo.getFieldList().stream()
.filter(f -> property.equals(f.getProperty()))
.toList();
if (!fieldInfos.isEmpty()) {
return fieldInfos.get(0).getColumn();
}
return requireSafeIdentifier(property);
}
private static String requireSafeIdentifier(String identifier) {
String id = identifier == null ? "" : identifier.trim();
if (id.isEmpty() || !SAFE_IDENTIFIER.matcher(id).matches()) {
return id;
}
return id;
}
}

View File

@ -71,6 +71,16 @@ public class SecurityUtils {
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
}
/**
* 获取系统用户ID
* @return 系统用户ID
*/
public static String getUserId() {
UserDetails userDetails = getCurrentUser();
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", String.class);
}
/**
* 获取当前用户的数据权限
* @return /

View File

@ -58,8 +58,8 @@ mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
# log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 登录相关配置

View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yfd.platform.data.mapper.FishDraftDataMapper">
<resultMap id="BaseResultMap" type="com.yfd.platform.data.domain.FishDraftData">
<id column="ID" property="id"/>
<result column="STCD" property="stcd"/>
<result column="TM" property="tm"/>
<result column="FTP" property="ftp"/>
<result column="FSZ" property="fsz"/>
<result column="FCNT" property="fcnt"/>
<result column="FWET" property="fwet"/>
<result column="STRDT" property="strdt"/>
<result column="ENDDT" property="enddt"/>
<result column="DIRECTION" property="direction"/>
<result column="YR" property="yr"/>
<result column="MOUTH" property="mouth"/>
<result column="VDPTH" property="vdpth"/>
<result column="PICPTH" property="picpth"/>
<result column="ISFS" property="isfs"/>
<result column="SOURCE_TYPE" property="sourceType"/>
<result column="APPROVAL_ID" property="approvalId"/>
<result column="STATUS" property="status"/>
<result column="LOCK_FLAG" property="lockFlag"/>
<result column="SUBMIT_TIME" property="submitTime"/>
<result column="APPROVE_TIME" property="approveTime"/>
<result column="DELETED_FLAG" property="deletedFlag"/>
<result column="DELETED_BY" property="deletedBy"/>
<result column="DELETED_AT" property="deletedAt"/>
<result column="CREATED_AT" property="createdAt"/>
<result column="CREATED_BY" property="createdBy"/>
<result column="UPDATED_AT" property="updatedAt"/>
<result column="UPDATED_BY" property="updatedBy"/>
</resultMap>
<resultMap id="JoinResultMap" type="com.yfd.platform.data.domain.vo.FishDraftDataVO">
<id column="ID" property="id"/>
<result column="STCD" property="stcd"/>
<result column="TM" property="tm"/>
<result column="FTP" property="ftp"/>
<result column="FTP" property="ftp"/>
<result column="FTPNAME" property="ftpName"/>
<result column="FSZ" property="fsz"/>
<result column="FCNT" property="fcnt"/>
<result column="FWET" property="fwet"/>
<result column="STRDT" property="strdt"/>
<result column="ENDDT" property="enddt"/>
<result column="DIRECTION" property="direction"/>
<result column="YR" property="yr"/>
<result column="WT" property="wt"/>
<result column="MOUTH" property="mouth"/>
<result column="VDPTH" property="vdpth"/>
<result column="PICPTH" property="picpth"/>
<result column="ISFS" property="isfs"/>
<result column="SOURCE_TYPE" property="sourceType"/>
<result column="APPROVAL_ID" property="approvalId"/>
<result column="STATUS" property="status"/>
<result column="LOCK_FLAG" property="lockFlag"/>
<result column="SUBMIT_TIME" property="submitTime"/>
<result column="APPROVE_TIME" property="approveTime"/>
<result column="DELETED_FLAG" property="deletedFlag"/>
<result column="DELETED_BY" property="deletedBy"/>
<result column="DELETED_AT" property="deletedAt"/>
<result column="CREATED_AT" property="createdAt"/>
<result column="CREATED_BY" property="createdBy"/>
<result column="UPDATED_AT" property="updatedAt"/>
<result column="UPDATED_BY" property="updatedBy"/>
<result column="STNM" property="stnm"/>
<result column="STTP" property="sttp"/>
<result column="RSTCD" property="rstcd"/>
<result column="ENNM" property="ennm"/>
<result column="BASE_ID" property="baseId"/>
<result column="BASENAME" property="baseName"/>
<result column="RVCD" property="rvcd"/>
<result column="LGTD" property="lgtd"/>
<result column="LTTD" property="lttd"/>
<result column="ORDER_INDEX" property="orderIndex"/>
</resultMap>
<sql id="joinColumns">
D.ID,
D.STCD,
D.TM,
D.FTP,
FB.NAME FTPNAME,
D.FSZ,
D.FCNT,
D.FWET,
D.STRDT,
D.ENDDT,
D.DIRECTION,
D.YR,
D.WT,
D.MOUTH,
D.VDPTH,
D.PICPTH,
D.ISFS,
D.SOURCE_TYPE,
D.APPROVAL_ID,
D.STATUS,
D.LOCK_FLAG,
D.SUBMIT_TIME,
D.APPROVE_TIME,
D.DELETED_FLAG,
D.DELETED_BY,
D.DELETED_AT,
D.CREATED_AT,
D.CREATED_BY,
D.UPDATED_AT,
D.UPDATED_BY,
F.STNM,
F.STTP,
F.RSTCD,
E.ENNM,
E.BASE_ID,
H.BASENAME,
E.RVCD,
E.LGTD,
E.LTTD,
E.ORDER_INDEX
</sql>
<select id="selectJoinPage" resultMap="JoinResultMap">
SELECT
<include refid="joinColumns"/>
FROM FISH_DRAFT_DATA D
LEFT JOIN SD_FPSS_B_H F ON D.STCD = F.STCD
LEFT JOIN SD_FISHDICTORY_B FB ON FB.ID = D.FTP
LEFT JOIN SD_ENGINFO_B_H E ON F.RSTCD = E.STCD
LEFT JOIN SD_HYDROBASE H ON E.BASE_ID = H.BASEID
WHERE D.DELETED_FLAG = 0
<if test="stcd != null and stcd != ''">
AND D.STCD = #{stcd}
</if>
<if test="ftp != null and ftp != ''">
AND D.FTP = #{ftp}
</if>
<if test="rstcd != null and rstcd != ''">
AND F.RSTCD = #{rstcd}
</if>
<if test="baseId != null and baseId != ''">
AND E.BASE_ID = #{baseId}
</if>
<if test="direction != null and direction != ''">
AND D.DIRECTION = #{direction}
</if>
<if test="status != null and status != ''">
AND D.STATUS = #{status}
</if>
<if test="startTime != null and startTime != ''">
AND D.TM &gt;= TO_DATE(#{startTime}, 'yyyy-mm-dd hh24:mi:ss')
</if>
<if test="endTime != null and endTime != ''">
AND D.TM &lt;= TO_DATE(#{endTime}, 'yyyy-mm-dd hh24:mi:ss')
</if>
ORDER BY D.CREATED_AT DESC
</select>
<select id="selectJoinList" resultMap="JoinResultMap">
SELECT
<include refid="joinColumns"/>
FROM FISH_DRAFT_DATA D
LEFT JOIN SD_FPSS_B_H F ON D.STCD = F.STCD
LEFT JOIN SD_ENGINFO_B_H E ON F.RSTCD = E.STCD
WHERE D.DELETED_FLAG = 0
<if test="stcd != null and stcd != ''">
AND D.STCD = #{stcd}
</if>
<if test="ftp != null and ftp != ''">
AND D.FTP = #{ftp}
</if>
<if test="rstcd != null and rstcd != ''">
AND F.RSTCD = #{rstcd}
</if>
<if test="baseId != null and baseId != ''">
AND E.BASE_ID = #{baseId}
</if>
<if test="direction != null and direction != ''">
AND D.DIRECTION = #{direction}
</if>
<if test="status != null and status != ''">
AND D.STATUS = #{status}
</if>
<if test="startTime != null and startTime != ''">
AND D.TM &gt;= TO_DATE(#{startTime}, 'yyyy-mm-dd hh24:mi:ss')
</if>
<if test="endTime != null and endTime != ''">
AND D.TM &lt;= TO_DATE(#{endTime}, 'yyyy-mm-dd hh24:mi:ss')
</if>
ORDER BY D.CREATED_AT DESC
</select>
<select id="selectJoinCount" resultType="long">
SELECT COUNT(*)
FROM FISH_DRAFT_DATA D
LEFT JOIN SD_FPSS_B_H F ON D.STCD = F.STCD
LEFT JOIN SD_ENGINFO_B_H E ON F.RSTCD = E.STCD
WHERE D.DELETED_FLAG = 0
<if test="stcd != null and stcd != ''">
AND D.STCD = #{stcd}
</if>
<if test="rstcd != null and rstcd != ''">
AND F.RSTCD = #{rstcd}
</if>
<if test="baseId != null and baseId != ''">
AND E.BASE_ID = #{baseId}
</if>
<if test="direction != null and direction != ''">
AND D.DIRECTION = #{direction}
</if>
<if test="status != null and status != ''">
AND D.STATUS = #{status}
</if>
</select>
</mapper>

View File

@ -159,7 +159,7 @@
>
<span>登录</span>
</a-button>
<a-button
<!-- <a-button
type="link"
size="mini"
block
@ -167,14 +167,14 @@
:style="{ marginTop: '10px', border: 'none' }"
>
忘记密码
</a-button>
</a-button> -->
<!-- 忘记密码 -->
</a-form>
</a-tab-pane>
<!-- 短信登录 Tab (占位) -->
<a-tab-pane key="sms" tab="短信登录">
<!-- <a-tab-pane key="sms" tab="短信登录">
<a-form
:model="loginData"
:rules="loginRules"
@ -231,7 +231,7 @@
<span>登录</span>
</a-button>
</a-form>
</a-tab-pane>
</a-tab-pane> -->
</a-tabs>
</div>
</div>

View File

@ -923,7 +923,7 @@ function handleClearSelection() {
:header-cell-style="{ background: 'rgb(250 250 250)', color: ' #383838', height: '50px' }">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="nickname" label="用户姓名" width="100"></el-table-column>
<el-table-column prop="nickname" label="用户姓名" width="140"></el-table-column>
<!-- <el-table-column prop="avatar" label="头像"></el-table-column> -->
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="phone" label="手机号" min-width="90"></el-table-column>
@ -948,7 +948,7 @@ function handleClearSelection() {
{{ dateFormat(scope.row.lastmodifydate) }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="110">
<el-table-column fixed="right" label="操作" width="130">
<template #default="scope">
<span
style="display: flex;display: -webkit-flex;justify-content: space-around;-webkit-justify-content: space-around; ">