feat: 完成履约管理模块全量功能迭代
本次迭代包含以下核心功能: 1. 新增履约时效总览可视化页面,支持多维度数据统计 2. 实现物料/客户/供应商的Excel批量导入导出功能 3. 新增订单批量结单功能,优化结单流程校验 4. 完善日志配置,新增文件日志落地 5. 修复分类查询逻辑,优化多租户数据隔离 6. 新增甲方履约结单管理页面与权限控制 7. 重构部分Mapper与Service接口,增强代码健壮性
This commit is contained in:
@@ -1,19 +1,40 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
public class BizClient extends BaseEntity {
|
||||
private Long clientId;
|
||||
private Long tenantId;
|
||||
|
||||
@Excel(name = "客户编号", type = Excel.Type.IMPORT)
|
||||
private String clientNo;
|
||||
|
||||
@Excel(name = "客户名称", type = Excel.Type.IMPORT)
|
||||
private String clientName;
|
||||
|
||||
@Excel(name = "联系人", type = Excel.Type.IMPORT)
|
||||
private String contact;
|
||||
|
||||
@Excel(name = "电话", type = Excel.Type.IMPORT)
|
||||
private String phone;
|
||||
|
||||
@Excel(name = "邮箱", type = Excel.Type.IMPORT)
|
||||
private String email;
|
||||
|
||||
@Excel(name = "城市", type = Excel.Type.IMPORT)
|
||||
private String city;
|
||||
|
||||
@Excel(name = "地址", type = Excel.Type.IMPORT)
|
||||
private String address;
|
||||
|
||||
@Excel(name = "等级", type = Excel.Type.IMPORT, combo = {"A", "B", "C"}, defaultValue = "B")
|
||||
private String grade;
|
||||
|
||||
@Excel(name = "来源", type = Excel.Type.IMPORT)
|
||||
private String source;
|
||||
|
||||
@Excel(name = "状态", type = Excel.Type.IMPORT, readConverterExp = "0=正常,1=停用", defaultValue = "0")
|
||||
private String status;
|
||||
|
||||
public Long getClientId() { return clientId; }
|
||||
|
||||
@@ -1,25 +1,46 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
public class BizMaterial extends BaseEntity {
|
||||
private Long materialId;
|
||||
private Long tenantId;
|
||||
private Long categoryId;
|
||||
|
||||
@Excel(name = "物料编码", type = Excel.Type.IMPORT)
|
||||
private String materialCode;
|
||||
|
||||
@Excel(name = "物料名称", type = Excel.Type.IMPORT)
|
||||
private String materialName;
|
||||
|
||||
@Excel(name = "规格型号", type = Excel.Type.IMPORT)
|
||||
private String spec;
|
||||
|
||||
@Excel(name = "单位", type = Excel.Type.IMPORT)
|
||||
private String unit;
|
||||
|
||||
@Excel(name = "品牌", type = Excel.Type.IMPORT)
|
||||
private String brand;
|
||||
|
||||
@Excel(name = "描述", type = Excel.Type.IMPORT)
|
||||
private String description;
|
||||
|
||||
@Excel(name = "状态", type = Excel.Type.IMPORT, readConverterExp = "0=正常,1=停用", defaultValue = "0")
|
||||
private String status;
|
||||
// search helper
|
||||
private String categoryName;
|
||||
|
||||
// 新增字段
|
||||
@Excel(name = "性能参数", type = Excel.Type.IMPORT)
|
||||
private String performanceParams;
|
||||
|
||||
@Excel(name = "材质", type = Excel.Type.IMPORT)
|
||||
private String material;
|
||||
|
||||
@Excel(name = "用途", type = Excel.Type.IMPORT)
|
||||
private String purpose;
|
||||
|
||||
private String imageUrl;
|
||||
|
||||
public Long getMaterialId() { return materialId; }
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
public class BizSupplier extends BaseEntity {
|
||||
private Long supplierId;
|
||||
private Long tenantId;
|
||||
|
||||
@Excel(name = "供应商名称", type = Excel.Type.IMPORT)
|
||||
private String supplierName;
|
||||
|
||||
@Excel(name = "联系人", type = Excel.Type.IMPORT)
|
||||
private String contact;
|
||||
|
||||
@Excel(name = "电话", type = Excel.Type.IMPORT)
|
||||
private String phone;
|
||||
|
||||
@Excel(name = "邮箱", type = Excel.Type.IMPORT)
|
||||
private String email;
|
||||
|
||||
@Excel(name = "地址", type = Excel.Type.IMPORT)
|
||||
private String address;
|
||||
|
||||
private Long userId;
|
||||
|
||||
@Excel(name = "状态", type = Excel.Type.IMPORT, readConverterExp = "0=正常,1=停用", defaultValue = "0")
|
||||
private String status;
|
||||
|
||||
public Long getSupplierId() { return supplierId; }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ruoyi.system.mapper.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -12,4 +13,7 @@ public interface BizClientMapper {
|
||||
int deleteBizClientById(Long id);
|
||||
int deleteBizClientByIds(Long[] ids);
|
||||
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
|
||||
|
||||
// 按客户编号查询(导入判重用)
|
||||
BizClient selectBizClientByNo(@Param("tenantId") Long tenantId, @Param("clientNo") String clientNo);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface BizDeliveryOrderMapper {
|
||||
List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query);
|
||||
List<BizDeliveryOrder> selectBizDeliveryOrderList(@Param("query") BizDeliveryOrder query);
|
||||
BizDeliveryOrder selectBizDeliveryOrderById(Long id);
|
||||
int insertBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int updateBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int insertBizDeliveryOrder(@Param("record") BizDeliveryOrder record);
|
||||
int updateBizDeliveryOrder(@Param("record") BizDeliveryOrder record);
|
||||
int deleteBizDeliveryOrderById(Long id);
|
||||
int deleteBizDeliveryOrderByIds(Long[] ids);
|
||||
|
||||
@@ -25,9 +25,15 @@ public interface BizDeliveryOrderMapper {
|
||||
List<Map<String, Object>> selectMaterialRecords(@Param("materialId") Long materialId);
|
||||
|
||||
// 在途统计
|
||||
Map<String, Object> selectTransitStats();
|
||||
Map<String, Object> selectTransitStats(@Param("tenantId") Long tenantId);
|
||||
// 履约时间线
|
||||
List<Map<String, Object>> selectTimelineData(@Param("tenantId") Long tenantId,
|
||||
@Param("type") String type,
|
||||
@Param("status") String status,
|
||||
@Param("dateFrom") String dateFrom,
|
||||
@Param("dateTo") String dateTo);
|
||||
// 历史统计
|
||||
Map<String, Object> selectHistoryStats();
|
||||
Map<String, Object> selectHistoryStats(@Param("tenantId") Long tenantId, @Param("type") String type);
|
||||
// 结单统计
|
||||
Map<String, Object> selectCloseDateStats();
|
||||
Map<String, Object> selectCloseDateStats(@Param("tenantId") Long tenantId);
|
||||
}
|
||||
|
||||
@@ -32,4 +32,7 @@ public interface BizMaterialMapper {
|
||||
|
||||
// 根据物料名称精确匹配(同名称不同规格/品牌对比)
|
||||
List<BizMaterial> selectMaterialsByExactName(@Param("materialName") String materialName, @Param("excludeId") Long excludeId);
|
||||
|
||||
// 按物料编码查询(导入判重用)
|
||||
BizMaterial selectBizMaterialByCode(@Param("tenantId") Long tenantId, @Param("materialCode") String materialCode);
|
||||
}
|
||||
|
||||
@@ -12,4 +12,7 @@ public interface BizSupplierMapper {
|
||||
int updateBizSupplier(BizSupplier record);
|
||||
int deleteBizSupplierById(Long id);
|
||||
int deleteBizSupplierByIds(Long[] ids);
|
||||
|
||||
// 按供应商名称查询(导入判重用)
|
||||
BizSupplier selectBizSupplierByName(@Param("tenantId") Long tenantId, @Param("supplierName") String supplierName);
|
||||
}
|
||||
|
||||
@@ -12,4 +12,7 @@ public interface IBizClientService {
|
||||
int deleteBizClientById(Long id);
|
||||
int deleteBizClientByIds(Long[] ids);
|
||||
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
|
||||
|
||||
// Excel批量导入
|
||||
String importClient(List<BizClient> clientList, Boolean updateSupport, String operName, Long tenantId);
|
||||
}
|
||||
|
||||
@@ -17,14 +17,17 @@ public interface IBizDeliveryOrderService {
|
||||
int complete(Long id, String username);
|
||||
int recall(Long id);
|
||||
int setCloseDate(Long id, String closeDate, String username);
|
||||
int batchSetCloseDate(List<Long> ids, String closeDate, String username);
|
||||
|
||||
// 物料发货记录
|
||||
List<Map<String, Object>> selectMaterialRecords(Long materialId);
|
||||
|
||||
// 在途统计
|
||||
Map<String, Object> selectTransitStats();
|
||||
Map<String, Object> selectTransitStats(Long tenantId);
|
||||
// 历史统计
|
||||
Map<String, Object> selectHistoryStats();
|
||||
Map<String, Object> selectHistoryStats(Long tenantId, String type);
|
||||
// 结单统计
|
||||
Map<String, Object> selectCloseDateStats();
|
||||
Map<String, Object> selectCloseDateStats(Long tenantId);
|
||||
// 履约时间线
|
||||
List<Map<String, Object>> selectTimelineData(Long tenantId, String type, String status, String dateFrom, String dateTo);
|
||||
}
|
||||
|
||||
@@ -26,4 +26,7 @@ public interface IBizMaterialService {
|
||||
|
||||
// 根据物料名称精确匹配(同名称不同规格/品牌对比)
|
||||
List<BizMaterial> selectMaterialsByExactName(String materialName, Long excludeId);
|
||||
|
||||
// Excel批量导入
|
||||
String importMaterial(List<BizMaterial> materialList, Boolean updateSupport, String operName, Long tenantId);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,7 @@ public interface IBizSupplierService {
|
||||
int updateBizSupplier(BizSupplier record);
|
||||
int deleteBizSupplierById(Long id);
|
||||
int deleteBizSupplierByIds(Long[] ids);
|
||||
|
||||
// Excel批量导入
|
||||
String importSupplier(List<BizSupplier> supplierList, Boolean updateSupport, String operName, Long tenantId);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.ruoyi.system.service.bid.impl;
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import com.ruoyi.system.mapper.bid.BizClientMapper;
|
||||
import com.ruoyi.system.service.bid.IBizClientService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
@@ -47,4 +49,64 @@ public class BizClientServiceImpl implements IBizClientService {
|
||||
public List<Map<String, Object>> selectClientDeliveryOrders(Long clientId) {
|
||||
return mapper.selectClientDeliveryOrders(clientId);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// Excel批量导入
|
||||
// ═══════════════════════════════════════════════
|
||||
@Override
|
||||
public String importClient(List<BizClient> clientList, Boolean updateSupport, String operName, Long tenantId) {
|
||||
if (StringUtils.isNull(clientList) || clientList.isEmpty()) {
|
||||
throw new ServiceException("导入数据不能为空!");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
for (BizClient row : clientList) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(row.getClientName())) {
|
||||
throw new ServiceException("客户名称不能为空");
|
||||
}
|
||||
// 按客户编号判重(编号为空则跳过判重直接新增)
|
||||
BizClient existing = null;
|
||||
if (StringUtils.isNotEmpty(row.getClientNo())) {
|
||||
existing = mapper.selectBizClientByNo(tenantId, row.getClientNo());
|
||||
}
|
||||
if (existing == null) {
|
||||
row.setTenantId(tenantId);
|
||||
row.setCreateBy(operName);
|
||||
if (StringUtils.isEmpty(row.getStatus())) {
|
||||
row.setStatus("0");
|
||||
}
|
||||
if (StringUtils.isEmpty(row.getGrade())) {
|
||||
row.setGrade("B");
|
||||
}
|
||||
mapper.insertBizClient(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、客户 " + row.getClientName() + " 导入成功");
|
||||
} else if (updateSupport) {
|
||||
row.setClientId(existing.getClientId());
|
||||
row.setTenantId(tenantId);
|
||||
row.setUpdateBy(operName);
|
||||
mapper.updateBizClient(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、客户 " + row.getClientName() + " 更新成功");
|
||||
} else {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>" + failureNum + "、客户编号 " + row.getClientNo() + " 已存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、客户 " + (row.getClientName() == null ? "空" : row.getClientName()) + " 导入失败:" + e.getMessage();
|
||||
failureMsg.append(msg);
|
||||
}
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
|
||||
@Service
|
||||
public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
|
||||
@Autowired
|
||||
@@ -126,11 +128,36 @@ public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
|
||||
@Override
|
||||
@Transactional
|
||||
public int setCloseDate(Long id, String closeDate, String username) {
|
||||
if (closeDate == null || closeDate.isEmpty()) {
|
||||
return mapper.updateDeliveryStatus(id, null, null, null, "");
|
||||
} else {
|
||||
return mapper.updateDeliveryStatus(id, null, null, java.sql.Date.valueOf(closeDate), username);
|
||||
BizDeliveryOrder d = mapper.selectBizDeliveryOrderById(id);
|
||||
if (d == null) throw new RuntimeException("发货单不存在");
|
||||
String status = d.getDeliveryStatus();
|
||||
// 仅允许已签收(history)的订单设置结单日期
|
||||
if (!"history".equals(status)) {
|
||||
throw new RuntimeException("当前状态(" + status + ")不允许设置结单日期,请先完成收货签收");
|
||||
}
|
||||
if (closeDate == null || closeDate.isEmpty()) {
|
||||
throw new RuntimeException("结单日期不能为空");
|
||||
}
|
||||
// 设置结单日期,同时将状态从 history(已签收) 置为 closed(已结单)
|
||||
java.sql.Date parsedDate;
|
||||
try {
|
||||
parsedDate = java.sql.Date.valueOf(closeDate);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("日期格式错误,请使用 yyyy-MM-dd 格式");
|
||||
}
|
||||
return mapper.updateDeliveryStatus(id, "closed", null, parsedDate, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int batchSetCloseDate(List<Long> ids, String closeDate, String username) {
|
||||
if (ids == null || ids.isEmpty()) throw new ServiceException("请选择要结单的订单");
|
||||
if (closeDate == null || closeDate.isEmpty()) throw new ServiceException("请设置结单日期");
|
||||
int total = 0;
|
||||
for (Long id : ids) {
|
||||
total += setCloseDate(id, closeDate, username);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
@@ -143,17 +170,22 @@ public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> selectTransitStats() {
|
||||
return mapper.selectTransitStats();
|
||||
public Map<String, Object> selectTransitStats(Long tenantId) {
|
||||
return mapper.selectTransitStats(tenantId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> selectHistoryStats() {
|
||||
return mapper.selectHistoryStats();
|
||||
public Map<String, Object> selectHistoryStats(Long tenantId, String type) {
|
||||
return mapper.selectHistoryStats(tenantId, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> selectCloseDateStats() {
|
||||
return mapper.selectCloseDateStats();
|
||||
public Map<String, Object> selectCloseDateStats(Long tenantId) {
|
||||
return mapper.selectCloseDateStats(tenantId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> selectTimelineData(Long tenantId, String type, String status, String dateFrom, String dateTo) {
|
||||
return mapper.selectTimelineData(tenantId, type, status, dateFrom, dateTo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.ruoyi.system.service.bid.impl;
|
||||
import com.ruoyi.system.domain.bid.BizMaterial;
|
||||
import com.ruoyi.system.mapper.bid.BizMaterialMapper;
|
||||
import com.ruoyi.system.service.bid.IBizMaterialService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.*;
|
||||
@@ -113,4 +115,62 @@ public class BizMaterialServiceImpl implements IBizMaterialService {
|
||||
public List<BizMaterial> selectMaterialsByExactName(String materialName, Long excludeId) {
|
||||
return mapper.selectMaterialsByExactName(materialName, excludeId);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// Excel批量导入
|
||||
// ═══════════════════════════════════════════════
|
||||
@Override
|
||||
public String importMaterial(List<BizMaterial> materialList, Boolean updateSupport, String operName, Long tenantId) {
|
||||
if (StringUtils.isNull(materialList) || materialList.isEmpty()) {
|
||||
throw new ServiceException("导入数据不能为空!");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
for (BizMaterial row : materialList) {
|
||||
try {
|
||||
// 校验必填字段
|
||||
if (StringUtils.isEmpty(row.getMaterialCode())) {
|
||||
throw new ServiceException("物料编码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(row.getMaterialName())) {
|
||||
throw new ServiceException("物料名称不能为空");
|
||||
}
|
||||
// 查询是否已存在
|
||||
BizMaterial existing = mapper.selectBizMaterialByCode(tenantId, row.getMaterialCode());
|
||||
if (existing == null) {
|
||||
row.setTenantId(tenantId);
|
||||
row.setCreateBy(operName);
|
||||
if (StringUtils.isEmpty(row.getStatus())) {
|
||||
row.setStatus("0");
|
||||
}
|
||||
mapper.insertBizMaterial(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、物料编码 " + row.getMaterialCode() + " 导入成功");
|
||||
} else if (updateSupport) {
|
||||
row.setMaterialId(existing.getMaterialId());
|
||||
row.setTenantId(tenantId);
|
||||
row.setUpdateBy(operName);
|
||||
mapper.updateBizMaterial(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、物料编码 " + row.getMaterialCode() + " 更新成功");
|
||||
} else {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>" + failureNum + "、物料编码 " + row.getMaterialCode() + " 已存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、物料编码 " + (row.getMaterialCode() == null ? "空" : row.getMaterialCode()) + " 导入失败:" + e.getMessage();
|
||||
failureMsg.append(msg);
|
||||
}
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.ruoyi.system.service.bid.impl;
|
||||
import com.ruoyi.system.domain.bid.BizSupplier;
|
||||
import com.ruoyi.system.mapper.bid.BizSupplierMapper;
|
||||
import com.ruoyi.system.service.bid.IBizSupplierService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
@@ -46,4 +48,58 @@ public class BizSupplierServiceImpl implements IBizSupplierService {
|
||||
public int deleteBizSupplierByIds(Long[] ids) {
|
||||
return mapper.deleteBizSupplierByIds(ids);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
// Excel批量导入
|
||||
// ═══════════════════════════════════════════════
|
||||
@Override
|
||||
public String importSupplier(List<BizSupplier> supplierList, Boolean updateSupport, String operName, Long tenantId) {
|
||||
if (StringUtils.isNull(supplierList) || supplierList.isEmpty()) {
|
||||
throw new ServiceException("导入数据不能为空!");
|
||||
}
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
for (BizSupplier row : supplierList) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(row.getSupplierName())) {
|
||||
throw new ServiceException("供应商名称不能为空");
|
||||
}
|
||||
// 按供应商名称判重
|
||||
BizSupplier existing = mapper.selectBizSupplierByName(tenantId, row.getSupplierName());
|
||||
if (existing == null) {
|
||||
row.setTenantId(tenantId);
|
||||
row.setCreateBy(operName);
|
||||
if (StringUtils.isEmpty(row.getStatus())) {
|
||||
row.setStatus("0");
|
||||
}
|
||||
mapper.insertBizSupplier(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、供应商 " + row.getSupplierName() + " 导入成功");
|
||||
} else if (updateSupport) {
|
||||
row.setSupplierId(existing.getSupplierId());
|
||||
row.setTenantId(tenantId);
|
||||
row.setUpdateBy(operName);
|
||||
mapper.updateBizSupplier(row);
|
||||
successNum++;
|
||||
successMsg.append("<br/>" + successNum + "、供应商 " + row.getSupplierName() + " 更新成功");
|
||||
} else {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>" + failureNum + "、供应商 " + row.getSupplierName() + " 已存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
String msg = "<br/>" + failureNum + "、供应商 " + (row.getSupplierName() == null ? "空" : row.getSupplierName()) + " 导入失败:" + e.getMessage();
|
||||
failureMsg.append(msg);
|
||||
}
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
SELECT * FROM biz_client WHERE client_id=#{id}
|
||||
</select>
|
||||
|
||||
<!-- 按客户编号查询(导入时判重用) -->
|
||||
<select id="selectBizClientByNo" resultMap="BaseRM">
|
||||
SELECT * FROM biz_client WHERE tenant_id=#{tenantId} AND client_no=#{clientNo} LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertBizClient" useGeneratedKeys="true" keyProperty="clientId">
|
||||
INSERT INTO biz_client(tenant_id,client_no,client_name,contact,phone,email,city,address,grade,source,status,create_by,create_time)
|
||||
VALUES(#{tenantId},#{clientNo},#{clientName},#{contact},#{phone},#{email},#{city},#{address},#{grade},#{source},#{status},#{createBy},NOW())
|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
LEFT JOIN biz_client_quote cq ON d.client_quote_id = cq.quote_id
|
||||
LEFT JOIN biz_client cl ON cq.client_id = cl.client_id
|
||||
<where>
|
||||
<if test="tenantId != null"> AND d.tenant_id=#{tenantId}</if>
|
||||
<if test="type != null and type != ''"> AND d.type=#{type}</if>
|
||||
<if test="doNo != null and doNo != ''"> AND d.do_no LIKE CONCAT('%',#{doNo},'%')</if>
|
||||
<if test="supplierId != null"> AND d.supplier_id=#{supplierId}</if>
|
||||
<if test="deliveryStatus != null and deliveryStatus != ''"> AND d.delivery_status=#{deliveryStatus}</if>
|
||||
<if test="supplierName != null and supplierName != ''"> AND s.supplier_name LIKE CONCAT('%',#{supplierName},'%')</if>
|
||||
<if test="clientName != null and clientName != ''"> AND cl.client_name LIKE CONCAT('%',#{clientName},'%')</if>
|
||||
<if test="query.tenantId != null"> AND d.tenant_id=#{query.tenantId}</if>
|
||||
<if test="query.type != null and query.type != ''"> AND d.type=#{query.type}</if>
|
||||
<if test="query.doNo != null and query.doNo != ''"> AND d.do_no LIKE CONCAT('%',#{query.doNo},'%')</if>
|
||||
<if test="query.supplierId != null"> AND d.supplier_id=#{query.supplierId}</if>
|
||||
<if test="query.deliveryStatus != null and query.deliveryStatus != ''"> AND d.delivery_status=#{query.deliveryStatus}</if>
|
||||
<if test="query.supplierName != null and query.supplierName != ''"> AND s.supplier_name LIKE CONCAT('%',#{query.supplierName},'%')</if>
|
||||
<if test="query.clientName != null and query.clientName != ''"> AND cl.client_name LIKE CONCAT('%',#{query.clientName},'%')</if>
|
||||
</where>
|
||||
ORDER BY d.create_time DESC
|
||||
</select>
|
||||
@@ -55,26 +55,26 @@
|
||||
WHERE d.do_id=#{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertBizDeliveryOrder" useGeneratedKeys="true" keyProperty="doId">
|
||||
<insert id="insertBizDeliveryOrder" useGeneratedKeys="true" keyProperty="record.doId">
|
||||
INSERT INTO biz_delivery_order(tenant_id,do_no,type,rfq_id,quotation_id,client_quote_id,supplier_id,total_amount,currency,delivery_date,delay_date,actual_close_date,close_date_set_by,delivery_status,remark,create_by,create_time)
|
||||
VALUES(#{tenantId},#{doNo},#{type},#{rfqId},#{quotationId},#{clientQuoteId},#{supplierId},#{totalAmount},#{currency},#{deliveryDate},#{delayDate},#{actualCloseDate},#{closeDateSetBy},#{deliveryStatus},#{remark},#{createBy},NOW())
|
||||
VALUES(#{record.tenantId},#{record.doNo},#{record.type},#{record.rfqId},#{record.quotationId},#{record.clientQuoteId},#{record.supplierId},#{record.totalAmount},#{record.currency},#{record.deliveryDate},#{record.delayDate},#{record.actualCloseDate},#{record.closeDateSetBy},#{record.deliveryStatus},#{record.remark},#{record.createBy},NOW())
|
||||
</insert>
|
||||
|
||||
<update id="updateBizDeliveryOrder">
|
||||
UPDATE biz_delivery_order
|
||||
<set>
|
||||
<if test="doNo != null">do_no=#{doNo},</if>
|
||||
<if test="supplierId != null">supplier_id=#{supplierId},</if>
|
||||
<if test="totalAmount != null">total_amount=#{totalAmount},</if>
|
||||
<if test="deliveryDate != null">delivery_date=#{deliveryDate},</if>
|
||||
<if test="delayDate != null">delay_date=#{delayDate},</if>
|
||||
<if test="actualCloseDate != null">actual_close_date=#{actualCloseDate},</if>
|
||||
<if test="closeDateSetBy != null">close_date_set_by=#{closeDateSetBy},</if>
|
||||
<if test="deliveryStatus != null">delivery_status=#{deliveryStatus},</if>
|
||||
<if test="remark != null">remark=#{remark},</if>
|
||||
update_by=#{updateBy}, update_time=NOW()
|
||||
<if test="record.doNo != null">do_no=#{record.doNo},</if>
|
||||
<if test="record.supplierId != null">supplier_id=#{record.supplierId},</if>
|
||||
<if test="record.totalAmount != null">total_amount=#{record.totalAmount},</if>
|
||||
<if test="record.deliveryDate != null">delivery_date=#{record.deliveryDate},</if>
|
||||
<if test="record.delayDate != null">delay_date=#{record.delayDate},</if>
|
||||
<if test="record.actualCloseDate != null">actual_close_date=#{record.actualCloseDate},</if>
|
||||
<if test="record.closeDateSetBy != null">close_date_set_by=#{record.closeDateSetBy},</if>
|
||||
<if test="record.deliveryStatus != null">delivery_status=#{record.deliveryStatus},</if>
|
||||
<if test="record.remark != null">remark=#{record.remark},</if>
|
||||
update_by=#{record.updateBy}, update_time=NOW()
|
||||
</set>
|
||||
WHERE do_id=#{doId}
|
||||
WHERE do_id=#{record.doId}
|
||||
</update>
|
||||
|
||||
<select id="selectTransitStats" resultType="java.util.Map">
|
||||
@@ -84,16 +84,20 @@
|
||||
SUM(CASE WHEN DATEDIFF(delivery_date, CURDATE()) < 0 THEN 1 ELSE 0 END) AS overdue
|
||||
FROM biz_delivery_order
|
||||
WHERE delivery_status = 'transit'
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
</select>
|
||||
|
||||
<select id="selectCloseDateStats" resultType="java.util.Map">
|
||||
SELECT
|
||||
COUNT(*) AS pendingClose,
|
||||
(SELECT COUNT(*) FROM biz_delivery_order WHERE delivery_status='history'
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
) AS pendingClose,
|
||||
SUM(CASE WHEN actual_close_date = CURDATE() THEN 1 ELSE 0 END) AS todayClosed,
|
||||
SUM(CASE WHEN YEARWEEK(actual_close_date, 1) = YEARWEEK(CURDATE(), 1) THEN 1 ELSE 0 END) AS weekClosed,
|
||||
ROUND(AVG(DATEDIFF(actual_close_date, delivery_date)), 1) AS avgCycleDays
|
||||
FROM biz_delivery_order
|
||||
WHERE delivery_status = 'history'
|
||||
WHERE delivery_status = 'closed'
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
</select>
|
||||
|
||||
<select id="selectHistoryStats" resultType="java.util.Map">
|
||||
@@ -104,6 +108,8 @@
|
||||
ROUND(AVG(DATEDIFF(actual_close_date, delivery_date)), 1) AS avgDeliveryDays
|
||||
FROM biz_delivery_order
|
||||
WHERE delivery_status = 'history'
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
<if test="type != null and type != ''"> AND type=#{type}</if>
|
||||
</select>
|
||||
|
||||
<delete id="deleteBizDeliveryOrderById">DELETE FROM biz_delivery_order WHERE do_id=#{id}</delete>
|
||||
@@ -148,4 +154,34 @@
|
||||
WHERE di.material_id = #{materialId}
|
||||
ORDER BY d.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════
|
||||
履约时效可视化 - 时间线数据
|
||||
═══════════════════════════════════════════════ -->
|
||||
<select id="selectTimelineData" resultType="java.util.Map">
|
||||
SELECT
|
||||
d.do_id AS doId,
|
||||
d.do_no AS doNo,
|
||||
d.type,
|
||||
d.delivery_status AS deliveryStatus,
|
||||
d.delivery_date AS deliveryDate,
|
||||
d.delay_date AS delayDate,
|
||||
d.actual_close_date AS actualCloseDate,
|
||||
d.create_time AS createTime,
|
||||
d.total_amount AS totalAmount,
|
||||
COALESCE(s.supplier_name, cl.client_name) AS partyName,
|
||||
(SELECT COUNT(*) FROM biz_delivery_order_item WHERE do_id = d.do_id) AS itemCount
|
||||
FROM biz_delivery_order d
|
||||
LEFT JOIN biz_supplier s ON d.supplier_id = s.supplier_id
|
||||
LEFT JOIN biz_client_quote cq ON d.client_quote_id = cq.quote_id
|
||||
LEFT JOIN biz_client cl ON cq.client_id = cl.client_id
|
||||
<where>
|
||||
<if test="tenantId != null"> AND d.tenant_id = #{tenantId}</if>
|
||||
<if test="type != null and type != ''"> AND d.type = #{type}</if>
|
||||
<if test="status != null and status != ''"> AND d.delivery_status = #{status}</if>
|
||||
<if test="dateFrom != null and dateFrom != ''"> AND d.delivery_date >= #{dateFrom}</if>
|
||||
<if test="dateTo != null and dateTo != ''"> AND d.delivery_date <= #{dateTo}</if>
|
||||
</where>
|
||||
ORDER BY d.create_time DESC
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<id property="materialId" column="material_id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="categoryId" column="category_id"/>
|
||||
<result property="categoryName" column="category_name"/>
|
||||
<result property="materialCode" column="material_code"/>
|
||||
<result property="materialName" column="material_name"/>
|
||||
<result property="spec" column="spec"/>
|
||||
@@ -33,10 +34,10 @@
|
||||
m.category_id = #{categoryId}
|
||||
OR m.category_id IN (
|
||||
SELECT category_id FROM biz_material_category
|
||||
WHERE ancestors LIKE CONCAT(
|
||||
(SELECT ancestors FROM biz_material_category WHERE category_id = #{categoryId}),
|
||||
',%'
|
||||
)
|
||||
WHERE ancestors LIKE CONCAT('%,', #{categoryId}, ',%')
|
||||
OR ancestors LIKE CONCAT(#{categoryId}, ',%')
|
||||
OR ancestors LIKE CONCAT('%,', #{categoryId})
|
||||
OR ancestors = #{categoryId}
|
||||
)
|
||||
)</if>
|
||||
<if test="materialCode != null and materialCode != ''"> AND m.material_code LIKE CONCAT('%',#{materialCode},'%')</if>
|
||||
@@ -55,6 +56,11 @@
|
||||
WHERE m.material_id=#{id}
|
||||
</select>
|
||||
|
||||
<!-- 按物料编码查询(导入时判重用) -->
|
||||
<select id="selectBizMaterialByCode" resultMap="BaseRM">
|
||||
SELECT * FROM biz_material WHERE tenant_id=#{tenantId} AND material_code=#{materialCode} LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertBizMaterial" useGeneratedKeys="true" keyProperty="materialId">
|
||||
INSERT INTO biz_material(tenant_id,category_id,material_code,material_name,spec,unit,brand,
|
||||
description,status,performance_params,material,purpose,image_url,create_by,create_time)
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
<select id="selectBizSupplierById" resultMap="BaseRM">SELECT * FROM biz_supplier WHERE supplier_id=#{id}</select>
|
||||
|
||||
<!-- 按供应商名称查询(导入时判重用) -->
|
||||
<select id="selectBizSupplierByName" resultMap="BaseRM">
|
||||
SELECT * FROM biz_supplier WHERE tenant_id=#{tenantId} AND supplier_name=#{supplierName} LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectBizSupplierByUserId" resultMap="BaseRM">
|
||||
SELECT * FROM biz_supplier WHERE user_id = #{userId}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user