本次提交新增了完整的投标报表统计分析功能,包括: 添加用于数据检查与菜单初始化的 SQL 脚本 实现采购概览仪表板、采购成本分析及供应商绩效报告的后端服务、Mapper、Controller 及 VO 类 添加前端 API、路由配置以及使用 ECharts 可视化图表的页面组件 为仪表板添加通用的 KPI 卡片组件
326 lines
14 KiB
XML
326 lines
14 KiB
XML
<?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.ruoyi.system.mapper.bid.BizReportMapper">
|
||
|
||
<!-- ================================================================ -->
|
||
<!-- 采 购 总 览 看 板 -->
|
||
<!-- ================================================================ -->
|
||
|
||
<!-- 指定月份采购总额 -->
|
||
<select id="selectPurchaseAmount" resultType="java.util.HashMap">
|
||
SELECT COALESCE(SUM(total_amount), 0) AS totalAmount
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
<if test="month != null and month != ''">
|
||
AND DATE_FORMAT(create_time, '%Y-%m') = #{month}
|
||
</if>
|
||
</select>
|
||
|
||
<!-- 指定月份 RFQ 数量 -->
|
||
<select id="selectRfqCount" resultType="java.util.HashMap">
|
||
SELECT COUNT(*) AS totalCount
|
||
FROM biz_rfq
|
||
WHERE 1=1
|
||
<if test="month != null and month != ''">
|
||
AND DATE_FORMAT(create_time, '%Y-%m') = #{month}
|
||
</if>
|
||
</select>
|
||
|
||
<!-- 指定月份 PO 数量 -->
|
||
<select id="selectPoCount" resultType="java.util.HashMap">
|
||
SELECT COUNT(*) AS totalCount
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
<if test="month != null and month != ''">
|
||
AND DATE_FORMAT(create_time, '%Y-%m') = #{month}
|
||
</if>
|
||
</select>
|
||
|
||
<!-- 活跃供应商数(有过报价或采购的) -->
|
||
<select id="selectActiveSupplierCount" resultType="java.util.HashMap">
|
||
SELECT COUNT(DISTINCT supplier_id) AS totalCount
|
||
FROM (
|
||
SELECT supplier_id FROM biz_quotation WHERE status IN ('submitted', 'accepted')
|
||
UNION
|
||
SELECT supplier_id FROM biz_purchase_order
|
||
) t
|
||
</select>
|
||
|
||
<!-- 月度采购趋势 -->
|
||
<select id="selectMonthlyTrend" resultType="com.ruoyi.system.domain.bid.ReportDashboardVO$MonthTrend">
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m') AS month,
|
||
COALESCE(SUM(total_amount), 0) AS amount,
|
||
COUNT(*) AS count
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
|
||
GROUP BY DATE_FORMAT(create_time, '%Y-%m')
|
||
ORDER BY month ASC
|
||
</select>
|
||
|
||
<!-- RFQ 状态分布 -->
|
||
<select id="selectRfqStatusDist" resultType="com.ruoyi.system.domain.bid.ReportDashboardVO$StatusDist">
|
||
SELECT status,
|
||
CASE status
|
||
WHEN 'draft' THEN '草稿'
|
||
WHEN 'published' THEN '已发布'
|
||
WHEN 'completed' THEN '已完成'
|
||
WHEN 'cancelled' THEN '已取消'
|
||
ELSE status
|
||
END AS statusLabel,
|
||
COUNT(*) AS count,
|
||
ROUND(COUNT(*) / (SELECT COUNT(*) FROM biz_rfq) * 100, 1) AS percent
|
||
FROM biz_rfq
|
||
GROUP BY status
|
||
</select>
|
||
|
||
<!-- Top 供应商排名 -->
|
||
<select id="selectTopSuppliers" resultType="com.ruoyi.system.domain.bid.ReportDashboardVO$SupplierRank">
|
||
SELECT p.supplier_id AS supplierId,
|
||
s.supplier_name AS supplierName,
|
||
COALESCE(SUM(p.total_amount), 0) AS totalAmount,
|
||
COUNT(*) AS poCount,
|
||
COALESCE(AVG(e.total_score), 0) AS avgScore
|
||
FROM biz_purchase_order p
|
||
LEFT JOIN biz_supplier s ON p.supplier_id = s.supplier_id
|
||
LEFT JOIN biz_supplier_evaluation e ON p.po_id = e.po_id
|
||
WHERE p.status IN ('confirmed', 'closed', 'delivered')
|
||
GROUP BY p.supplier_id, s.supplier_name
|
||
ORDER BY totalAmount DESC
|
||
LIMIT 5
|
||
</select>
|
||
|
||
<!-- 最近动态 -->
|
||
<select id="selectRecentActivities" resultType="com.ruoyi.system.domain.bid.ReportDashboardVO$RecentActivity">
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:%i') AS time,
|
||
'PO' AS type,
|
||
CONCAT('创建采购单 ', po_no, '(¥', total_amount, ')') AS `desc`,
|
||
po_id AS linkId
|
||
FROM biz_purchase_order
|
||
UNION ALL
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:%i') AS time,
|
||
'QUOTE' AS type,
|
||
CONCAT('供应商报价 ', quote_no, '(¥', total_amount, ')') AS `desc`,
|
||
quotation_id AS linkId
|
||
FROM biz_quotation
|
||
WHERE status IN ('submitted', 'accepted')
|
||
UNION ALL
|
||
SELECT DATE_FORMAT(eval_time, '%Y-%m-%d %H:%i') AS time,
|
||
'EVAL' AS type,
|
||
CONCAT('评价供应商:', s.supplier_name, '(', e.total_score, '分)') AS `desc`,
|
||
e.eval_id AS linkId
|
||
FROM biz_supplier_evaluation e
|
||
LEFT JOIN biz_supplier s ON e.supplier_id = s.supplier_id
|
||
UNION ALL
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:%i') AS time,
|
||
'OBJECTION' AS type,
|
||
CONCAT('订单异议:', LEFT(o.reason, 30)) AS `desc`,
|
||
o.objection_id AS linkId
|
||
FROM biz_order_objection o
|
||
ORDER BY time DESC
|
||
LIMIT 10
|
||
</select>
|
||
|
||
<!-- ================================================================ -->
|
||
<!-- 采 购 成 本 分 析 -->
|
||
<!-- ================================================================ -->
|
||
|
||
<!-- 预算总额 -->
|
||
<select id="selectTotalExpected" resultType="java.util.HashMap">
|
||
SELECT COALESCE(SUM(ri.quantity * ri.expected_price), 0) AS totalExpected
|
||
FROM biz_rfq r
|
||
JOIN biz_rfq_item ri ON r.rfq_id = ri.rfq_id
|
||
WHERE r.status = 'completed'
|
||
</select>
|
||
|
||
<!-- 实际采购总额 -->
|
||
<select id="selectTotalActual" resultType="java.util.HashMap">
|
||
SELECT COALESCE(SUM(total_amount), 0) AS totalActual
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
</select>
|
||
|
||
<!-- 月度成本趋势 -->
|
||
<select id="selectCostTrend" resultType="com.ruoyi.system.domain.bid.ReportCostVO$CostTrend">
|
||
SELECT
|
||
t.month,
|
||
COALESCE(e.expectedAmount, 0) AS expectedAmount,
|
||
COALESCE(a.actualAmount, 0) AS actualAmount,
|
||
COALESCE(e.expectedAmount, 0) - COALESCE(a.actualAmount, 0) AS savedAmount
|
||
FROM (
|
||
SELECT DISTINCT DATE_FORMAT(create_time, '%Y-%m') AS month
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
UNION
|
||
SELECT DISTINCT DATE_FORMAT(create_time, '%Y-%m') FROM biz_rfq
|
||
) t
|
||
LEFT JOIN (
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m') AS month,
|
||
SUM(ri.quantity * ri.expected_price) AS expectedAmount
|
||
FROM biz_rfq r
|
||
JOIN biz_rfq_item ri ON r.rfq_id = ri.rfq_id
|
||
WHERE r.status = 'completed'
|
||
GROUP BY DATE_FORMAT(create_time, '%Y-%m')
|
||
) e ON t.month = e.month
|
||
LEFT JOIN (
|
||
SELECT DATE_FORMAT(create_time, '%Y-%m') AS month,
|
||
SUM(total_amount) AS actualAmount
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
GROUP BY DATE_FORMAT(create_time, '%Y-%m')
|
||
) a ON t.month = a.month
|
||
<where>
|
||
<if test="startMonth != null and startMonth != ''">
|
||
AND t.month >= #{startMonth}
|
||
</if>
|
||
<if test="endMonth != null and endMonth != ''">
|
||
AND t.month <= #{endMonth}
|
||
</if>
|
||
</where>
|
||
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
|
||
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
|
||
WHERE p.status IN ('confirmed', 'closed', 'delivered')
|
||
GROUP BY c.category_name
|
||
ORDER BY amount DESC
|
||
</select>
|
||
|
||
<!-- RFQ 比价明细 -->
|
||
<select id="selectRfqCompareDetails" resultType="com.ruoyi.system.domain.bid.ReportCostVO$RfqCompareDetail">
|
||
SELECT
|
||
r.rfq_id AS rfqId,
|
||
r.rfq_no AS rfqNo,
|
||
r.rfq_title AS rfqTitle,
|
||
ri.expectedTotal,
|
||
COALESCE(lowest.lowestQuote, 0) AS lowestQuote,
|
||
COALESCE(accepted.acceptedQuote, 0) AS acceptedQuote,
|
||
ri.expectedTotal - COALESCE(accepted.acceptedQuote, 0) AS savedAmount,
|
||
COALESCE(sup.supplierCount, 0) AS supplierCount
|
||
FROM biz_rfq r
|
||
JOIN (
|
||
SELECT rfq_id,
|
||
COALESCE(SUM(quantity * expected_price), 0) AS expectedTotal
|
||
FROM biz_rfq_item
|
||
GROUP BY rfq_id
|
||
) ri ON r.rfq_id = ri.rfq_id
|
||
LEFT JOIN (
|
||
SELECT q.rfq_id,
|
||
MIN(q.total_amount) AS lowestQuote
|
||
FROM biz_quotation q
|
||
WHERE q.status IN ('submitted', 'accepted', 'rejected')
|
||
AND q.total_amount > 0
|
||
GROUP BY q.rfq_id
|
||
) lowest ON r.rfq_id = lowest.rfq_id
|
||
LEFT JOIN (
|
||
SELECT q.rfq_id,
|
||
MAX(q.total_amount) AS acceptedQuote
|
||
FROM biz_quotation q
|
||
WHERE q.status = 'accepted'
|
||
GROUP BY q.rfq_id
|
||
) accepted ON r.rfq_id = accepted.rfq_id
|
||
LEFT JOIN (
|
||
SELECT q.rfq_id,
|
||
COUNT(DISTINCT q.supplier_id) AS supplierCount
|
||
FROM biz_quotation q
|
||
WHERE q.status IN ('submitted', 'accepted', 'rejected')
|
||
AND q.total_amount > 0
|
||
GROUP BY q.rfq_id
|
||
) sup ON r.rfq_id = sup.rfq_id
|
||
WHERE r.status = 'completed'
|
||
ORDER BY r.create_time DESC
|
||
</select>
|
||
|
||
<!-- ================================================================ -->
|
||
<!-- 供 应 商 绩 效 -->
|
||
<!-- ================================================================ -->
|
||
|
||
<!-- 供应商评分排名 -->
|
||
<select id="selectSupplierScores" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$SupplierScore">
|
||
SELECT
|
||
s.supplier_id AS supplierId,
|
||
s.supplier_name AS supplierName,
|
||
COALESCE(e.evalCount, 0) AS evalCount,
|
||
COALESCE(e.qualityAvg, 0) AS qualityAvg,
|
||
COALESCE(e.deliveryAvg, 0) AS deliveryAvg,
|
||
COALESCE(e.serviceAvg, 0) AS serviceAvg,
|
||
COALESCE(e.priceAvg, 0) AS priceAvg,
|
||
COALESCE(e.totalAvg, 0) AS totalAvg,
|
||
COALESCE(po.poCount, 0) AS poCount,
|
||
COALESCE(po.poAmount, 0) AS poAmount
|
||
FROM biz_supplier s
|
||
LEFT JOIN (
|
||
SELECT supplier_id,
|
||
COUNT(*) AS evalCount,
|
||
AVG(quality_score) AS qualityAvg,
|
||
AVG(delivery_score) AS deliveryAvg,
|
||
AVG(service_score) AS serviceAvg,
|
||
AVG(price_score) AS priceAvg,
|
||
AVG(total_score) AS totalAvg
|
||
FROM biz_supplier_evaluation
|
||
GROUP BY supplier_id
|
||
) e ON s.supplier_id = e.supplier_id
|
||
LEFT JOIN (
|
||
SELECT supplier_id,
|
||
COUNT(*) AS poCount,
|
||
SUM(total_amount) AS poAmount
|
||
FROM biz_purchase_order
|
||
WHERE status IN ('confirmed', 'closed', 'delivered')
|
||
GROUP BY supplier_id
|
||
) po ON s.supplier_id = po.supplier_id
|
||
ORDER BY totalAvg DESC
|
||
</select>
|
||
|
||
<!-- 中标率 -->
|
||
<select id="selectWinRate" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$WinRateData">
|
||
SELECT
|
||
q.supplier_id AS supplierId,
|
||
s.supplier_name AS supplierName,
|
||
COUNT(*) AS totalQuotes,
|
||
SUM(CASE WHEN q.status = 'accepted' THEN 1 ELSE 0 END) AS winCount,
|
||
ROUND(SUM(CASE WHEN q.status = 'accepted' THEN 1 ELSE 0 END) / COUNT(*) * 100, 1) AS winRate
|
||
FROM biz_quotation q
|
||
JOIN biz_supplier s ON q.supplier_id = s.supplier_id
|
||
WHERE q.status IN ('accepted', 'rejected')
|
||
GROUP BY q.supplier_id, s.supplier_name
|
||
ORDER BY winRate DESC
|
||
</select>
|
||
|
||
<!-- 雷达图数据 -->
|
||
<select id="selectRadarData" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$RadarData">
|
||
SELECT
|
||
s.supplier_name AS supplierName,
|
||
COALESCE(AVG(e.quality_score), 0) AS quality,
|
||
COALESCE(AVG(e.delivery_score), 0) AS delivery,
|
||
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
|
||
GROUP BY s.supplier_id, s.supplier_name
|
||
ORDER BY s.supplier_id
|
||
</select>
|
||
|
||
<!-- 异议统计 -->
|
||
<select id="selectObjectionStats" resultType="com.ruoyi.system.domain.bid.ReportSupplierVO$ObjectionStat">
|
||
SELECT
|
||
o.supplier_id AS supplierId,
|
||
s.supplier_name AS supplierName,
|
||
COUNT(*) AS objectionCount,
|
||
SUM(CASE WHEN o.status = 'resolved' THEN 1 ELSE 0 END) AS resolvedCount,
|
||
SUBSTRING_INDEX(GROUP_CONCAT(o.reason ORDER BY o.create_time DESC SEPARATOR ';'), ';', 1) AS topReason
|
||
FROM biz_order_objection o
|
||
JOIN biz_supplier s ON o.supplier_id = s.supplier_id
|
||
GROUP BY o.supplier_id, s.supplier_name
|
||
ORDER BY objectionCount DESC
|
||
</select>
|
||
|
||
</mapper>
|