1、完善项目

2、完善合同
3、完善费用项
4、司机管理对接OCR
5、完善运输计划
6、完善临时额度
This commit is contained in:
2026-08-04 02:49:59 +08:00
387 changed files with 22482 additions and 110 deletions

View File

@@ -81,8 +81,8 @@ public class ContractManageController extends BladeController {
@PostMapping("/save-draft")
@ApiOperationSupport(order = 3)
@Operation(summary = "保存草稿", description = "传入contractManage")
public R saveDraft(@RequestBody ContractManage contractManage) {
return R.status(contractManageService.saveDraft(contractManage));
public R<ContractManage> saveDraft(@RequestBody ContractManage contractManage) {
return contractManageService.saveDraft(contractManage) ? R.data(contractManage) : R.fail("保存失败");
}
@PostMapping("/submit")

View File

@@ -126,8 +126,22 @@ public class ProjectApplyController extends BladeController {
return R.status(projectApplyService.voidProject(id, reason));
}
@PostMapping("/start-change")
@PostMapping("/save-change")
@ApiOperationSupport(order = 10)
@Operation(summary = "保存变更", description = "传入projectApply")
public R saveChange(@RequestBody ProjectApplyVO projectApply) {
return R.status(projectApplyService.saveChange(projectApply));
}
@PostMapping("/submit-change")
@ApiOperationSupport(order = 11)
@Operation(summary = "提交变更", description = "传入projectApply")
public R submitChange(@RequestBody ProjectApplyVO projectApply) {
return R.status(projectApplyService.submitChange(projectApply));
}
@PostMapping("/start-change")
@ApiOperationSupport(order = 12)
@Operation(summary = "发起变更", description = "传入id、changeContent和changeReason")
public R startChange(@Parameter(description = "主键", required = true) @RequestParam Long id,
@RequestParam String changeContent,
@@ -136,14 +150,14 @@ public class ProjectApplyController extends BladeController {
}
@PostMapping("/remove")
@ApiOperationSupport(order = 11)
@ApiOperationSupport(order = 13)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status(projectApplyService.removeDraft(ids));
}
@GetMapping("/export-project-apply")
@ApiOperationSupport(order = 12)
@ApiOperationSupport(order = 14)
@Operation(summary = "导出项目立项")
public void exportProjectApply(ProjectApplyVO projectApply, @RequestParam(required = false) String ids, HttpServletResponse response) {
List<ProjectApplyExcel> list = projectApplyService.exportProjectApply(projectApply, ids);

View File

@@ -46,6 +46,8 @@ public interface IProjectApplyService extends BaseService<ProjectApply> {
boolean reject(Long id);
boolean withdraw(Long id);
boolean voidProject(Long id, String reason);
boolean saveChange(ProjectApplyVO projectApply);
boolean submitChange(ProjectApplyVO projectApply);
boolean startChange(Long id, String changeContent, String changeReason);
boolean removeDraft(String ids);
List<ProjectApplyExcel> exportProjectApply(ProjectApplyVO projectApply, String ids);

View File

@@ -28,6 +28,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.UserCache;
@@ -43,6 +44,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -65,6 +68,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private static final String STATUS_REJECTED = "rejected";
private static final String STATUS_APPROVED = "approved";
private static final String STATUS_CHANGE_REVIEWING = "change_reviewing";
private static final String STATUS_CHANGE_APPROVED = "change_approved";
private static final String STATUS_CHANGE_REJECTED = "change_rejected";
@Override
public IPage<ContractManageVO> selectContractManagePage(IPage<ContractManage> page, ContractManageVO contractManage) {
@@ -111,6 +116,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
prepareCreateOrUpdate(contractManage);
contractManage.setContractStage(STAGE_TEMPORARY);
contractManage.setApprovalStatus(STATUS_REVIEWING);
appendCreateChangeRecordIfAbsent(contractManage);
return saveOrUpdate(contractManage);
}
@@ -147,13 +153,15 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class)
public boolean approve(Long id) {
ContractManage contractManage = loadReviewing(id);
contractManage.setApprovalStatus(STATUS_APPROVED);
boolean changeReviewing = Objects.equals(contractManage.getApprovalStatus(), STATUS_CHANGE_REVIEWING);
contractManage.setApprovalStatus(changeReviewing ? STATUS_CHANGE_APPROVED : STATUS_APPROVED);
contractManage.setCurrentNode("审批通过");
contractManage.setCurrentProcessor(AuthUtil.getUserName());
contractManage.setApprovedTime(LocalDateTime.now());
if (Objects.equals(contractManage.getContractStage(), STAGE_TEMPORARY) && contractManage.getTemporaryStartDate() == null) {
contractManage.setTemporaryStartDate(LocalDate.now());
}
updateLatestReviewingChangeRecord(contractManage, contractManage.getApprovalStatus(), "审核通过");
return updateById(contractManage);
}
@@ -161,9 +169,11 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class)
public boolean reject(Long id) {
ContractManage contractManage = loadReviewing(id);
contractManage.setApprovalStatus(STATUS_REJECTED);
boolean changeReviewing = Objects.equals(contractManage.getApprovalStatus(), STATUS_CHANGE_REVIEWING);
contractManage.setApprovalStatus(changeReviewing ? STATUS_CHANGE_REJECTED : STATUS_REJECTED);
contractManage.setCurrentNode("已驳回");
contractManage.setCurrentProcessor(AuthUtil.getUserName());
updateLatestReviewingChangeRecord(contractManage, contractManage.getApprovalStatus(), "审核不通过");
return updateById(contractManage);
}
@@ -171,9 +181,11 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Transactional(rollbackFor = Exception.class)
public boolean withdraw(Long id) {
ContractManage contractManage = loadReviewing(id);
contractManage.setApprovalStatus(STATUS_DRAFT);
boolean changeReviewing = Objects.equals(contractManage.getApprovalStatus(), STATUS_CHANGE_REVIEWING);
contractManage.setApprovalStatus(changeReviewing ? STATUS_APPROVED : STATUS_DRAFT);
contractManage.setCurrentNode("已撤回");
contractManage.setCurrentProcessor(AuthUtil.getUserName());
updateLatestReviewingChangeRecord(contractManage, "withdrawn", "已撤回");
return updateById(contractManage);
}
@@ -189,6 +201,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setChangeReason(TransportBusinessSupport.trimToNull(changeReason));
contractManage.setCurrentNode("合同变更审批");
contractManage.setCurrentProcessor("待处理");
appendChangeRecord(contractManage, "合同信息变更", contractManage.getChangeReason(), STATUS_CHANGE_REVIEWING, "审核中");
return updateById(contractManage);
}
@@ -203,6 +216,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setTerminateReason(TransportBusinessSupport.trimToNull(reason));
contractManage.setCurrentNode("已终止");
contractManage.setCurrentProcessor(AuthUtil.getUserName());
appendChangeRecord(contractManage, "终止", contractManage.getTerminateReason(), STATUS_APPROVED, "已终止");
return updateById(contractManage);
}
@@ -267,7 +281,11 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
TransportBusinessSupport.validateAllDept(contractManage.getAllDept(), "合同管理");
LambdaQueryWrapper<ContractManage> queryWrapper = Wrappers.<ContractManage>lambdaQuery().eq(ContractManage::getIsDeleted, 0);
if (!Objects.equals(contractManage.getAllDept(), 1)) {
queryWrapper.eq(ContractManage::getOrganizationId, TransportBusinessSupport.currentDeptId("合同管理"));
Long currentDeptId = TransportBusinessSupport.currentDeptId("合同管理");
Long currentUserId = AuthUtil.getUserId();
queryWrapper.and(wrapper -> wrapper.eq(ContractManage::getOrganizationId, currentDeptId)
.or().eq(ContractManage::getCreateUser, currentUserId)
.or().eq(ContractManage::getHandlerUserId, currentUserId));
} else if (Func.isNotEmpty(contractManage.getOrganizationId())) {
queryWrapper.eq(ContractManage::getOrganizationId, contractManage.getOrganizationId());
}
@@ -299,8 +317,10 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
} else {
ContractManage oldRecord = loadExists(contractManage.getId());
contractManage.setContractNo(oldRecord.getContractNo());
contractManage.setOrganizationId(oldRecord.getOrganizationId());
contractManage.setOrganizationName(oldRecord.getOrganizationName());
if (Func.isEmpty(contractManage.getOrganizationId())) {
contractManage.setOrganizationId(oldRecord.getOrganizationId());
contractManage.setOrganizationName(oldRecord.getOrganizationName());
}
contractManage.setHandlerUserId(oldRecord.getHandlerUserId());
contractManage.setHandlerUserName(oldRecord.getHandlerUserName());
}
@@ -325,6 +345,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
contractManage.setBillingPlanJson(TransportBusinessSupport.trimToNull(contractManage.getBillingPlanJson()));
contractManage.setSettlementRuleJson(TransportBusinessSupport.trimToNull(contractManage.getSettlementRuleJson()));
contractManage.setReconciliationJson(TransportBusinessSupport.trimToNull(contractManage.getReconciliationJson()));
contractManage.setChangeRecordJson(TransportBusinessSupport.trimToNull(contractManage.getChangeRecordJson()));
}
private void validateDraft(ContractManage contractManage) {
@@ -359,18 +380,70 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
if (!Objects.equals(contractManage.getApprovalStatus(), STATUS_DRAFT)) {
throw new ServiceException("当前状态不允许编辑");
}
TransportBusinessSupport.assertCurrentDept(contractManage.getOrganizationId(), "合同管理");
if (!canOperateInCurrentScope(contractManage)) {
throw new ServiceException("无权操作其他组织合同管理");
}
return contractManage;
}
private ContractManage loadReviewing(Long id) {
ContractManage contractManage = loadExists(id);
if (!Objects.equals(contractManage.getApprovalStatus(), STATUS_REVIEWING)) {
if (!List.of(STATUS_REVIEWING, STATUS_CHANGE_REVIEWING).contains(contractManage.getApprovalStatus())) {
throw new ServiceException("当前状态不允许操作");
}
return contractManage;
}
private void appendCreateChangeRecordIfAbsent(ContractManage contractManage) {
List<Map<String, Object>> records = parseChangeRecords(contractManage.getChangeRecordJson());
boolean exists = records.stream().anyMatch(record -> Objects.equals(record.get("changeType"), "创建"));
if (!exists) {
appendChangeRecord(contractManage, "创建", null, STATUS_REVIEWING, "审核中");
}
}
private void appendChangeRecord(ContractManage contractManage, String changeType, String changeReason, String status, String statusName) {
List<Map<String, Object>> records = parseChangeRecords(contractManage.getChangeRecordJson());
Map<String, Object> record = new LinkedHashMap<>();
record.put("changeDate", LocalDate.now().toString());
record.put("handlerUserId", AuthUtil.getUserId());
record.put("handlerUserName", AuthUtil.getUserName());
record.put("changeType", changeType);
record.put("changeReason", TransportBusinessSupport.trimToNull(changeReason));
record.put("status", status);
record.put("statusName", statusName);
records.add(record);
contractManage.setChangeRecordJson(JsonUtil.toJson(records));
}
private void updateLatestReviewingChangeRecord(ContractManage contractManage, String status, String statusName) {
List<Map<String, Object>> records = parseChangeRecords(contractManage.getChangeRecordJson());
for (int index = records.size() - 1; index >= 0; index--) {
Map<String, Object> record = records.get(index);
if (Objects.equals(record.get("status"), STATUS_REVIEWING) || Objects.equals(record.get("status"), STATUS_CHANGE_REVIEWING)) {
record.put("status", status);
record.put("statusName", statusName);
contractManage.setChangeRecordJson(JsonUtil.toJson(records));
return;
}
}
}
@SuppressWarnings("unchecked")
private List<Map<String, Object>> parseChangeRecords(String value) {
if (Func.isEmpty(value)) {
return new ArrayList<>();
}
try {
Object records = JsonUtil.parse(value, List.class);
if (records instanceof List<?> list) {
return (List<Map<String, Object>>) (List<?>) list;
}
} catch (Exception ignored) {
}
return new ArrayList<>();
}
private String expireScope(LocalDate endDate) {
long days = java.time.temporal.ChronoUnit.DAYS.between(LocalDate.now(), endDate);
if (days < 0) {
@@ -386,7 +459,15 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
private void fillReadonly(ContractManageVO contractManageVO) {
contractManageVO.setReadonly(!Objects.equals(contractManageVO.getOrganizationId(), TransportBusinessSupport.currentDeptId("合同管理")));
contractManageVO.setReadonly(!canOperateInCurrentScope(contractManageVO));
}
private boolean canOperateInCurrentScope(ContractManage contractManage) {
Long currentDeptId = TransportBusinessSupport.currentDeptId("合同管理");
Long currentUserId = AuthUtil.getUserId();
return Objects.equals(contractManage.getOrganizationId(), currentDeptId)
|| Objects.equals(contractManage.getCreateUser(), currentUserId)
|| Objects.equals(contractManage.getHandlerUserId(), currentUserId);
}
}

View File

@@ -67,6 +67,8 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
private static final String STATUS_VOIDED = "voided";
private static final String EFFECTIVE_TEMPORARY = "temporary";
private static final String EFFECTIVE_FORMAL = "formal";
private static final String CHANGE_TYPE_PROJECT = "项目变更";
private static final String CHANGE_TYPE_RECORD = "项目备案调整";
private static final DateTimeFormatter CODE_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
private static final DateTimeFormatter PROJECT_YEAR = DateTimeFormatter.ofPattern("yyyy");
@@ -179,12 +181,38 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
return updateById(projectApply);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveChange(ProjectApplyVO projectApply) {
ProjectApply oldRecord = loadChangeable(projectApply.getId());
prepare(projectApply);
copyChangeFields(oldRecord, projectApply);
validateSubmit(oldRecord);
validateChangeLength(oldRecord);
return updateById(oldRecord);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submitChange(ProjectApplyVO projectApply) {
ProjectApply oldRecord = loadChangeable(projectApply.getId());
prepare(projectApply);
copyChangeFields(oldRecord, projectApply);
validateSubmit(oldRecord);
validateChange(oldRecord, projectApply.getChangeType());
oldRecord.setApprovalStatus(STATUS_CHANGE_REVIEWING);
oldRecord.setCurrentNode(projectApply.getChangeType() + "审批");
oldRecord.setCurrentProcessor("待处理");
return updateById(oldRecord);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean startChange(Long id, String changeContent, String changeReason) {
ProjectApply projectApply = loadExists(id);
if (!Objects.equals(projectApply.getApprovalStatus(), STATUS_APPROVED) || !Objects.equals(projectApply.getEffectiveType(), EFFECTIVE_FORMAL)) {
throw new ServiceException("仅正式生效且审批通过的项目允许发起变更");
validateChangeable(projectApply);
if (!canCurrentUserOperate(projectApply)) {
throw new ServiceException("无权操作其他组织项目立项");
}
TransportBusinessSupport.validateRequired(changeContent, "请输入变更内容");
TransportBusinessSupport.validateRequired(changeReason, "请输入变更原因");
@@ -234,7 +262,12 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
TransportBusinessSupport.validateAllDept(projectApply.getAllDept(), "项目立项");
LambdaQueryWrapper<ProjectApply> queryWrapper = Wrappers.<ProjectApply>lambdaQuery().eq(ProjectApply::getIsDeleted, 0);
if (!Objects.equals(projectApply.getAllDept(), 1)) {
queryWrapper.eq(ProjectApply::getUndertakeDeptId, TransportBusinessSupport.currentDeptId("项目立项"));
Long currentDeptId = TransportBusinessSupport.currentDeptId("项目立项");
Long currentUserId = AuthUtil.getUserId();
queryWrapper.and(wrapper -> wrapper.eq(ProjectApply::getUndertakeDeptId, currentDeptId)
.or().eq(ProjectApply::getCreateUser, currentUserId)
.or().eq(ProjectApply::getHandlerUserId, currentUserId)
.or().eq(ProjectApply::getPrincipalUserId, currentUserId));
} else if (Func.isNotEmpty(projectApply.getUndertakeDeptId())) {
queryWrapper.eq(ProjectApply::getUndertakeDeptId, projectApply.getUndertakeDeptId());
}
@@ -307,6 +340,36 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
projectApply.setSituationRemark(TransportBusinessSupport.trimToNull(projectApply.getSituationRemark()));
}
private void copyChangeFields(ProjectApply target, ProjectApply source) {
target.setFundLimit(source.getFundLimit());
target.setReceivableLimit(source.getReceivableLimit());
target.setReceivableDays(source.getReceivableDays());
target.setPaymentDays(source.getPaymentDays());
target.setCargoType(source.getCargoType());
target.setCargoQuantity(source.getCargoQuantity());
target.setBusinessStartDate(source.getBusinessStartDate());
target.setBusinessEndDate(source.getBusinessEndDate());
target.setTransportRoute(source.getTransportRoute());
target.setTransportType(source.getTransportType());
target.setBusinessType(source.getBusinessType());
target.setProjectScale(source.getProjectScale());
target.setSettlementMode(source.getSettlementMode());
target.setEstimatedProfit(source.getEstimatedProfit());
target.setFundDemand(source.getFundDemand());
target.setHandlerUserId(source.getHandlerUserId());
target.setHandlerUserName(source.getHandlerUserName());
target.setPrincipalUserId(source.getPrincipalUserId());
target.setPrincipalUserName(source.getPrincipalUserName());
target.setCustomerNames(source.getCustomerNames());
target.setCarrierNames(source.getCarrierNames());
target.setCustomerJson(source.getCustomerJson());
target.setCarrierJson(source.getCarrierJson());
target.setSituationRemark(source.getSituationRemark());
target.setAttachmentsJson(source.getAttachmentsJson());
target.setChangeContent(TransportBusinessSupport.trimToNull(source.getChangeContent()));
target.setChangeReason(TransportBusinessSupport.trimToNull(source.getChangeReason()));
}
private void validateDraft(ProjectApply projectApply) {
TransportBusinessSupport.validateRequired(projectApply.getProjectType(), "请选择项目类型");
TransportBusinessSupport.validateRequired(projectApply.getProjectName(), "请输入项目名称");
@@ -355,6 +418,20 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
TransportBusinessSupport.validateLength(projectApply.getTransportRoute(), 100, "运输线路不能超过100个字");
}
private void validateChange(ProjectApply projectApply, String changeType) {
if (!List.of(CHANGE_TYPE_PROJECT, CHANGE_TYPE_RECORD).contains(changeType)) {
throw new ServiceException("请选择变更类型");
}
TransportBusinessSupport.validateRequired(projectApply.getChangeContent(), "请输入变更内容");
TransportBusinessSupport.validateRequired(projectApply.getChangeReason(), "请输入变更原因");
validateChangeLength(projectApply);
}
private void validateChangeLength(ProjectApply projectApply) {
TransportBusinessSupport.validateLength(projectApply.getChangeContent(), 2000, "变更内容不能超过2000个字");
TransportBusinessSupport.validateLength(projectApply.getChangeReason(), 2000, "变更原因不能超过2000个字");
}
private void validateAmount(BigDecimal value, String label, boolean nullable) {
if (!nullable && value == null) {
throw new ServiceException(label + "不能为空");
@@ -392,8 +469,8 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
private ProjectApply loadEditable(Long id, boolean assertDept) {
ProjectApply projectApply = loadExists(id);
if (assertDept) {
TransportBusinessSupport.assertCurrentDept(projectApply.getUndertakeDeptId(), "项目立项");
if (assertDept && !canCurrentUserOperate(projectApply)) {
throw new ServiceException("无权操作其他组织项目立项");
}
if (!List.of(STATUS_DRAFT, STATUS_WITHDRAWN, STATUS_REJECTED, "change_rejected").contains(projectApply.getApprovalStatus())) {
throw new ServiceException("当前状态不允许编辑");
@@ -401,6 +478,21 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
return projectApply;
}
private ProjectApply loadChangeable(Long id) {
ProjectApply projectApply = loadExists(id);
validateChangeable(projectApply);
if (!canCurrentUserOperate(projectApply)) {
throw new ServiceException("无权操作其他组织项目立项");
}
return projectApply;
}
private void validateChangeable(ProjectApply projectApply) {
if (!Objects.equals(projectApply.getApprovalStatus(), STATUS_APPROVED) || !Objects.equals(projectApply.getEffectiveType(), EFFECTIVE_FORMAL)) {
throw new ServiceException("仅正式生效且审批通过的项目允许发起变更");
}
}
private String resolveEditableStatus(ProjectApply projectApply) {
if (Func.isEmpty(projectApply.getApprovalStatus())) {
return STATUS_DRAFT;
@@ -428,7 +520,19 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
}
private void fillReadonly(ProjectApplyVO projectApplyVO) {
projectApplyVO.setReadonly(!Objects.equals(projectApplyVO.getUndertakeDeptId(), TransportBusinessSupport.currentDeptId("项目立项")));
projectApplyVO.setReadonly(!canCurrentUserOperate(projectApplyVO));
}
private boolean canCurrentUserOperate(ProjectApply projectApply) {
if (AuthUtil.isAdministrator()) {
return true;
}
Long currentDeptId = TransportBusinessSupport.currentDeptId("项目立项");
Long currentUserId = AuthUtil.getUserId();
return Objects.equals(projectApply.getUndertakeDeptId(), currentDeptId)
|| Objects.equals(projectApply.getCreateUser(), currentUserId)
|| Objects.equals(projectApply.getHandlerUserId(), currentUserId)
|| Objects.equals(projectApply.getPrincipalUserId(), currentUserId);
}
}