Razor Pages工序管理Web端界面化实现方案

开发一个主页面包含工序路径的主子表单控件GridView表格图表的页面,工序管理带拖拽式控件,相关分菜单页面,SQLSugar相关函数预备5,6组工序数据,项目框架主要使用ASP.NET Core Razor Pages 应用,实现本地文件化数据库的Web端界面化实现的代码解决方案实现组件

ASP.NET Core Razor Pages 工序管理系统实现方案

一、项目基础架构

1. 项目创建与依赖

创建ASP.NET Core Razor Pages 项目(.NET 8),安装以下 NuGet 包:

powershell

复制代码
Install-Package SQLSugarCore
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Install-Package Bootstrap
Install-Package jQuery
Install-Package SortableJS
Install-Package Chart.js

2. 数据库配置(SQLite 本地文件数据库)

(1) SQLSugar 配置类

csharp

运行

复制代码
// Services/SqlSugarSetup.cs
using SqlSugar;

namespace ProcessManagement.Services
{
    public static class SqlSugarSetup
    {
        public static void AddSqlSugar(this IServiceCollection services)
        {
            var db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = "Data Source=ProcessManagement.db", // 本地SQLite文件
                DbType = DbType.Sqlite,
                IsAutoCloseConnection = true,
                InitKeyType = InitKeyType.Attribute
            });
            
            // 初始化数据库和表
            db.CodeFirst.InitTables<Process, ProcessPath, ProcessStep>();
            
            // 预插入测试数据
            InitTestData(db);
            
            services.AddSingleton<ISqlSugarClient>(db);
        }

        /// <summary>
        /// 初始化5-6组工序测试数据
        /// </summary>
        private static void InitTestData(ISqlSugarClient db)
        {
            if (!db.Queryable<Process>().Any())
            {
                var processes = new List<Process>
                {
                    new Process { Id = 1, ProcessName = "机械加工工序", CreateTime = DateTime.Now, Status = 1 },
                    new Process { Id = 2, ProcessName = "表面处理工序", CreateTime = DateTime.Now, Status = 1 },
                    new Process { Id = 3, ProcessName = "装配工序", CreateTime = DateTime.Now, Status = 1 },
                    new Process { Id = 4, ProcessName = "检测工序", CreateTime = DateTime.Now, Status = 1 },
                    new Process { Id = 5, ProcessName = "包装工序", CreateTime = DateTime.Now, Status = 1 },
                    new Process { Id = 6, ProcessName = "热处理工序", CreateTime = DateTime.Now, Status = 0 }
                };
                db.Insertable(processes).ExecuteCommand();

                // 工序路径数据
                var paths = new List<ProcessPath>
                {
                    new ProcessPath { Id = 1, ProcessId = 1, PathName = "主轴加工路径", PathCode = "PATH001" },
                    new ProcessPath { Id = 2, ProcessId = 1, PathName = "外壳加工路径", PathCode = "PATH002" },
                    new ProcessPath { Id = 3, ProcessId = 2, PathName = "镀锌处理路径", PathCode = "PATH003" },
                    new ProcessPath { Id = 4, ProcessId = 3, PathName = "总装路径", PathCode = "PATH004" },
                    new ProcessPath { Id = 5, ProcessId = 4, PathName = "精度检测路径", PathCode = "PATH005" },
                    new ProcessPath { Id = 6, ProcessId = 5, PathName = "成品包装路径", PathCode = "PATH006" }
                };
                db.Insertable(paths).ExecuteCommand();

                // 工序步骤(用于拖拽排序)
                var steps = new List<ProcessStep>
                {
                    new ProcessStep { Id = 1, PathId = 1, StepName = "粗加工", Sort = 1 },
                    new ProcessStep { Id = 2, PathId = 1, StepName = "半精加工", Sort = 2 },
                    new ProcessStep { Id = 3, PathId = 1, StepName = "精加工", Sort = 3 },
                    new ProcessStep { Id = 4, PathId = 2, StepName = "打磨", Sort = 1 },
                    new ProcessStep { Id = 5, PathId = 2, StepName = "抛光", Sort = 2 },
                    new ProcessStep { Id = 6, PathId = 3, StepName = "脱脂", Sort = 1 },
                    new ProcessStep { Id = 7, PathId = 3, StepName = "酸洗", Sort = 2 },
                    new ProcessStep { Id = 8, PathId = 3, StepName = "镀锌", Sort = 3 },
                    new ProcessStep { Id = 9, PathId = 3, StepName = "钝化", Sort = 4 }
                };
                db.Insertable(steps).ExecuteCommand();
            }
        }
    }
}
(2) 实体类定义

csharp

运行

复制代码
// Models/Process.cs
using SqlSugar;

namespace ProcessManagement.Models
{
    /// <summary>
    /// 工序主表
    /// </summary>
    [SugarTable("Process")]
    public class Process
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        
        [SugarColumn(ColumnName = "ProcessName", Length = 100, IsNullable = false)]
        public string ProcessName { get; set; } = string.Empty;
        
        [SugarColumn(ColumnName = "CreateTime")]
        public DateTime CreateTime { get; set; }
        
        [SugarColumn(ColumnName = "Status")] // 1-启用 0-禁用
        public int Status { get; set; }
    }

    /// <summary>
    /// 工序路径表(子表)
    /// </summary>
    [SugarTable("ProcessPath")]
    public class ProcessPath
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        
        [SugarColumn(ColumnName = "ProcessId")]
        public int ProcessId { get; set; }
        
        [SugarColumn(ColumnName = "PathName", Length = 100, IsNullable = false)]
        public string PathName { get; set; } = string.Empty;
        
        [SugarColumn(ColumnName = "PathCode", Length = 50, IsNullable = false)]
        public string PathCode { get; set; } = string.Empty;
        
        // 导航属性
        [SugarColumn(IsIgnore = true)]
        public List<ProcessStep> Steps { get; set; } = new List<ProcessStep>();
    }

    /// <summary>
    /// 工序步骤表(用于拖拽排序)
    /// </summary>
    [SugarTable("ProcessStep")]
    public class ProcessStep
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        
        [SugarColumn(ColumnName = "PathId")]
        public int PathId { get; set; }
        
        [SugarColumn(ColumnName = "StepName", Length = 100, IsNullable = false)]
        public string StepName { get; set; } = string.Empty;
        
        [SugarColumn(ColumnName = "Sort")] // 排序字段
        public int Sort { get; set; }
    }
}
(3) Program.cs 注册服务

csharp

运行

复制代码
using ProcessManagement.Services;

var builder = WebApplication.CreateBuilder(args);

// 添加Razor Pages支持
builder.Services.AddRazorPages();

// 注册SQLSugar
builder.Services.AddSqlSugar();

var app = builder.Build();

// 中间件配置
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

// 配置路由
app.MapRazorPages();

app.Run();

二、核心页面实现

1. 主页面(Index.cshtml)- 包含 GridView、图表、主子表单

(1) Index.cshtml.cs 后台逻辑

csharp

运行

复制代码
// Pages/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ProcessManagement.Models;
using SqlSugar;
using System.Data;

namespace ProcessManagement.Pages
{
    public class IndexModel : PageModel
    {
        private readonly ISqlSugarClient _db;

        public IndexModel(ISqlSugarClient db)
        {
            _db = db;
        }

        /// <summary>
        /// 工序列表(主表)
        /// </summary>
        public List<Process> ProcessList { get; set; } = new List<Process>();
        
        /// <summary>
        /// 选中工序的路径列表(子表)
        /// </summary>
        public List<ProcessPath> SelectedPathList { get; set; } = new List<ProcessPath>();
        
        /// <summary>
        /// 图表数据
        /// </summary>
        public string ChartData { get; set; } = string.Empty;

        public void OnGet(int? processId = 1)
        {
            // 获取所有工序
            ProcessList = _db.Queryable<Process>().ToList();
            
            // 获取选中工序的路径(含步骤)
            SelectedPathList = _db.Queryable<ProcessPath>()
                .Where(p => p.ProcessId == processId)
                .LeftJoin<ProcessStep>((p, s) => p.Id == s.PathId)
                .Select((p, s) => new ProcessPath
                {
                    Id = p.Id,
                    ProcessId = p.ProcessId,
                    PathName = p.PathName,
                    PathCode = p.PathCode,
                    Steps = SqlFunc.GroupBySelect<ProcessStep>(s, it => it).OrderBy(it => it.Sort).ToList()
                })
                .GroupBy(p => p.Id)
                .ToList();
            
            // 构建图表数据(工序数量统计)
            var chartData = _db.Queryable<Process>()
                .GroupBy(p => p.Status)
                .Select(p => new { 
                    Name = SqlFunc.Case().When(p.Status == 1).Then("启用").Else("禁用").End(),
                    Count = SqlFunc.Count(p.Id)
                }).ToList();
            
            ChartData = System.Text.Json.JsonSerializer.Serialize(chartData);
        }

        /// <summary>
        /// 切换工序
        /// </summary>
        public IActionResult OnGetSwitchProcess(int processId)
        {
            SelectedPathList = _db.Queryable<ProcessPath>()
                .Where(p => p.ProcessId == processId)
                .LeftJoin<ProcessStep>((p, s) => p.Id == s.PathId)
                .Select((p, s) => new ProcessPath
                {
                    Id = p.Id,
                    ProcessId = p.ProcessId,
                    PathName = p.PathName,
                    PathCode = p.PathCode,
                    Steps = SqlFunc.GroupBySelect<ProcessStep>(s, it => it).OrderBy(it => it.Sort).ToList()
                })
                .GroupBy(p => p.Id)
                .ToList();
            
            return new JsonResult(new { success = true, data = SelectedPathList });
        }
    }
}
(2) Index.cshtml 前端页面

html

预览

复制代码
@page
@model ProcessManagement.Pages.IndexModel
@{
    ViewData["Title"] = "工序管理主页面";
}

<!-- 引入静态资源 -->
<link href="~/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="~/lib/jquery/jquery.min.js"></script>
<script src="~/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="~/lib/chart.js/chart.umd.js"></script>
<script src="~/lib/sortablejs/Sortable.min.js"></script>

<div class="container mt-4">
    <h2 class="mb-4">工序管理系统</h2>

    <!-- 1. 工序统计图表 -->
    <div class="row mb-4">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">工序状态统计</div>
                <div class="card-body">
                    <canvas id="processChart"></canvas>
                </div>
            </div>
        </div>
        
        <!-- 2. 工序主表GridView -->
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">工序列表</div>
                <div class="card-body">
                    <table class="table table-bordered table-hover">
                        <thead>
                            <tr>
                                <th>ID</th>
                                <th>工序名称</th>
                                <th>创建时间</th>
                                <th>状态</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var process in Model.ProcessList)
                            {
                                <tr @(process.Id == 1 ? "class='table-primary'" : "")>
                                    <td>@process.Id</td>
                                    <td>@process.ProcessName</td>
                                    <td>@process.CreateTime.ToString("yyyy-MM-dd")</td>
                                    <td>@(process.Status == 1 ? "启用" : "禁用")</td>
                                    <td>
                                        <button class="btn btn-sm btn-primary switch-process" 
                                                data-process-id="@process.Id">选择</button>
                                    </td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <!-- 3. 工序路径子表 + 拖拽式步骤管理 -->
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="card-header">工序路径(子表)</div>
                <div class="card-body">
                    <div id="pathContainer">
                        @foreach (var path in Model.SelectedPathList)
                        {
                            <div class="mb-4 border p-3">
                                <h5>路径名称:@path.PathName(编码:@path.PathCode)</h5>
                                <div class="mb-2">
                                    <strong>工序步骤(拖拽排序):</strong>
                                </div>
                                <ul id="stepList_@path.Id" class="list-group sortable-step-list">
                                    @foreach (var step in path.Steps)
                                    {
                                        <li class="list-group-item" data-step-id="@step.Id">
                                            @step.Sort. @step.StepName
                                        </li>
                                    }
                                </ul>
                                <button class="btn btn-sm btn-success mt-2 save-sort" 
                                        data-path-id="@path.Id">保存排序</button>
                            </div>
                        }
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    // 1. 初始化图表
    const chartData = @Html.Raw(Model.ChartData);
    const ctx = document.getElementById('processChart').getContext('2d');
    new Chart(ctx, {
        type: 'pie',
        data: {
            labels: chartData.map(item => item.Name),
            datasets: [{
                label: '工序数量',
                data: chartData.map(item => item.Count),
                backgroundColor: ['#28a745', '#dc3545']
            }]
        },
        options: {
            responsive: true
        }
    });

    // 2. 切换工序
    $('.switch-process').click(function () {
        const processId = $(this).data('process-id');
        $.get(`?handler=SwitchProcess&processId=${processId}`, function (res) {
            if (res.success) {
                let html = '';
                res.data.forEach(path => {
                    let stepHtml = '';
                    path.steps.forEach(step => {
                        stepHtml += `<li class="list-group-item" data-step-id="${step.id}">
                            ${step.sort}. ${step.stepName}
                        </li>`;
                    });
                    
                    html += `<div class="mb-4 border p-3">
                        <h5>路径名称:${path.pathName}(编码:${path.pathCode})</h5>
                        <div class="mb-2">
                            <strong>工序步骤(拖拽排序):</strong>
                        </div>
                        <ul id="stepList_${path.id}" class="list-group sortable-step-list">
                            ${stepHtml}
                        </ul>
                        <button class="btn btn-sm btn-success mt-2 save-sort" 
                                data-path-id="${path.id}">保存排序</button>
                    </div>`;
                });
                $('#pathContainer').html(html);
                initSortable(); // 重新初始化拖拽
            }
        });
    });

    // 3. 初始化拖拽排序
    function initSortable() {
        $('.sortable-step-list').each(function () {
            new Sortable(this, {
                animation: 150,
                handle: '.list-group-item',
                ghostClass: 'bg-light'
            });
        });
    }

    // 4. 保存排序
    $(document).on('click', '.save-sort', function () {
        const pathId = $(this).data('path-id');
        const stepList = $(`#stepList_${pathId}`);
        const sortData = [];
        
        stepList.find('li').each(function (index) {
            sortData.push({
                stepId: $(this).data('step-id'),
                sort: index + 1
            });
        });

        // 提交排序数据(后续实现保存接口)
        $.post(`/ProcessStep/SaveSort?pathId=${pathId}`, 
            JSON.stringify(sortData), 
            function (res) {
                if (res.success) {
                    alert('排序保存成功!');
                } else {
                    alert('排序保存失败!');
                }
            }, 'json')
            .fail(function () {
                alert('请求失败!');
            });
    });

    // 页面加载时初始化拖拽
    $(function () {
        initSortable();
    });
</script>

2. 工序步骤排序保存页面(ProcessStep/SaveSort.cshtml.cs)

csharp

运行

复制代码
// Pages/ProcessStep/SaveSort.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ProcessManagement.Models;
using SqlSugar;

namespace ProcessManagement.Pages.ProcessStep
{
    public class SaveSortModel : PageModel
    {
        private readonly ISqlSugarClient _db;

        public SaveSortModel(ISqlSugarClient db)
        {
            _db = db;
        }

        public async Task<IActionResult> OnPostAsync(int pathId, [FromBody] List<StepSortDto> sortData)
        {
            try
            {
                // 批量更新排序
                foreach (var item in sortData)
                {
                    await _db.Updateable<ProcessStep>()
                        .SetColumns(s => s.Sort == item.Sort)
                        .Where(s => s.Id == item.StepId)
                        .ExecuteCommandAsync();
                }
                return new JsonResult(new { success = true });
            }
            catch (Exception ex)
            {
                return new JsonResult(new { success = false, message = ex.Message });
            }
        }

        public class StepSortDto
        {
            public int StepId { get; set; }
            public int Sort { get; set; }
        }
    }
}

3. 分菜单页面示例(ProcessManage.cshtml)

html

预览

复制代码
@page "/ProcessManage"
@model ProcessManagement.Pages.ProcessManageModel
@{
    ViewData["Title"] = "工序管理";
}

<link href="~/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="~/lib/jquery/jquery.min.js"></script>

<div class="container mt-4">
    <h2>工序基础管理</h2>
    
    <!-- 工序新增/编辑表单 -->
    <div class="card mb-4">
        <div class="card-header">工序信息维护</div>
        <div class="card-body">
            <form id="processForm">
                <div class="row mb-3">
                    <div class="col-md-6">
                        <label class="form-label">工序名称</label>
                        <input type="text" class="form-control" id="processName" required />
                    </div>
                    <div class="col-md-6">
                        <label class="form-label">状态</label>
                        <select class="form-select" id="processStatus">
                            <option value="1">启用</option>
                            <option value="0">禁用</option>
                        </select>
                    </div>
                </div>
                <button type="submit" class="btn btn-primary">保存</button>
            </form>
        </div>
    </div>

    <!-- 工序列表 -->
    <div class="card">
        <div class="card-header">工序列表</div>
        <div class="card-body">
            <table class="table table-bordered" id="processTable">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>工序名称</th>
                        <th>创建时间</th>
                        <th>状态</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var process in Model.ProcessList)
                    {
                        <tr>
                            <td>@process.Id</td>
                            <td>@process.ProcessName</td>
                            <td>@process.CreateTime.ToString("yyyy-MM-dd")</td>
                            <td>@(process.Status == 1 ? "启用" : "禁用")</td>
                            <td>
                                <button class="btn btn-sm btn-warning edit-process" data-id="@process.Id">编辑</button>
                                <button class="btn btn-sm btn-danger delete-process" data-id="@process.Id">删除</button>
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
    </div>
</div>

<script>
    // 表单提交
    $('#processForm').submit(function (e) {
        e.preventDefault();
        const data = {
            ProcessName: $('#processName').val(),
            Status: $('#processStatus').val()
        };
        
        // 提交新增/编辑请求(后续实现接口)
        $.post('/ProcessManage/SaveProcess', data, function (res) {
            if (res.success) {
                alert('保存成功!');
                window.location.reload();
            } else {
                alert('保存失败:' + res.message);
            }
        }, 'json');
    });

    // 删除工序
    $('.delete-process').click(function () {
        if (confirm('确认删除该工序?')) {
            const id = $(this).data('id');
            $.post(`/ProcessManage/DeleteProcess?id=${id}`, function (res) {
                if (res.success) {
                    alert('删除成功!');
                    window.location.reload();
                } else {
                    alert('删除失败:' + res.message);
                }
            }, 'json');
        }
    });
</script>

三、关键功能说明

1. 拖拽排序实现

使用 SortableJS 实现工序步骤的拖拽排序,通过data-step-id绑定步骤 ID,拖拽后获取新的排序序号,提交到后台批量更新Sort字段。

2. 主子表单联动

通过点击主表(工序)的 "选择" 按钮,异步加载对应子表(工序路径)数据,更新页面展示。

3. 本地文件数据库

使用 SQLite 作为本地文件数据库,无需额外安装数据库服务,数据存储在ProcessManagement.db文件中。

4. SQLSugar 核心函数示例

csharp

运行

复制代码
// 1. 关联查询+分组
var pathWithSteps = _db.Queryable<ProcessPath>()
    .LeftJoin<ProcessStep>((p, s) => p.Id == s.PathId)
    .Select((p, s) => new ProcessPath
    {
        Id = p.Id,
        PathName = p.PathName,
        Steps = SqlFunc.GroupBySelect<ProcessStep>(s, it => it).OrderBy(it => it.Sort).ToList()
    })
    .GroupBy(p => p.Id)
    .ToList();

// 2. 批量插入
_db.Insertable(processList).ExecuteCommand();

// 3. 条件更新
_db.Updateable<ProcessStep>()
    .SetColumns(s => s.Sort == newSort)
    .Where(s => s.Id == stepId)
    .ExecuteCommand();

// 4. 分组统计
var stat = _db.Queryable<Process>()
    .GroupBy(p => p.Status)
    .Select(p => new { Count = SqlFunc.Count(p.Id) })
    .ToList();

// 5. 左连接查询
var joinData = _db.Queryable<Process>()
    .LeftJoin<ProcessPath>((p, pp) => p.Id == pp.ProcessId)
    .Select((p, pp) => new { p.ProcessName, pp.PathName })
    .ToList();

四、部署与运行

  1. 将项目发布为本地文件,或直接在 VS 中运行
  2. 首次运行会自动创建ProcessManagement.db SQLite 数据库文件,并插入测试数据
  3. 访问https://localhost:5001即可进入主页面
  4. 支持工序选择、路径步骤拖拽排序、图表展示、基础工序管理等功能

五、扩展建议

  1. 添加分页功能:对工序列表实现分页查询,优化大数据量展示
  2. 增加数据验证:在表单提交时添加前端 + 后端双重验证
  3. 完善权限控制:添加用户登录、角色权限管理
  4. 导出功能:支持将工序数据导出为 Excel/CSV 格式
  5. 日志记录:添加操作日志,记录工序修改、排序变更等操作
相关推荐
特立独行的猫a1 小时前
Fast DDS & Fast DDS Spy Windows x64 编译安装完全指南
windows·编译·安装·fastdds·fastddsspy
爱喝热水的呀哈喽2 小时前
多轮对话 gpt‘
运维·windows·python
私人珍藏库2 小时前
【PC】[吾爱大神原创工具] PDFImageViewer V1 永久免费的PDF图像查看和导出工具
windows·pdf·工具·软件·多功能
阿昭L2 小时前
Windows进程间通信
windows·进程通信
H Journey2 小时前
Windows下通过vscode连接 Linux服务器
windows·vscode·venv
GDAL3 小时前
在 Windows 上做 Go 跨平台编
windows·golang
whyfail3 小时前
Codex 下载安装指南:Windows 和 macOS 官方版下载
windows·macos·codex
感谢地心引力3 小时前
在Claude Code里面使用Deepseek-v4,支持mac和Windows双系统
人工智能·windows·macos·ai·deepseek·claude code
c238563 小时前
list(下)
数据结构·windows·list