feat: 完成采购看板与异议管理模块功能升级
1. 新增报表下钻跳转支持,为供应商、RFQ、采购单、物料等页面添加路由参数解析 2. 优化异议管理模块:新增发货单关联、详情弹窗、审批流程优化 3. 完善采购看板功能:支持累计数据展示、图表导出、数据补全与趋势优化 4. 新增供应商评分历史趋势统计与品类分布聚合逻辑 5. 修复异议API路径与通知跳转路径问题,新增模拟测试数据
This commit is contained in:
@@ -7,6 +7,7 @@ public class BizOrderObjection {
|
||||
private Long objectionId;
|
||||
private Long tenantId;
|
||||
private Long poId;
|
||||
private Long doId;
|
||||
private Long supplierId;
|
||||
private String reason;
|
||||
private String attachment;
|
||||
@@ -19,6 +20,7 @@ public class BizOrderObjection {
|
||||
private Date resolveTime;
|
||||
private String supplierName;
|
||||
private String poNo;
|
||||
private String doNo;
|
||||
|
||||
public Long getObjectionId() { return objectionId; }
|
||||
public void setObjectionId(Long objectionId) { this.objectionId = objectionId; }
|
||||
@@ -26,6 +28,8 @@ public class BizOrderObjection {
|
||||
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
|
||||
public Long getPoId() { return poId; }
|
||||
public void setPoId(Long poId) { this.poId = poId; }
|
||||
public Long getDoId() { return doId; }
|
||||
public void setDoId(Long doId) { this.doId = doId; }
|
||||
public Long getSupplierId() { return supplierId; }
|
||||
public void setSupplierId(Long supplierId) { this.supplierId = supplierId; }
|
||||
public String getReason() { return reason; }
|
||||
@@ -46,4 +50,6 @@ public class BizOrderObjection {
|
||||
public void setSupplierName(String supplierName) { this.supplierName = supplierName; }
|
||||
public String getPoNo() { return poNo; }
|
||||
public void setPoNo(String poNo) { this.poNo = poNo; }
|
||||
public String getDoNo() { return doNo; }
|
||||
public void setDoNo(String doNo) { this.doNo = doNo; }
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public class ReportCostVO {
|
||||
private BigDecimal expectedAmount;
|
||||
private BigDecimal actualAmount;
|
||||
private BigDecimal savedAmount;
|
||||
private boolean overBudget;
|
||||
|
||||
public String getMonth() { return month; }
|
||||
public void setMonth(String v) { month = v; }
|
||||
@@ -68,15 +69,20 @@ public class ReportCostVO {
|
||||
public void setActualAmount(BigDecimal v) { actualAmount = v; }
|
||||
public BigDecimal getSavedAmount() { return savedAmount; }
|
||||
public void setSavedAmount(BigDecimal v) { savedAmount = v; }
|
||||
public boolean isOverBudget() { return overBudget; }
|
||||
public void setOverBudget(boolean v) { overBudget = v; }
|
||||
}
|
||||
|
||||
/** 品类分布 */
|
||||
public static class CategoryDist {
|
||||
private Long categoryId;
|
||||
private String categoryName;
|
||||
private BigDecimal amount;
|
||||
private int materialCount;
|
||||
private double percent;
|
||||
|
||||
public Long getCategoryId() { return categoryId; }
|
||||
public void setCategoryId(Long v) { categoryId = v; }
|
||||
public String getCategoryName() { return categoryName; }
|
||||
public void setCategoryName(String v) { categoryName = v; }
|
||||
public BigDecimal getAmount() { return amount; }
|
||||
@@ -97,6 +103,7 @@ public class ReportCostVO {
|
||||
private BigDecimal acceptedQuote;
|
||||
private BigDecimal savedAmount;
|
||||
private int supplierCount;
|
||||
private boolean overBudget;
|
||||
|
||||
public Long getRfqId() { return rfqId; }
|
||||
public void setRfqId(Long v) { rfqId = v; }
|
||||
@@ -114,5 +121,7 @@ public class ReportCostVO {
|
||||
public void setSavedAmount(BigDecimal v) { savedAmount = v; }
|
||||
public int getSupplierCount() { return supplierCount; }
|
||||
public void setSupplierCount(int v) { supplierCount = v; }
|
||||
public boolean isOverBudget() { return overBudget; }
|
||||
public void setOverBudget(boolean v) { overBudget = v; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ public class ReportDashboardVO {
|
||||
public static class KpiCard {
|
||||
private String label;
|
||||
private BigDecimal value;
|
||||
/** 累计值(全部历史数据汇总),用于当月为0时的补充展示 */
|
||||
private BigDecimal totalValue;
|
||||
private double changeRate;
|
||||
private String unit;
|
||||
private String trend; // up / down
|
||||
@@ -66,6 +68,8 @@ public class ReportDashboardVO {
|
||||
public void setLabel(String v) { label = v; }
|
||||
public BigDecimal getValue() { return value; }
|
||||
public void setValue(BigDecimal v) { value = v; }
|
||||
public BigDecimal getTotalValue() { return totalValue; }
|
||||
public void setTotalValue(BigDecimal v) { totalValue = v; }
|
||||
public double getChangeRate() { return changeRate; }
|
||||
public void setChangeRate(double v) { changeRate = v; }
|
||||
public String getUnit() { return unit; }
|
||||
|
||||
@@ -20,6 +20,9 @@ public class ReportSupplierVO {
|
||||
/** 异议统计 */
|
||||
private List<ObjectionStat> objectionStats;
|
||||
|
||||
/** 评分历史趋势 */
|
||||
private List<ScoreHistory> scoreHistory;
|
||||
|
||||
// ===== getters / setters =====
|
||||
|
||||
public List<SupplierScore> getRankings() { return rankings; }
|
||||
@@ -34,6 +37,9 @@ public class ReportSupplierVO {
|
||||
public List<ObjectionStat> getObjectionStats() { return objectionStats; }
|
||||
public void setObjectionStats(List<ObjectionStat> v) { objectionStats = v; }
|
||||
|
||||
public List<ScoreHistory> getScoreHistory() { return scoreHistory; }
|
||||
public void setScoreHistory(List<ScoreHistory> v) { scoreHistory = v; }
|
||||
|
||||
// ===== 内部类 =====
|
||||
|
||||
/** 供应商评分 */
|
||||
@@ -41,6 +47,7 @@ public class ReportSupplierVO {
|
||||
private Long supplierId;
|
||||
private String supplierName;
|
||||
private int evalCount;
|
||||
private String evalStatus;
|
||||
private double qualityAvg;
|
||||
private double deliveryAvg;
|
||||
private double serviceAvg;
|
||||
@@ -55,6 +62,8 @@ public class ReportSupplierVO {
|
||||
public void setSupplierName(String v) { supplierName = v; }
|
||||
public int getEvalCount() { return evalCount; }
|
||||
public void setEvalCount(int v) { evalCount = v; }
|
||||
public String getEvalStatus() { return evalStatus; }
|
||||
public void setEvalStatus(String v) { evalStatus = v; }
|
||||
public double getQualityAvg() { return qualityAvg; }
|
||||
public void setQualityAvg(double v) { qualityAvg = v; }
|
||||
public double getDeliveryAvg() { return deliveryAvg; }
|
||||
@@ -130,4 +139,30 @@ public class ReportSupplierVO {
|
||||
public String getTopReason() { return topReason; }
|
||||
public void setTopReason(String v) { topReason = v; }
|
||||
}
|
||||
|
||||
/** 评分历史趋势 */
|
||||
public static class ScoreHistory {
|
||||
private Long supplierId;
|
||||
private String supplierName;
|
||||
private String month;
|
||||
private double qualityAvg;
|
||||
private double deliveryAvg;
|
||||
private double serviceAvg;
|
||||
private double priceAvg;
|
||||
|
||||
public Long getSupplierId() { return supplierId; }
|
||||
public void setSupplierId(Long v) { supplierId = v; }
|
||||
public String getSupplierName() { return supplierName; }
|
||||
public void setSupplierName(String v) { supplierName = v; }
|
||||
public String getMonth() { return month; }
|
||||
public void setMonth(String v) { month = v; }
|
||||
public double getQualityAvg() { return qualityAvg; }
|
||||
public void setQualityAvg(double v) { qualityAvg = v; }
|
||||
public double getDeliveryAvg() { return deliveryAvg; }
|
||||
public void setDeliveryAvg(double v) { deliveryAvg = v; }
|
||||
public double getServiceAvg() { return serviceAvg; }
|
||||
public void setServiceAvg(double v) { serviceAvg = v; }
|
||||
public double getPriceAvg() { return priceAvg; }
|
||||
public void setPriceAvg(double v) { priceAvg = v; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,18 @@ public interface BizReportMapper {
|
||||
/** 本月/上月采购总额 */
|
||||
Map<String, Object> selectPurchaseAmount(@Param("month") String month);
|
||||
|
||||
/** 累计采购总额(不限月份) */
|
||||
Map<String, Object> selectPurchaseAmountAll();
|
||||
|
||||
/** 本月/上月 RFQ 数量 */
|
||||
Map<String, Object> selectRfqCount(@Param("month") String month);
|
||||
|
||||
/** 本月/上月 PO 数量 */
|
||||
Map<String, Object> selectPoCount(@Param("month") String month);
|
||||
|
||||
/** 累计采购单数(不限月份) */
|
||||
Map<String, Object> selectPoCountAll();
|
||||
|
||||
/** 活跃供应商数 */
|
||||
Map<String, Object> selectActiveSupplierCount();
|
||||
|
||||
@@ -70,4 +76,7 @@ public interface BizReportMapper {
|
||||
|
||||
/** 异议统计 */
|
||||
List<ReportSupplierVO.ObjectionStat> selectObjectionStats();
|
||||
|
||||
/** 供应商评分历史趋势 */
|
||||
List<ReportSupplierVO.ScoreHistory> selectSupplierScoreHistory();
|
||||
}
|
||||
|
||||
@@ -168,6 +168,14 @@ public class BizApprovalActionServiceImpl implements IBizApprovalActionService {
|
||||
sb.append(";驳回原因: ").append(reason);
|
||||
}
|
||||
|
||||
// 订单异议额外显示处理结果
|
||||
if ("ORDER_OBJECTION".equals(bizType) && detail.get("resolution") != null) {
|
||||
String resolution = String.valueOf(detail.get("resolution")).trim();
|
||||
if (!resolution.isEmpty()) {
|
||||
sb.append(";处理结果: ").append(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -203,6 +211,15 @@ public class BizApprovalActionServiceImpl implements IBizApprovalActionService {
|
||||
}
|
||||
|
||||
sb.append("提交人: ").append(submitterName);
|
||||
|
||||
// 订单异议额外显示处理结果
|
||||
if ("ORDER_OBJECTION".equals(bizType) && detail.get("resolution") != null) {
|
||||
String resolution = String.valueOf(detail.get("resolution")).trim();
|
||||
if (!resolution.isEmpty()) {
|
||||
sb.append(";处理结果: ").append(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -286,10 +303,10 @@ public class BizApprovalActionServiceImpl implements IBizApprovalActionService {
|
||||
if (bizType == null || bizId == null) return null;
|
||||
switch (bizType) {
|
||||
case "PURCHASE_ORDER": return "/quote/purchaseorder?id=" + bizId;
|
||||
case "CLIENT_QUOTE": return "/bid/clientquote/detail?id=" + bizId;
|
||||
case "CLIENT_QUOTE": return "/bid/clientquote?id=" + bizId;
|
||||
case "QUOTATION": return "/quote/quotation?quotationId=" + bizId;
|
||||
case "DELIVERY_ORDER": return "/bid/order/pending?id=" + bizId;
|
||||
case "ORDER_OBJECTION": return "/bid/order/objection?id=" + bizId;
|
||||
case "DELIVERY_ORDER": return "/fulfill/client-delivery/pending?id=" + bizId;
|
||||
case "ORDER_OBJECTION": return "/fulfill/supplierFulfill/objection?id=" + bizId;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,10 +145,10 @@ public class BizNotifyMessageServiceImpl implements IBizNotifyMessageService {
|
||||
if (bizType == null || bizId == null) return null;
|
||||
switch (bizType) {
|
||||
case "PURCHASE_ORDER": return "/quote/purchaseorder?id=" + bizId;
|
||||
case "CLIENT_QUOTE": return "/bid/clientquote/detail?id=" + bizId;
|
||||
case "CLIENT_QUOTE": return "/bid/clientquote?id=" + bizId;
|
||||
case "QUOTATION": return "/quote/quotation?quotationId=" + bizId;
|
||||
case "DELIVERY_ORDER": return "/bid/order/pending?id=" + bizId;
|
||||
case "ORDER_OBJECTION": return "/bid/order/objection?id=" + bizId;
|
||||
case "DELIVERY_ORDER": return "/fulfill/client-delivery/pending?id=" + bizId;
|
||||
case "ORDER_OBJECTION": return "/fulfill/supplierFulfill/objection?id=" + bizId;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 报表统计 Service 实现
|
||||
@@ -35,25 +36,34 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
String curMonth = LocalDate.now().format(MONTH_FMT);
|
||||
String lastMonth = LocalDate.now().minusMonths(1).format(MONTH_FMT);
|
||||
|
||||
// 累计值(全部历史数据)
|
||||
BigDecimal totalPurchaseAll = selectAmount("totalAmount", null, true);
|
||||
BigDecimal totalPoAll = selectCount("po", null, true);
|
||||
|
||||
// 1) KPI 卡片
|
||||
vo.setTotalPurchaseAmount(buildKpi("采购总额",
|
||||
ReportDashboardVO.KpiCard purchaseCard = buildKpi("采购总额",
|
||||
selectAmount("totalAmount", curMonth),
|
||||
selectAmount("totalAmount", lastMonth), "元"));
|
||||
selectAmount("totalAmount", lastMonth), "元");
|
||||
purchaseCard.setTotalValue(totalPurchaseAll);
|
||||
vo.setTotalPurchaseAmount(purchaseCard);
|
||||
|
||||
vo.setTotalRfqCount(buildKpi("RFQ总数",
|
||||
selectCount("rfq", curMonth),
|
||||
selectCount("rfq", lastMonth), "单"));
|
||||
|
||||
vo.setTotalPoCount(buildKpi("采购单数",
|
||||
ReportDashboardVO.KpiCard poCard = buildKpi("采购单数",
|
||||
selectCount("po", curMonth),
|
||||
selectCount("po", lastMonth), "单"));
|
||||
selectCount("po", lastMonth), "单");
|
||||
poCard.setTotalValue(totalPoAll);
|
||||
vo.setTotalPoCount(poCard);
|
||||
|
||||
Map<String, Object> act = mapper.selectActiveSupplierCount();
|
||||
BigDecimal activeVal = toBD(act.get("totalCount"));
|
||||
vo.setActiveSupplierCount(buildKpi("活跃供应商", activeVal, null, "家"));
|
||||
|
||||
// 2) 月度趋势
|
||||
vo.setMonthlyTrend(mapper.selectMonthlyTrend());
|
||||
// 2) 月度趋势(补全近12个月,无数据月份填0)
|
||||
List<ReportDashboardVO.MonthTrend> rawTrend = mapper.selectMonthlyTrend();
|
||||
vo.setMonthlyTrend(fillMonthlyTrend(rawTrend, 12));
|
||||
|
||||
// 3) RFQ 状态分布
|
||||
List<ReportDashboardVO.StatusDist> dist = mapper.selectRfqStatusDist();
|
||||
@@ -91,8 +101,9 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
: 0);
|
||||
vo.setSummary(summary);
|
||||
|
||||
// 月度趋势
|
||||
vo.setCostTrend(mapper.selectCostTrend(startMonth, endMonth));
|
||||
// 月度趋势(补全月份,无数据月份填0)
|
||||
List<ReportCostVO.CostTrend> rawTrend = mapper.selectCostTrend(startMonth, endMonth);
|
||||
vo.setCostTrend(fillCostTrend(rawTrend, startMonth, endMonth));
|
||||
|
||||
// 品类分布
|
||||
List<ReportCostVO.CategoryDist> catDist = mapper.selectCategoryDist();
|
||||
@@ -108,7 +119,15 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
vo.setCategoryDist(catDist);
|
||||
|
||||
// RFQ 比价明细
|
||||
vo.setRfqDetails(mapper.selectRfqCompareDetails());
|
||||
List<ReportCostVO.RfqCompareDetail> details = mapper.selectRfqCompareDetails();
|
||||
if (details != null) {
|
||||
for (ReportCostVO.RfqCompareDetail d : details) {
|
||||
if (d.getSavedAmount() != null && d.getSavedAmount().compareTo(BigDecimal.ZERO) < 0) {
|
||||
d.setOverBudget(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
vo.setRfqDetails(details);
|
||||
|
||||
return vo;
|
||||
}
|
||||
@@ -121,6 +140,7 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
vo.setWinRateData(mapper.selectWinRate());
|
||||
vo.setRadarData(mapper.selectRadarData());
|
||||
vo.setObjectionStats(mapper.selectObjectionStats());
|
||||
vo.setScoreHistory(mapper.selectSupplierScoreHistory());
|
||||
|
||||
return vo;
|
||||
}
|
||||
@@ -149,15 +169,36 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
}
|
||||
|
||||
private BigDecimal selectAmount(String column, String month) {
|
||||
Map<String, Object> map = mapper.selectPurchaseAmount(month);
|
||||
return selectAmount(column, month, false);
|
||||
}
|
||||
|
||||
private BigDecimal selectAmount(String column, String month, boolean all) {
|
||||
Map<String, Object> map;
|
||||
if (all) {
|
||||
map = mapper.selectPurchaseAmountAll();
|
||||
} else {
|
||||
map = mapper.selectPurchaseAmount(month);
|
||||
}
|
||||
return toBD(map.get(column));
|
||||
}
|
||||
|
||||
private BigDecimal selectCount(String type, String month) {
|
||||
return selectCount(type, month, false);
|
||||
}
|
||||
|
||||
private BigDecimal selectCount(String type, String month, boolean all) {
|
||||
Map<String, Object> map;
|
||||
switch (type) {
|
||||
case "rfq": map = mapper.selectRfqCount(month); break;
|
||||
case "po": map = mapper.selectPoCount(month); break;
|
||||
case "rfq":
|
||||
if (all) return BigDecimal.ZERO; // RFQ无累计需求
|
||||
map = mapper.selectRfqCount(month); break;
|
||||
case "po":
|
||||
if (all) {
|
||||
map = mapper.selectPoCountAll();
|
||||
} else {
|
||||
map = mapper.selectPoCount(month);
|
||||
}
|
||||
break;
|
||||
default: return BigDecimal.ZERO;
|
||||
}
|
||||
return toBD(map.get("totalCount"));
|
||||
@@ -169,4 +210,100 @@ public class BizReportServiceImpl implements IBizReportService {
|
||||
if (v instanceof Number) return BigDecimal.valueOf(((Number) v).doubleValue());
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 补全月度采购趋势 — 生成近N个月的完整月份列表,无数据月份填0
|
||||
* 解决趋势图断层问题
|
||||
*/
|
||||
private List<ReportDashboardVO.MonthTrend> fillMonthlyTrend(List<ReportDashboardVO.MonthTrend> raw, int months) {
|
||||
// 生成近N个月份列表(从最早到当前月)
|
||||
List<String> allMonths = new ArrayList<>();
|
||||
LocalDate now = LocalDate.now();
|
||||
for (int i = months - 1; i >= 0; i--) {
|
||||
allMonths.add(now.minusMonths(i).format(MONTH_FMT));
|
||||
}
|
||||
|
||||
// 将原始数据转为Map便于查找
|
||||
Map<String, ReportDashboardVO.MonthTrend> rawMap = new LinkedHashMap<>();
|
||||
if (raw != null) {
|
||||
for (ReportDashboardVO.MonthTrend t : raw) {
|
||||
if (t.getMonth() != null) {
|
||||
rawMap.put(t.getMonth(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按完整月份列表补全
|
||||
List<ReportDashboardVO.MonthTrend> result = new ArrayList<>();
|
||||
for (String m : allMonths) {
|
||||
ReportDashboardVO.MonthTrend t = rawMap.get(m);
|
||||
if (t == null) {
|
||||
t = new ReportDashboardVO.MonthTrend();
|
||||
t.setMonth(m);
|
||||
t.setAmount(BigDecimal.ZERO);
|
||||
t.setCount(0);
|
||||
}
|
||||
result.add(t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 补全成本趋势 — 生成完整月份列表,无数据月份填0
|
||||
* 解决成本趋势图断层问题
|
||||
*/
|
||||
private List<ReportCostVO.CostTrend> fillCostTrend(List<ReportCostVO.CostTrend> raw, String startMonth, String endMonth) {
|
||||
// 确定起止月份
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalDate start;
|
||||
LocalDate end;
|
||||
|
||||
if (startMonth != null && !startMonth.isEmpty()) {
|
||||
start = LocalDate.parse(startMonth + "-01");
|
||||
} else {
|
||||
start = now.minusMonths(11); // 默认近12个月
|
||||
}
|
||||
if (endMonth != null && !endMonth.isEmpty()) {
|
||||
end = LocalDate.parse(endMonth + "-01");
|
||||
} else {
|
||||
end = now;
|
||||
}
|
||||
|
||||
// 生成完整月份列表
|
||||
List<String> allMonths = new ArrayList<>();
|
||||
LocalDate cur = start.withDayOfMonth(1);
|
||||
while (!cur.isAfter(end)) {
|
||||
allMonths.add(cur.format(MONTH_FMT));
|
||||
cur = cur.plusMonths(1);
|
||||
}
|
||||
|
||||
// 将原始数据转为Map
|
||||
Map<String, ReportCostVO.CostTrend> rawMap = new LinkedHashMap<>();
|
||||
if (raw != null) {
|
||||
for (ReportCostVO.CostTrend t : raw) {
|
||||
if (t.getMonth() != null) {
|
||||
rawMap.put(t.getMonth(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 补全
|
||||
List<ReportCostVO.CostTrend> result = new ArrayList<>();
|
||||
for (String m : allMonths) {
|
||||
ReportCostVO.CostTrend t = rawMap.get(m);
|
||||
if (t == null) {
|
||||
t = new ReportCostVO.CostTrend();
|
||||
t.setMonth(m);
|
||||
t.setExpectedAmount(BigDecimal.ZERO);
|
||||
t.setActualAmount(BigDecimal.ZERO);
|
||||
t.setSavedAmount(BigDecimal.ZERO);
|
||||
}
|
||||
// 设置超支标识:节省金额为负表示实际超预算
|
||||
if (t.getSavedAmount() != null && t.getSavedAmount().compareTo(BigDecimal.ZERO) < 0) {
|
||||
t.setOverBudget(true);
|
||||
}
|
||||
result.add(t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +64,14 @@
|
||||
|
||||
<!-- 查询订单异议详情 -->
|
||||
<select id="selectObjectionInfo" resultType="java.util.Map">
|
||||
SELECT o.reason AS bizTitle, s.supplier_name AS partnerName, p.po_no AS bizNo,
|
||||
SELECT o.reason AS bizTitle, s.supplier_name AS partnerName,
|
||||
COALESCE(d.do_no, p.po_no) AS bizNo,
|
||||
o.resolution AS resolution, o.status AS status,
|
||||
o.create_time AS createTime, o.create_by AS createBy
|
||||
FROM biz_order_objection o
|
||||
LEFT JOIN biz_supplier s ON o.supplier_id = s.supplier_id
|
||||
LEFT JOIN biz_purchase_order p ON o.po_id = p.po_id
|
||||
LEFT JOIN biz_delivery_order d ON o.do_id = d.do_id
|
||||
WHERE o.objection_id = #{id}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<id property="objectionId" column="objection_id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="poId" column="po_id"/>
|
||||
<result property="doId" column="do_id"/>
|
||||
<result property="supplierId" column="supplier_id"/>
|
||||
<result property="reason" column="reason"/>
|
||||
<result property="attachment" column="attachment"/>
|
||||
@@ -15,13 +16,15 @@
|
||||
<result property="resolveTime" column="resolve_time"/>
|
||||
<result property="supplierName" column="supplier_name"/>
|
||||
<result property="poNo" column="po_no"/>
|
||||
<result property="doNo" column="do_no"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectBizOrderObjectionList" resultMap="BaseRM">
|
||||
SELECT o.*, s.supplier_name, p.po_no
|
||||
SELECT o.*, s.supplier_name, p.po_no, d.do_no
|
||||
FROM biz_order_objection o
|
||||
LEFT JOIN biz_supplier s ON o.supplier_id=s.supplier_id
|
||||
LEFT JOIN biz_purchase_order p ON o.po_id=p.po_id
|
||||
LEFT JOIN biz_delivery_order d ON o.do_id=d.do_id
|
||||
<where>
|
||||
<if test="tenantId != null"> AND o.tenant_id=#{tenantId}</if>
|
||||
<if test="status != null and status != ''"> AND o.status=#{status}</if>
|
||||
@@ -30,15 +33,16 @@
|
||||
</select>
|
||||
|
||||
<select id="selectBizOrderObjectionById" resultMap="BaseRM">
|
||||
SELECT o.*, s.supplier_name, p.po_no FROM biz_order_objection o
|
||||
SELECT o.*, s.supplier_name, p.po_no, d.do_no FROM biz_order_objection o
|
||||
LEFT JOIN biz_supplier s ON o.supplier_id=s.supplier_id
|
||||
LEFT JOIN biz_purchase_order p ON o.po_id=p.po_id
|
||||
LEFT JOIN biz_delivery_order d ON o.do_id=d.do_id
|
||||
WHERE o.objection_id=#{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertBizOrderObjection" useGeneratedKeys="true" keyProperty="objectionId">
|
||||
INSERT INTO biz_order_objection(tenant_id,po_id,supplier_id,reason,attachment,status,create_by,create_time)
|
||||
VALUES(#{tenantId},#{poId},#{supplierId},#{reason},#{attachment},'pending',#{createBy},NOW())
|
||||
INSERT INTO biz_order_objection(tenant_id,po_id,do_id,supplier_id,reason,attachment,status,create_by,create_time)
|
||||
VALUES(#{tenantId},#{poId},#{doId},#{supplierId},#{reason},#{attachment},'pending',#{createBy},NOW())
|
||||
</insert>
|
||||
|
||||
<update id="updateBizOrderObjection">
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 累计采购总额(不限月份) -->
|
||||
<select id="selectPurchaseAmountAll" resultType="java.util.HashMap">
|
||||
SELECT COALESCE(SUM(total_amount), 0) AS totalAmount
|
||||
FROM biz_purchase_order
|
||||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||||
</select>
|
||||
|
||||
<!-- 指定月份 RFQ 数量 -->
|
||||
<select id="selectRfqCount" resultType="java.util.HashMap">
|
||||
SELECT COUNT(*) AS totalCount
|
||||
@@ -36,6 +43,13 @@
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 累计采购单数(不限月份) -->
|
||||
<select id="selectPoCountAll" resultType="java.util.HashMap">
|
||||
SELECT COUNT(*) AS totalCount
|
||||
FROM biz_purchase_order
|
||||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||||
</select>
|
||||
|
||||
<!-- 活跃供应商数(有过报价或采购的) -->
|
||||
<select id="selectActiveSupplierCount" resultType="java.util.HashMap">
|
||||
SELECT COUNT(DISTINCT supplier_id) AS totalCount
|
||||
@@ -180,17 +194,26 @@
|
||||
ORDER BY t.month ASC
|
||||
</select>
|
||||
|
||||
<!-- 品类采购分布 -->
|
||||
<!-- 品类采购分布(按一级分类聚合) -->
|
||||
<select id="selectCategoryDist" resultType="com.ruoyi.system.domain.bid.ReportCostVO$CategoryDist">
|
||||
SELECT COALESCE(c.category_name, '未分类') AS categoryName,
|
||||
COALESCE(SUM(pi.total_price), 0) AS amount,
|
||||
COUNT(DISTINCT pi.material_id) AS materialCount
|
||||
SELECT
|
||||
COALESCE(top_cat.category_id, 0) AS categoryId,
|
||||
COALESCE(top_cat.category_name, '未分类') AS categoryName,
|
||||
COALESCE(SUM(pi.total_price), 0) AS amount,
|
||||
COUNT(DISTINCT pi.material_id) AS materialCount
|
||||
FROM biz_purchase_order_item pi
|
||||
JOIN biz_purchase_order p ON pi.po_id = p.po_id
|
||||
LEFT JOIN biz_material m ON pi.material_id = m.material_id
|
||||
LEFT JOIN biz_material_category c ON m.category_id = c.category_id
|
||||
<!-- 通过ancestors字段找到顶级分类(parent_id=0的一级分类) -->
|
||||
LEFT JOIN biz_material_category top_cat ON top_cat.category_id =
|
||||
CASE
|
||||
WHEN c.ancestors = '0' THEN c.category_id
|
||||
WHEN c.ancestors IS NULL THEN NULL
|
||||
ELSE CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(c.ancestors, ',', 2), ',', -1) AS UNSIGNED)
|
||||
END
|
||||
WHERE p.status IN ('confirmed', 'closed', 'delivered')
|
||||
GROUP BY c.category_name
|
||||
GROUP BY top_cat.category_id, top_cat.category_name
|
||||
ORDER BY amount DESC
|
||||
</select>
|
||||
|
||||
@@ -249,6 +272,7 @@
|
||||
s.supplier_id AS supplierId,
|
||||
s.supplier_name AS supplierName,
|
||||
COALESCE(e.evalCount, 0) AS evalCount,
|
||||
CASE WHEN COALESCE(e.evalCount, 0) > 0 THEN 'evaluated' ELSE 'not_evaluated' END AS evalStatus,
|
||||
COALESCE(e.qualityAvg, 0) AS qualityAvg,
|
||||
COALESCE(e.deliveryAvg, 0) AS deliveryAvg,
|
||||
COALESCE(e.serviceAvg, 0) AS serviceAvg,
|
||||
@@ -276,7 +300,7 @@
|
||||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||||
GROUP BY supplier_id
|
||||
) po ON s.supplier_id = po.supplier_id
|
||||
ORDER BY totalAvg DESC
|
||||
ORDER BY CASE WHEN COALESCE(e.evalCount, 0) > 0 THEN 0 ELSE 1 END, totalAvg DESC
|
||||
</select>
|
||||
|
||||
<!-- 中标率 -->
|
||||
@@ -294,7 +318,7 @@
|
||||
ORDER BY winRate DESC
|
||||
</select>
|
||||
|
||||
<!-- 雷达图数据 -->
|
||||
<!-- 雷达图数据(仅含有评价数据的供应商) -->
|
||||
<select id="selectRadarData" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$RadarData">
|
||||
SELECT
|
||||
s.supplier_name AS supplierName,
|
||||
@@ -303,7 +327,7 @@
|
||||
COALESCE(AVG(e.service_score), 0) AS service,
|
||||
COALESCE(AVG(e.price_score), 0) AS price
|
||||
FROM biz_supplier s
|
||||
LEFT JOIN biz_supplier_evaluation e ON s.supplier_id = e.supplier_id
|
||||
INNER JOIN biz_supplier_evaluation e ON s.supplier_id = e.supplier_id
|
||||
GROUP BY s.supplier_id, s.supplier_name
|
||||
ORDER BY s.supplier_id
|
||||
</select>
|
||||
@@ -322,4 +346,20 @@
|
||||
ORDER BY objectionCount DESC
|
||||
</select>
|
||||
|
||||
<!-- 供应商评分历史趋势(按月) -->
|
||||
<select id="selectSupplierScoreHistory" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$ScoreHistory">
|
||||
SELECT
|
||||
e.supplier_id AS supplierId,
|
||||
s.supplier_name AS supplierName,
|
||||
DATE_FORMAT(e.eval_time, '%Y-%m') AS month,
|
||||
AVG(e.quality_score) AS qualityAvg,
|
||||
AVG(e.delivery_score) AS deliveryAvg,
|
||||
AVG(e.service_score) AS serviceAvg,
|
||||
AVG(e.price_score) AS priceAvg
|
||||
FROM biz_supplier_evaluation e
|
||||
JOIN biz_supplier s ON e.supplier_id = s.supplier_id
|
||||
GROUP BY e.supplier_id, s.supplier_name, DATE_FORMAT(e.eval_time, '%Y-%m')
|
||||
ORDER BY e.supplier_id, month
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user