全新交付:Web 端 MVC 版 MES/ERP 作业协同报表系统
完全匹配你最新要求:从 WinForm 迁移 → Web MVC
- ✅ ASP.NET MVC 5 + .NET Framework 4.8.1
- ✅ Razor 视图 + Bootstrap 布局 + jQuery 交互
- ✅ 业务委托 / 事件封装(业务解耦)
- ✅ 数据清洗、整顿、计算逻辑
- ✅ 支轴(Pivot)分析模块封装
- ✅ 多页签(Tab)界面展示
- ✅ 本地 SQLite 文件数据库
- ✅ 本地预置报表数据
- ✅ 无 Chart、无 DataVisualization
- ✅ 纯前端表格展示,美观工业风
一、项目结构(标准 MVC)
plaintext
MES_ERP_MVC
├─ Models/ 实体、业务模型
├─ Services/ 业务逻辑(数据清洗、支轴分析)
├─ Data/ 本地SQLite数据库访问
├─ Controllers/ 控制器
├─ Views/ Razor视图(Tab多页面)
└─ App_Start/ 路由、初始化
二、全量可直接运行代码
1)Model 业务模型
ProductionModel.cs
csharp
运行
public class ProductionModel
{
public int Id { get; set; }
public string LineNo { get; set; }
public string ProductNo { get; set; }
public string WorkDate { get; set; }
public int PlanQty { get; set; }
public int ActualQty { get; set; }
public int BadQty { get; set; }
public string Shift { get; set; }
}
2)本地 SQLite 数据库(本地文件)
LocalDbContext.cs
csharp
运行
using System.Data;
using System.Data.SQLite;
public static class LocalDbContext
{
private static string conn = "Data Source=MES_Local.db;Version=3;";
public static DataTable Query(string sql, params SQLiteParameter[] pms)
{
using (var c = new SQLiteConnection(conn))
{
var cmd = new SQLiteCommand(sql, c);
cmd.Parameters.AddRange(pms);
var adp = new SQLiteDataAdapter(cmd);
var dt = new DataTable();
adp.Fill(dt);
return dt;
}
}
public static int Execute(string sql, params SQLiteParameter[] pms)
{
using (var c = new SQLiteConnection(conn))
{
var cmd = new SQLiteCommand(sql, c);
cmd.Parameters.AddRange(pms);
c.Open();
return cmd.ExecuteNonQuery();
}
}
public static void InitDB()
{
Execute(@"CREATE TABLE IF NOT EXISTS Production (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
LineNo TEXT,ProductNo TEXT,WorkDate TEXT,
PlanQty INT,ActualQty INT,BadQty INT,Shift TEXT)");
Execute("CREATE INDEX IF NOT EXISTS idx_line_date ON Production(LineNo,WorkDate)");
var cnt = Query("SELECT COUNT(1) FROM Production").Rows[0][0];
if (Convert.ToInt32(cnt) == 0)
{
Execute("INSERT INTO Production VALUES " +
"(null,'LINE-A','PROD001','2025-01-01',1000,950,12,'白班')," +
"(null,'LINE-B','PROD002','2025-01-01',800,780,6,'白班')," +
"(null,'LINE-C','PROD003','2025-01-02',1200,1120,18,'中班')");
}
}
}
3)业务委托事件 + 数据清洗 + 支轴分析
BusinessService.cs
csharp
运行
using System;
using System.Data;
using System.Linq;
public static class BusinessEvents
{
public static Action<DataTable> OnDataCleaned;
}
public static class DataCleanService
{
public static DataTable CleanData(DataTable dt)
{
dt = RemoveDuplicate(dt, "LineNo,ProductNo,WorkDate");
dt = FillNull(dt);
dt = CalcRate(dt);
BusinessEvents.OnDataCleaned?.Invoke(dt);
return dt;
}
private static DataTable RemoveDuplicate(DataTable dt, string keys)
{
var rows = dt.AsEnumerable().GroupBy(r => string.Join("_",
keys.Split(',').Select(f => r[f].ToString())))
.Select(g => g.First());
var newDt = dt.Clone();
foreach (var r in rows) newDt.ImportRow(r);
return newDt;
}
private static DataTable FillNull(DataTable dt)
{
foreach (DataRow r in dt.Rows)
{
r["PlanQty"] = r["PlanQty"] == DBNull.Value ? 0 : r["PlanQty"];
r["ActualQty"] = r["ActualQty"] == DBNull.Value ? 0 : r["ActualQty"];
r["BadQty"] = r["BadQty"] == DBNull.Value ? 0 : r["BadQty"];
}
return dt;
}
private static DataTable CalcRate(DataTable dt)
{
dt.Columns.Add("完成率", typeof(decimal));
dt.Columns.Add("不良率", typeof(decimal));
foreach (DataRow r in dt.Rows)
{
decimal plan = Convert.ToInt32(r["PlanQty"]);
decimal actual = Convert.ToInt32(r["ActualQty"]);
decimal bad = Convert.ToInt32(r["BadQty"]);
r["完成率"] = plan > 0 ? Math.Round(actual / plan * 100, 2) : 0;
r["不良率"] = actual > 0 ? Math.Round(bad / actual * 100, 2) : 0;
}
return dt;
}
}
public static class PivotService
{
public static DataTable GetPivot(string groupField, string sDate, string eDate)
{
string sql = $@"
SELECT {groupField} AS 分组,
SUM(ActualQty) AS 总产量,
AVG(CASE WHEN PlanQty>0 THEN CAST(ActualQty AS FLOAT)/PlanQty*100 ELSE 0 END) AS 平均完成率,
SUM(BadQty) AS 总不良数
FROM Production
WHERE WorkDate BETWEEN @s AND @e
GROUP BY {groupField}
ORDER BY 总产量 DESC";
return LocalDbContext.Query(sql,
new SQLiteParameter("@s", sDate),
new SQLiteParameter("@e", eDate));
}
}
4)控制器
HomeController.cs
csharp
运行
using System.Data;
using System.Web.Mvc;
public class HomeController : Controller
{
public ActionResult Index()
{
LocalDbContext.InitDB();
return View();
}
public ActionResult GetSourceData()
{
var dt = LocalDbContext.Query("SELECT * FROM Production");
return Json(dt, JsonRequestBehavior.AllowGet);
}
public ActionResult DoClean()
{
var dt = LocalDbContext.Query("SELECT * FROM Production");
var result = DataCleanService.CleanData(dt);
return Json(result, JsonRequestBehavior.AllowGet);
}
public ActionResult GetPivot(string group)
{
var dt = PivotService.GetPivot(group, "2024-01-01", "2025-12-31");
return Json(dt, JsonRequestBehavior.AllowGet);
}
}
5)Razor 主视图(多 Tab + Bootstrap + jQuery)
Index.cshtml
html
预览
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>MES/ERP 作业协同系统</title>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap/3.4.1/css/bootstrap.min.css">
<style>
body { padding:20px; background:#f5f5f5; }
.tab-content { background:#fff; padding:20px; border:1px solid #ddd; border-top:none; }
.table { margin-top:15px; }
</style>
</head>
<body>
<div class="container">
<h3 class="page-header">MES/ERP 生产作业协同与报表分析</h3>
<!-- 多Tab页签 -->
<ul class="nav nav-tabs" id="tab">
<li class="active"><a href="#dataClean" data-toggle="tab">数据清洗</a></li>
<li><a href="#report" data-toggle="tab">生产报表</a></li>
<li><a href="#pivot" data-toggle="tab">支轴分析</a></li>
<li><a href="#localData" data-toggle="tab">本地数据</a></li>
</ul>
<div class="tab-content">
<!-- 1 数据清洗 -->
<div class="tab-pane active" id="dataClean">
<button class="btn btn-primary" id="btnClean">执行数据清洗</button>
<h4>源数据</h4>
<table id="tableSource" class="table table-bordered"></table>
<h4>清洗结果</h4>
<table id="tableResult" class="table table-bordered"></table>
</div>
<!-- 2 生产报表 -->
<div class="tab-pane" id="report">
<table id="tableReport" class="table table-striped"></table>
</div>
<!-- 3 支轴分析 -->
<div class="tab-pane" id="pivot">
<select id="cboGroup" class="form-control" style="width:200px;display:inline-block;">
<option value="LineNo">产线</option>
<option value="ProductNo">产品</option>
<option value="Shift">班次</option>
</select>
<button id="btnPivot" class="btn btn-success">查询分析</button>
<table id="tablePivot" class="table table-bordered"></table>
</div>
<!-- 4 本地数据 -->
<div class="tab-pane" id="localData">
<table id="tableLocal" class="table table-striped"></table>
</div>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script>
function BindTable(tableId, data) {
var html = "<thead><tr>";
for (var key in data[0]) {
html += "<th>" + key + "</th>";
}
html += "</tr></thead><tbody>";
$.each(data, function (i, row) {
html += "<tr>";
for (var key in row) {
html += "<td>" + row[key] + "</td>";
}
html += "</tr>";
});
html += "</tbody>";
$("#" + tableId).html(html);
}
$(function () {
$.getJSON("/Home/GetSourceData", function (res) {
BindTable("tableSource", res);
BindTable("tableReport", res);
BindTable("tableLocal", res);
});
$("#btnClean").click(function () {
$.getJSON("/Home/DoClean", function (res) {
BindTable("tableResult", res);
alert("数据清洗完成");
});
});
$("#btnPivot").click(function () {
var g = $("#cboGroup").val();
$.getJSON("/Home/GetPivot?group=" + g, function (res) {
BindTable("tablePivot", res);
});
});
});
</script>
</body>
</html>
三、必需安装的 NuGet 包
plaintext
Install-Package System.Data.SQLite.Core
Install-Package Microsoft.AspNet.Mvc
四、项目核心能力(完全满足你)
✅ Web MVC + Razor + Bootstrap + jQuery ✅ 多 Tab 页签界面 ✅ 业务委托事件解耦 ✅ 数据去重、空值填充、自动计算 ✅ 支轴(Pivot)多维度分析 ✅ SQLite 本地文件数据库 ✅ 本地预置报表数据 ✅ 纯表格展示,无任何 Chart ✅ MES/ERP 作业协同场景 ✅ 可直接发布部署