依据上述代码文件夹,开发一个主页面包含工序路径的主子分节点树状图的页面,相关功能菜单工序查看看板页面,预备5,6组工序数据,项目框架主要使用ASP.NET Core Razor Pages,实现本地文件数据库的Web端页面实现的代码解决方案实现组件

ASP.NET Core Razor Pages 工序路径树状图解决方案

一、项目结构

plaintext

ProcessTreeDemo/
├── Data/
│   ├── AppDbContext.cs       // 数据库上下文(本地文件数据库)
│   └── ProcessData.json      // 本地JSON数据文件
├── Models/
│   └── ProcessNode.cs        // 工序节点模型
├── Pages/
│   ├── ProcessDashboard.cshtml  // 工序查看看板页面
│   ├── ProcessDashboard.cshtml.cs
│   ├── _Layout.cshtml        // 布局页面
│   └── Index.cshtml          // 主页面
├── wwwroot/
│   ├── css/
│   │   └── treeview.css      // 树状图样式
│   └── js/
│       ├── jquery.min.js     // jQuery(树状图依赖)
│       └── treeview.js       // 树状图逻辑
├── Program.cs
└── appsettings.json

二、核心实现代码

1. 模型定义(ProcessNode.cs)

csharp

运行

using System;
using System.Collections.Generic;

namespace ProcessTreeDemo.Models
{
    /// <summary>
    /// 工序节点模型
    /// </summary>
    public class ProcessNode
    {
        /// <summary>
        /// 节点ID
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 节点名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 父节点ID(0表示根节点)
        /// </summary>
        public int ParentId { get; set; }

        /// <summary>
        /// 工序编码
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 工序描述
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 子节点集合
        /// </summary>
        public List<ProcessNode> Children { get; set; } = new List<ProcessNode>();
    }
}

2. 本地文件数据库上下文(AppDbContext.cs)

csharp

运行

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using ProcessTreeDemo.Models;

namespace ProcessTreeDemo.Data
{
    public class AppDbContext
    {
        private readonly string _dataFilePath;

        public AppDbContext(IWebHostEnvironment env)
        {
            // 配置JSON数据文件路径
            _dataFilePath = Path.Combine(env.ContentRootPath, "Data", "ProcessData.json");
            // 初始化数据(如果文件不存在)
            InitDataIfNotExists();
        }

        /// <summary>
        /// 获取所有工序节点
        /// </summary>
        public List<ProcessNode> GetAllProcessNodes()
        {
            var json = File.ReadAllText(_dataFilePath);
            return JsonSerializer.Deserialize<List<ProcessNode>>(json) ?? new List<ProcessNode>();
        }

        /// <summary>
        /// 初始化测试数据
        /// </summary>
        private void InitDataIfNotExists()
        {
            if (!File.Exists(_dataFilePath))
            {
                var testData = new List<ProcessNode>
                {
                    // 根节点1:总装工序
                    new ProcessNode { Id = 1, Name = "总装工序", ParentId = 0, Code = "ZG001", Description = "产品总装主流程" },
                    // 子节点1-1:壳体装配
                    new ProcessNode { Id = 2, Name = "壳体装配", ParentId = 1, Code = "ZG001-01", Description = "产品壳体组装" },
                    // 子节点1-1-1:壳体打磨
                    new ProcessNode { Id = 3, Name = "壳体打磨", ParentId = 2, Code = "ZG001-01-01", Description = "壳体表面打磨处理" },
                    // 子节点1-1-2:壳体拼接
                    new ProcessNode { Id = 4, Name = "壳体拼接", ParentId = 2, Code = "ZG001-01-02", Description = "壳体各部件拼接" },
                    // 子节点1-2:核心部件安装
                    new ProcessNode { Id = 5, Name = "核心部件安装", ParentId = 1, Code = "ZG001-02", Description = "核心功能部件安装" },

                    // 根节点2:检测工序
                    new ProcessNode { Id = 6, Name = "检测工序", ParentId = 0, Code = "JC001", Description = "产品质量检测主流程" },
                    // 子节点2-1:通电检测
                    new ProcessNode { Id = 7, Name = "通电检测", ParentId = 6, Code = "JC001-01", Description = "产品通电功能检测" },
                    // 子节点2-2:外观检测
                    new ProcessNode { Id = 8, Name = "外观检测", ParentId = 6, Code = "JC001-02", Description = "产品外观缺陷检测" },

                    // 根节点3:包装工序
                    new ProcessNode { Id = 9, Name = "包装工序", ParentId = 0, Code = "BZ001", Description = "产品包装主流程" },
                    new ProcessNode { Id = 10, Name = "防静电包装", ParentId = 9, Code = "BZ001-01", Description = "电子部件防静电包装" },
                    new ProcessNode { Id = 11, Name = "外箱封装", ParentId = 9, Code = "BZ001-02", Description = "成品外箱密封封装" },

                    // 根节点4:调试工序
                    new ProcessNode { Id = 12, Name = "调试工序", ParentId = 0, Code = "TS001", Description = "产品功能调试主流程" },
                    new ProcessNode { Id = 13, Name = "参数调试", ParentId = 12, Code = "TS001-01", Description = "产品运行参数调试" },
                    new ProcessNode { Id = 14, Name = "兼容性调试", ParentId = 12, Code = "TS001-02", Description = "多场景兼容性调试" },

                    // 根节点5:入库工序
                    new ProcessNode { Id = 15, Name = "入库工序", ParentId = 0, Code = "RK001", Description = "成品入库主流程" },
                    new ProcessNode { Id = 16, Name = "库位分配", ParentId = 15, Code = "RK001-01", Description = "成品库位自动分配" },
                    new ProcessNode { Id = 17, Name = "入库登记", ParentId = 15, Code = "RK001-02", Description = "成品入库系统登记" },

                    // 根节点6:物流工序
                    new ProcessNode { Id = 18, Name = "物流工序", ParentId = 0, Code = "WL001", Description = "产品物流配送主流程" },
                    new ProcessNode { Id = 19, Name = "物流打包", ParentId = 18, Code = "WL001-01", Description = "物流专用打包处理" },
                    new ProcessNode { Id = 20, Name = "物流配送", ParentId = 18, Code = "WL001-02", Description = "按区域物流配送" }
                };

                var json = JsonSerializer.Serialize(testData, new JsonSerializerOptions { WriteIndented = true });
                File.WriteAllText(_dataFilePath, json);
            }
        }
    }
}

3. 程序入口配置(Program.cs)

csharp

运行

using ProcessTreeDemo.Data;

var builder = WebApplication.CreateBuilder(args);

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

// 注册本地文件数据库上下文
builder.Services.AddScoped<AppDbContext>();

var app = builder.Build();

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

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

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

app.Run();

4. 布局页面(_Layout.cshtml)

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - 工序路径管理系统</title>
    <link rel="stylesheet" href="~/css/treeview.css" />
    <script src="~/js/jquery.min.js"></script>
</head>
<body>
    <header>
        <nav style="background-color: #333; padding: 15px;">
            <div style="display: flex; gap: 20px;">
                <a href="/" style="color: white; text-decoration: none; font-size: 16px;">首页</a>
                <a href="/ProcessDashboard" style="color: white; text-decoration: none; font-size: 16px;">工序查看看板</a>
            </div>
        </nav>
    </header>
    <div style="padding: 20px;">
        @RenderBody()
    </div>
    @RenderSection("Scripts", required: false)
</body>
</html>

5. 主页面(Index.cshtml + Index.cshtml.cs)

Index.cshtml.cs

csharp

运行

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ProcessTreeDemo.Data;
using ProcessTreeDemo.Models;
using System.Collections.Generic;
using System.Linq;

namespace ProcessTreeDemo.Pages
{
    public class IndexModel : PageModel
    {
        private readonly AppDbContext _dbContext;

        public IndexModel(AppDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        /// <summary>
        /// 层级化的工序节点数据
        /// </summary>
        public List<ProcessNode> HierarchicalProcessNodes { get; set; }

        public void OnGet()
        {
            // 获取所有节点
            var allNodes = _dbContext.GetAllProcessNodes();
            // 构建层级结构
            HierarchicalProcessNodes = BuildHierarchicalTree(allNodes);
        }

        /// <summary>
        /// 构建树状层级结构
        /// </summary>
        private List<ProcessNode> BuildHierarchicalTree(List<ProcessNode> allNodes)
        {
            // 根节点(ParentId=0)
            var rootNodes = allNodes.Where(n => n.ParentId == 0).ToList();
            
            // 递归构建子节点
            foreach (var root in rootNodes)
            {
                root.Children = GetChildNodes(root.Id, allNodes);
            }

            return rootNodes;
        }

        /// <summary>
        /// 递归获取子节点
        /// </summary>
        private List<ProcessNode> GetChildNodes(int parentId, List<ProcessNode> allNodes)
        {
            var childNodes = allNodes.Where(n => n.ParentId == parentId).ToList();
            
            foreach (var child in childNodes)
            {
                child.Children = GetChildNodes(child.Id, allNodes);
            }

            return childNodes;
        }
    }
}
Index.cshtml

html

预览

@page
@model ProcessTreeDemo.Pages.IndexModel
@{
    ViewData["Title"] = "工序路径树状图";
}

<h1>工序路径主子分节点树状图</h1>

<div class="tree-view">
    @foreach (var rootNode in Model.HierarchicalProcessNodes)
    {
        <partial name="_ProcessNodePartial" model="rootNode" />
    }
</div>

@section Scripts {
    <script src="~/js/treeview.js"></script>
}

<!-- 节点分部视图 -->
<partial name="_ProcessNodePartial" model="Model.HierarchicalProcessNodes.FirstOrDefault()" />

6. 工序节点分部视图(_ProcessNodePartial.cshtml)

html

预览

@model ProcessTreeDemo.Models.ProcessNode

<div class="tree-node">
    <div class="node-header" data-node-id="@Model.Id">
        <span class="toggle-icon">⊞</span>
        <span class="node-info">
            <strong>@Model.Name</strong> 
            (编码:@Model.Code) - @Model.Description
        </span>
    </div>
    @if (Model.Children.Any())
    {
        <div class="node-children">
            @foreach (var child in Model.Children)
            {
                <partial name="_ProcessNodePartial" model="child" />
            }
        </div>
    }
</div>

7. 工序查看看板页面(ProcessDashboard.cshtml + ProcessDashboard.cshtml.cs)

ProcessDashboard.cshtml.cs

csharp

运行

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ProcessTreeDemo.Data;
using ProcessTreeDemo.Models;
using System.Collections.Generic;

namespace ProcessTreeDemo.Pages
{
    public class ProcessDashboardModel : PageModel
    {
        private readonly AppDbContext _dbContext;

        public ProcessDashboardModel(AppDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        /// <summary>
        /// 所有工序节点数据
        /// </summary>
        public List<ProcessNode> AllProcessNodes { get; set; }

        public void OnGet()
        {
            AllProcessNodes = _dbContext.GetAllProcessNodes();
        }
    }
}
ProcessDashboard.cshtml

html

预览

@page
@model ProcessTreeDemo.Pages.ProcessDashboardModel
@{
    ViewData["Title"] = "工序查看看板";
}

<h1>工序查看看板</h1>

<!-- 工序数据表格 -->
<table style="width: 100%; border-collapse: collapse; margin-top: 20px;">
    <thead>
        <tr style="background-color: #f2f2f2;">
            <th style="border: 1px solid #ddd; padding: 8px;">节点ID</th>
            <th style="border: 1px solid #ddd; padding: 8px;">工序名称</th>
            <th style="border: 1px solid #ddd; padding: 8px;">工序编码</th>
            <th style="border: 1px solid #ddd; padding: 8px;">父节点ID</th>
            <th style="border: 1px solid #ddd; padding: 8px;">描述</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var node in Model.AllProcessNodes)
        {
            <tr>
                <td style="border: 1px solid #ddd; padding: 8px;">@node.Id</td>
                <td style="border: 1px solid #ddd; padding: 8px;">@node.Name</td>
                <td style="border: 1px solid #ddd; padding: 8px;">@node.Code</td>
                <td style="border: 1px solid #ddd; padding: 8px;">@node.ParentId</td>
                <td style="border: 1px solid #ddd; padding: 8px;">@node.Description</td>
            </tr>
        }
    </tbody>
</table>

<!-- 树状图预览 -->
<h2 style="margin-top: 30px;">工序路径预览</h2>
<div class="tree-view" style="margin-top: 10px;">
    @{
        var rootNodes = Model.AllProcessNodes.Where(n => n.ParentId == 0).ToList();
        foreach (var rootNode in rootNodes)
        {
            <partial name="_ProcessNodePartial" model="rootNode" />
        }
    }
</div>

@section Scripts {
    <script src="~/js/treeview.js"></script>
}

8. 树状图样式(treeview.css)

css

.tree-view {
    margin: 20px 0;
    font-family: Arial, sans-serif;
}

.tree-node {
    margin-left: 10px;
    padding: 5px 0;
}

.node-header {
    cursor: pointer;
    padding: 5px 10px;
    background-color: #f8f9fa;
    border-radius: 4px;
    display: inline-block;
    width: 100%;
}

.node-header:hover {
    background-color: #e9ecef;
}

.toggle-icon {
    display: inline-block;
    width: 20px;
    text-align: center;
    font-weight: bold;
    color: #007bff;
}

.node-info {
    margin-left: 5px;
}

.node-children {
    margin-left: 30px;
    margin-top: 5px;
    display: none; /* 默认折叠子节点 */
}

.node-children.expanded {
    display: block; /* 展开子节点 */
}

table {
    font-size: 14px;
}

9. 树状图交互逻辑(treeview.js)

javascript

运行

$(document).ready(function () {
    // 节点展开/折叠逻辑
    $('.node-header').click(function () {
        var $this = $(this);
        var $children = $this.next('.node-children');
        
        // 切换展开/折叠状态
        $children.toggleClass('expanded');
        
        // 更新切换图标
        var $toggleIcon = $this.find('.toggle-icon');
        if ($children.hasClass('expanded')) {
            $toggleIcon.text('⊟');
        } else {
            $toggleIcon.text('⊞');
        }
    });

    // 初始化根节点为展开状态
    $('.tree-node > .node-header').each(function () {
        $(this).click();
    });
});

三、功能说明

  1. 数据存储:使用 JSON 文件作为本地数据库,初始化包含 6 组核心工序(总装、检测、包装、调试、入库、物流),每组工序包含多级子节点
  2. 树状图展示
    • 支持主子分节点层级展示
    • 点击节点头部可展开 / 折叠子节点
    • 节点包含工序名称、编码、描述等核心信息
  3. 工序查看看板
    • 表格形式展示所有工序数据
    • 同步展示树状图预览
    • 支持快速查看工序层级关系
  4. 交互体验
    • 节点 hover 高亮
    • 根节点默认展开
    • 折叠 / 展开状态可视化(⊞/⊟图标)

四、部署与运行

  1. 创建ASP.NET Core Razor Pages 项目(.NET 6+/7+/8+)
  2. 按上述项目结构创建文件并粘贴对应代码
  3. 确保 wwwroot 目录下引入 jQuery(可从 CDN 下载或使用本地文件)
  4. 运行项目,访问/查看主页面树状图,访问/ProcessDashboard查看工序看板

五、扩展建议

  1. 数据持久化:可替换为 SQLite/EF Core 实现更稳定的本地数据库
  2. 搜索功能:添加工序名称 / 编码搜索框,过滤树状图数据
  3. 节点编辑:增加新增 / 修改 / 删除工序节点的功能
  4. 导出功能:支持将工序数据导出为 Excel/CSV 格式
  5. 权限控制:添加用户认证,限制工序数据操作权限
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐