结算修改

This commit is contained in:
hayu 2026-01-28 18:09:27 +08:00
parent 181a93d340
commit 48cf463236
12 changed files with 592 additions and 5 deletions

View File

@ -0,0 +1,261 @@
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>项目结算计算</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<%@include file="../baseset.jsp" %>
<%@include file="../systemset.jsp" %>
<link rel="stylesheet" href="${bonuspath}/static/js/layui/css/layui.css" media="all">
<link rel="stylesheet" href="${bonuspath}/static/css/admin.css" media="all">
<link rel="stylesheet" href="${bonuspath}/static/css/common.css" media="all">
<style>
.layui-table-body layui-table-main {
height: 300px;
}
.layui-form-item .layui-input-inline {
width: 180px;
}
.table-container {
padding: 0 10px;
height: calc(100vh - 150px);
}
.table-section {
height: calc(50% - 20px);
margin-bottom: 20px;
}
.table-section:last-child {
margin-bottom: 0;
}
.table-header {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
padding-left: 10px;
border-left: 5px solid #1E9FFF;
}
.modified-cell {
color: #FF5722 !important;
font-weight: bold !important;
background-color: #fff5f0 !important;
}
.confirm-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
border-top: 1px solid #eee;
padding: 10px;
text-align: right;
z-index: 999;
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}
.confirm-btn {
padding: 0 30px;
height: 40px;
line-height: 40px;
font-size: 16px;
}
.summary-modal {
padding: 20px;
}
.summary-item {
margin-bottom: 15px;
padding: 10px;
border: 1px solid #e6e6e6;
border-radius: 4px;
}
.summary-header {
font-weight: bold;
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
}
.summary-row {
display: flex;
margin-bottom: 8px;
}
.summary-label {
width: 120px;
color: #666;
}
.summary-value {
flex: 1;
}
.modified-mark {
display: inline-block;
padding: 2px 6px;
background: #FF5722;
color: white;
border-radius: 3px;
font-size: 12px;
margin-left: 5px;
vertical-align: middle;
}
</style>
</head>
<body>
<div class="layui-form" lay-filter="calculation-form" id="calculation-form">
<input type="hidden" name="id" id="editId">
<!-- 加载中提示 -->
<div id="data-loading" style="display:none; text-align: center; padding: 30px 0;">
<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop" style="font-size: 30px;"></i>
<p>数据加载中,请稍候...</p>
</div>
<!-- 数据表格容器 -->
<div id="data-container" class="table-container" style="display:none;">
<div class="table-section" style="margin-bottom: 150px;">
<div class="table-header">物资领料明细</div>
<table class="layui-table" id="leaseTable" lay-filter="leaseTable"></table>
</div>
<div class="table-section">
<div class="table-header">物资退料明细</div>
<table class="layui-table" id="returnTable" lay-filter="returnTable"></table>
</div>
</div>
<!-- 底部确认栏 -->
<div class="confirm-bar">
<button class="layui-btn layui-btn-danger confirm-btn" id="confirmAllEdit">
确认修改
</button>
</div>
</div>
<!-- 修改确认弹框模板 -->
<script type="text/html" id="confirmModalTpl">
<div class="summary-modal">
<div style="margin-bottom: 20px; font-size: 16px; font-weight: bold; color: #333;">
共修改了 {{ d.totalCount }} 条数据
</div>
<div style="max-height: 400px; overflow-y: auto;">
{{# if(d.leaseModified.length > 0) { }}
<div class="summary-item">
<div class="summary-header">领料明细修改 ({{ d.leaseModified.length }}条)</div>
{{# layui.each(d.leaseModified, function(index, item){ }}
<div class="summary-row">
<div class="summary-label">物资名称:</div>
<div class="summary-value">{{ item.machineTypeName || '' }}</div>
</div>
{{# layui.each(item.fields, function(fieldName, fieldData){ }}
<div class="summary-row">
<div class="summary-label">{{ fieldData.label }}</div>
<div class="summary-value">
<span style="text-decoration: line-through; color: #999; margin-right: 10px;">
{{ fieldData.old }}
</span>
<span class="modified-cell">→ {{ fieldData.val }}</span>
<span class="modified-mark">已修改</span>
</div>
</div>
{{# }); }}
<div style="height: 1px; background: #eee; margin: 10px 0;"></div>
{{# }); }}
</div>
{{# } }}
{{# if(d.returnModified.length > 0) { }}
<div class="summary-item">
<div class="summary-header">退料明细修改 ({{ d.returnModified.length }}条)</div>
{{# layui.each(d.returnModified, function(index, item){ }}
<div class="summary-row">
<div class="summary-label">物资名称:</div>
<div class="summary-value">{{ item.machineTypeName || '' }}</div>
</div>
{{# layui.each(item.fields, function(fieldName, fieldData){ }}
<div class="summary-row">
<div class="summary-label">{{ fieldData.label }}</div>
<div class="summary-value">
<span style="text-decoration: line-through; color: #999; margin-right: 10px;">
{{ fieldData.old }}
</span>
<span class="modified-cell">→ {{ fieldData.val }}</span>
<span class="modified-mark">已修改</span>
</div>
</div>
{{# }); }}
<div style="height: 1px; background: #eee; margin: 10px 0;"></div>
{{# }); }}
</div>
{{# } }}
</div>
{{# if(d.totalCount === 0) { }}
<div style="text-align: center; padding: 30px; color: #999;">
暂无修改的数据
</div>
{{# } }}
</div>
</script>
<script src="${bonuspath}/static/js/layui/layui.js"></script>
<script>
// 先配置模块路径
layui.config({
base: '${bonuspath}/static/' //静态资源所在路径
}).extend({
index: 'js/index', //主入口模块
projectCost: 'js/projectCost/projectCostEdit'
});
// 然后按顺序加载模块
layui.use(['layer', 'element', 'form', 'table', 'laydate', 'index'], function(){
var $ = layui.$,
layer = layui.layer,
form = layui.form,
laydate = layui.laydate;
// 初始化日期选择器(与新增页一致)
laydate.render({elem: '#startTime', format: 'yyyy-MM-dd'});
laydate.render({elem: '#endTime', format: 'yyyy-MM-dd'});
// 【核心1解析URL参数的工具函数】
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return decodeURIComponent(r[2]);
return null;
}
// 加载projectCost模块
layui.use('projectCost', function(){
var projectCost = layui.projectCost;
// 解析URL传递的参数
var editId = getUrlParam('id');
var projectId = getUrlParam('projectId');
var startTime = getUrlParam('startTime');
var endTime = getUrlParam('endTime');
$('#editId').val(editId);
form.render();
setTimeout(function() {
var field = {
calculationId: $('#editId').val(),
projectId: projectId,
startTime: startTime,
endTime: endTime
};
// 此时执行,参数有效、方法可正常触发
console.log("传参",field)
projectCost.generateSettlement(field);
}, 200);
// 绑定确认修改按钮点击事件
$('#confirmAllEdit').click(function() {
projectCost.showConfirmModal();
});
});
});
</script>
</body>
</html>

View File

@ -204,6 +204,9 @@
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">
<i class="layui-icon layui-icon-search"></i> 查看
</a>
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit">
<i class="layui-icon layui-icon-edit"></i> 修改
</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">
<i class="layui-icon layui-icon-delete"></i> 删除
</a>

Binary file not shown.

View File

@ -1,9 +1,38 @@
<?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.bonus.cost.dao.ProjectCostDao">
<update id="editWfTaskRecord">
UPDATE wf_task_record
SET
NEW_NUM = #{newNum},
NEW_TIME = #{operateTime}
WHERE ID = #{id}
</update>
<update id="editWfInfoRecord">
UPDATE wf_info_record
SET
NEW_NUM = #{newNum},
NEW_TIME = #{operateTime}
WHERE ID = #{id}
</update>
<update id="editProjectCostCalculation">
update t_project_cost_calculation set total_amount = #{totalAmount} where id = #{calculationId}
</update>
<delete id="deleteCalculationSegments">
delete
from t_project_cost_calculation_segment
where calculation_detail_id = #{id}
</delete>
<delete id="deleteCalculationDetails">
delete
from t_project_cost_calculation_detail
where calculation_id = #{id}
</delete>
<select id="queryProjectLeaseDetails" parameterType="com.bonus.cost.beans.ProjectLeaseCostDetail" resultType="com.bonus.cost.beans.ProjectLeaseCostDetail">
SELECT
wir.ID,
wir.SUP_ID as supId,
wir.`CODE` AS machineCode,
1 AS operateType,
mt2.`NAME` AS machineTypeName,
@ -16,8 +45,18 @@
bp.`NAME` AS projectName,
wla.`CODE` AS taskCode,
wtr1.NUMBER AS taskCode,
ROUND(wir.num) AS leaseNum,
wtr.OPERATION_TIME AS operateTime,
CASE
WHEN wtr.NEW_NUM is not null THEN
ROUND(wtr.NEW_NUM)
ELSE
ROUND(wir.num)
END leaseNum,
CASE
WHEN wtr.NEW_TIME is not null THEN
wtr.NEW_TIME
ELSE
wtr.OPERATION_TIME
END operateTime,
wtr1.LEASE_PERSON AS operatePersonName,
pmo. NAME AS companyName,
pu.`NAME` as servicer,
@ -72,7 +111,19 @@
wir.ID as id,wir.MODEL_ID as machineTypeId,wla.`CODE` AS agreementCode,bu.`NAME` AS leaseUnit,
bp.`NAME` AS projectName,mmt.`NAME` as machineTypeName,mt.`NAME` as machineModel,mt.BUY_PRICE AS price,
mt.UNIT AS machineUnit,mt.ID AS machineTypeId,
wtr.NUMBER AS taskCode,wir.`CODE` as machineCode,wir.TIME as operateTime,ROUND(wir.NUM) as returnNum,
wtr.NUMBER AS taskCode,wir.`CODE` as machineCode,
CASE
WHEN wir.NEW_TIME is not null THEN
wir.NEW_TIME
ELSE
wir.TIME
END operateTime,
CASE
WHEN wir.NEW_NUM is not null THEN
ROUND( wir.NEW_NUM )
ELSE
ROUND( wir.NUM )
END returnNum,
mt.IS_COUNT as isCount,wir.TYPE as type,pmo.`NAME` as companyName,wrd.OPERATOR as operatePersonName,
mm.REMARK AS remark,bs.`NAME` as bsName,wir.RM_STATUS as rmStatus,2 AS operateType,mt.LEASE_PRICE AS price,
mt3.`NAME` AS machineCodeName,mm.REMARK as oldMachineCode
@ -83,7 +134,7 @@
LEFT JOIN wf_agreement_task wat ON wtr.ID = wat.TASK_ID
LEFT JOIN wf_lease_agreement wla ON wat.AGREEMENT_ID = wla.ID
LEFT JOIN bm_unit bu ON wla.LEASE_COMPANY = bu.ID
LEFT JOIN pm_organization pmo on wtr.ORG_ID = pmo.id
LEFT JOIN pm_organization pmo on wtr.ORG_ID = pmo.id
LEFT JOIN bm_project bp ON wla.PROJECT = bp.ID
LEFT JOIN pm_user pu ON wtr.CHECKER_ID = pu.ID
LEFT JOIN mm_type mt ON wir.MODEL_ID = mt.ID

View File

@ -45,7 +45,6 @@ public class ProjectCostCalculation {
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private String createTime;
/**

View File

@ -17,6 +17,10 @@ public class ProjectLeaseCostDetail {
*/
private Integer id;
private Integer supId;
private Integer calculationId;
/**
* 机具名称
*/
@ -99,6 +103,8 @@ public class ProjectLeaseCostDetail {
*/
private Byte isCount;
private Integer newNum;
/**
* 领料数量
*/
@ -413,5 +419,29 @@ public class ProjectLeaseCostDetail {
public void setDifferenceQuantity(BigDecimal differenceQuantity) {
this.differenceQuantity = differenceQuantity;
}
public Integer getSupId() {
return supId;
}
public void setSupId(Integer supId) {
this.supId = supId;
}
public Integer getNewNum() {
return newNum;
}
public void setNewNum(Integer newNum) {
this.newNum = newNum;
}
public Integer getCalculationId() {
return calculationId;
}
public void setCalculationId(Integer calculationId) {
this.calculationId = calculationId;
}
}

View File

@ -53,6 +53,11 @@ public class ProjectCostController extends BaseController<T> {
return "/projectCost/calculation_detail";
}
@RequestMapping("calculation_edit")
public String calculationEdit() {
return "/projectCost/calculation_edit";
}
/**
* 前往结算计算表单页面
*/
@ -135,6 +140,20 @@ public class ProjectCostController extends BaseController<T> {
return ar;
}
@RequestMapping("editSettlement")
@ResponseBody
public AjaxRes editSettlement(@RequestBody ProjectLeaseCostDetail o) {
AjaxRes ar = getAjaxRes();
try {
int res = projectCostService.editSettlement(o);
ar.setSucceed(res);
} catch (Exception e) {
logger.error(e.toString(), e);
ar.setFailMsg(GlobalConst.DATA_FAIL);
}
return ar;
}
/**
* 打印结算详情
*/

View File

@ -106,4 +106,45 @@ public interface ProjectCostDao extends BaseDao<ProjectLeaseCostDetail> {
* @return 影响行数
*/
int deleteCalculation(Integer id);
/**
* 修改流程任务记录
*
* @param o 流程任务记录
* @return 影响行数
*/
int editWfTaskRecord(ProjectLeaseCostDetail o);
/**
* 修改流程信息记录
*
* @param o 流程信息记录
* @return 影响行数
*/
int editWfInfoRecord(ProjectLeaseCostDetail o);
/**
* 删除计算结果时间段
*
* @param id 计算结果ID
* @return 影响行数
*/
int deleteCalculationSegments(Integer id);
/**
* 删除计算结果明细
*
* @param id 删除计算结果ID
* @return 影响行数
*/
int deleteCalculationDetails(Integer id);
/**
* 修改计算结果
*
* @param calculationId 计算结果ID
* @param totalAmount 总金额
* @return 影响行数
*/
int editProjectCostCalculation(@Param("calculationId") Integer calculationId,@Param("totalAmount") Double totalAmount);
}

View File

@ -53,6 +53,89 @@ public class NewSettlementService {
private static final DateTimeFormatter INPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Transactional(rollbackFor = Exception.class)
public int editSettlement(ProjectLeaseCostDetail o) {
//根据领料还是退料进行数据修改
Byte operateType = o.getOperateType();
if (Byte.valueOf("1").equals(operateType)) {
int res = projectCostDao.editWfTaskRecord(o);
if (res == 0) {
throw new RuntimeException("修改领料数据失败!");
}
} else if (Byte.valueOf("2").equals(operateType)) {
int res = projectCostDao.editWfInfoRecord(o);
if (res == 0) {
throw new RuntimeException("修改退料数据失败!");
}
}
//调用结算计算逻辑
ProjectLeaseCostDetail bean = new ProjectLeaseCostDetail();
bean.setProjectId(o.getProjectId());
bean.setStartTime(o.getStartTime());
bean.setEndTime(o.getEndTime());
Map<String, Object> newSettlement = getNewSettlement(bean);
//将结算数据保存更新
List<Map<String, Object>> calculationResults = (List<Map<String, Object>>) newSettlement
.get("calculationResults");
//总金额
Double totalAmount = safeToDouble(newSettlement.get("totalAmount"), 0.0);
//修改总金额
int res = projectCostDao.editProjectCostCalculation(o.getCalculationId(), totalAmount);
//删除之前的数据
//1现根据calculationId查询详情数据
List<ProjectCostCalculationDetail> details = projectCostDao.queryCalculationDetails(o.getCalculationId());
//2根据详情数据删除工程费用计算结果时间段表
for (ProjectCostCalculationDetail detail : details){
projectCostDao.deleteCalculationSegments(detail.getId());
}
//3删除详情数据
projectCostDao.deleteCalculationDetails(o.getCalculationId());
// 保存计算结果明细和时间段
if (calculationResults != null && !calculationResults.isEmpty()) {
for (Map<String, Object> resultItem : calculationResults) {
// 创建明细记录
ProjectCostCalculationDetail detail = new ProjectCostCalculationDetail();
detail.setCalculationId(o.getCalculationId());
detail.setMachineTypeId(safeToInteger(resultItem.get("machineTypeId"), 0));
detail.setMachineTypeName(safeToString(resultItem.get("machineTypeName"), ""));
detail.setMachineModel(safeToString(resultItem.get("machineModel"), ""));
detail.setMachineUnit(safeToString(resultItem.get("machineUnit"), ""));
detail.setPrice(safeToDouble(resultItem.get("price"), 0.0));
detail.setCurrentCount(safeToInteger(resultItem.get("currentCount"), 0));
detail.setAmount(safeToDouble(resultItem.get("amount"), 0.0));
detail.setFirstLeaseTime(safeToString(resultItem.get("firstLeaseTime"), ""));
detail.setLastReturnTime(safeToString(resultItem.get("lastReturnTime"), ""));
// 保存明细记录
projectCostDao.saveCalculationDetail(detail);
Integer detailId = detail.getId();
// 保存时间段记录
@SuppressWarnings("unchecked")
List<Map<String, Object>> segments = (List<Map<String, Object>>) resultItem.get("segments");
if (segments != null && !segments.isEmpty()) {
List<ProjectCostCalculationSegment> segmentList = new ArrayList<>();
for (Map<String, Object> segmentItem : segments) {
ProjectCostCalculationSegment segment = new ProjectCostCalculationSegment();
segment.setCalculationDetailId(detailId);
segment.setStartTime(safeToString(segmentItem.get("startTime"), ""));
segment.setEndTime(safeToString(segmentItem.get("endTime"), ""));
segment.setDays(safeToInteger(segmentItem.get("days"), 0));
segment.setCount(safeToInteger(segmentItem.get("count"), 0));
segment.setAmount(safeToDouble(segmentItem.get("amount"), 0.0));
segmentList.add(segment);
}
projectCostDao.saveCalculationSegments(segmentList);
}
}
}
return 1;
}
/**
* 新的结算逻辑
*
@ -499,5 +582,91 @@ public class NewSettlementService {
return projectCostDao.queryProjectReturnDetails(o);
}
/**
* 安全转换为String类型
*
* @param obj 要转换的对象
* @param defaultValue 默认值
* @return 转换后的String值
*/
private String safeToString(Object obj, String defaultValue) {
if (obj == null) {
return defaultValue;
}
if (obj instanceof String) {
return (String) obj;
}
return String.valueOf(obj);
}
/**
* 安全转换为Integer类型
*
* @param obj 要转换的对象
* @param defaultValue 默认值
* @return 转换后的Integer值
*/
private Integer safeToInteger(Object obj, Integer defaultValue) {
if (obj == null) {
return defaultValue;
}
if (obj instanceof Integer) {
return (Integer) obj;
} else if (obj instanceof Double) {
return ((Double) obj).intValue();
} else if (obj instanceof Number) {
return ((Number) obj).intValue();
} else if (obj instanceof String) {
try {
return Integer.parseInt((String) obj);
} catch (NumberFormatException e) {
return defaultValue;
}
}
// 其他类型尝试转换为字符串再解析
try {
return Integer.parseInt(String.valueOf(obj));
} catch (NumberFormatException e) {
return defaultValue;
}
}
/**
* 安全转换为Double类型
*
* @param obj 要转换的对象
* @param defaultValue 默认值
* @return 转换后的Double值
*/
private Double safeToDouble(Object obj, Double defaultValue) {
if (obj == null) {
return defaultValue;
}
if (obj instanceof Double) {
return (Double) obj;
} else if (obj instanceof Integer) {
return ((Integer) obj).doubleValue();
} else if (obj instanceof Number) {
return ((Number) obj).doubleValue();
} else if (obj instanceof String) {
try {
return Double.parseDouble((String) obj);
} catch (NumberFormatException e) {
return defaultValue;
}
}
// 其他类型尝试转换为字符串再解析
try {
return Double.parseDouble(String.valueOf(obj));
} catch (NumberFormatException e) {
return defaultValue;
}
}
}

View File

@ -115,4 +115,12 @@ public interface ProjectCostService {
* @throws Exception 导出异常
*/
void exportOperationRecords(Integer id, javax.servlet.http.HttpServletResponse response) throws Exception;
/**
* 修改结算信息
*
* @param o 结算信息
* @return 是否成功
*/
int editSettlement(ProjectLeaseCostDetail o);
}

View File

@ -2157,6 +2157,12 @@ public class ProjectCostServiceImpl implements ProjectCostService {
ouputStream.flush();
ouputStream.close();
}
@Override
public int editSettlement(ProjectLeaseCostDetail o) {
return newSettlementService.editSettlement(o);
}
/**
* 封装导出Excel的方法适用于只有HttpServletResponse的情况
*