简介:这份供应链系统页面原型资源面向产品经理、UI设计师、前端开发者及供应链业务人员,用于在开发前期快速理解系统界面布局与交互流程,降低沟通成本。压缩包共299个文件,约661KB,以87个html页面为主体,辅以126个gif与43个png图片素材、14张jpg、5个css与6个js脚本,另有15个scc及3个xlsx表格,覆盖登录、菜单、表单等界面元素。内容围绕采购管理、库存管理、生产计划与调度、物流配送、销售分销、财务管理及报表分析等核心模块展开,每个页面均呈现按钮、表单、图表与导航菜单的协同方式。已有1175人学习下载,适合作为供应链系统设计阶段的参考模板,帮助读者把握需求实现方式,提升项目落地效率。
1. 供应链系统页面原型:一套能直接跑起来的 HTML 静态原型
如果你接过供应链相关的后台项目,大概率遇到过这种局面:需求方说“先出个页面看看”,后端接口还没影,设计稿只给了几张模糊的截图,前端却要在一周内拿出能点击、能跳转、能演示的原型。这时候最省事的做法不是从零画页面,而是找一套结构完整、模块齐全的 HTML 原型,把菜单、表格、表单、弹窗这些高频组件先搭起来。这份「供应链系统页面原型」就是干这个的——它用纯 HTML 加 CSS 加少量 JavaScript,把供应商管理、采购订单、库存查询、物流跟踪这几个核心业务场景的页面骨架全部铺好,下载解压后用浏览器直接打开就能点。适合谁?适合需要快速交付演示版本的前端、需要给客户看流程的产品,以及想拿一套现成后台模板做二次开发的人。
2. 技术选型与目录结构:为什么用纯静态 HTML 而不是框架
2.1 静态原型的取舍逻辑
拿到一份原型资源,第一件事是判断它的技术底座。这套原型没有用 Vue、React 或者任何构建工具,全部是原生 HTML 文件加外链 CSS 和 JavaScript。这个选择在原型阶段其实很合理:供应链系统的页面原型核心诉求是“能看、能点、能改”,而不是“能扛住生产流量”。用框架反而会引入 node_modules、构建配置、路由定义这些额外负担,改一个字段名要重新编译,演示时还得起本地服务。
原生方案的好处是双击index.html就能跑,发给不懂技术的业务方也能直接打开。代价是页面之间的状态共享要靠 URL 参数或者 localStorage 手动处理,组件复用靠复制粘贴。对于原型来说,这个代价可以接受。我一般会在原型阶段刻意保持这种“低技术密度”,把精力留给信息架构和交互流程,等需求确认后再决定要不要迁移到框架。
2.2 目录结构拆解
一份组织良好的静态原型,目录结构本身就是文档。这套原型的典型布局如下:
supply-chain-prototype/ ├── index.html # 登录页 / 入口 ├── dashboard.html # 数据概览首页 ├── supplier/ │ ├── list.html # 供应商列表 │ ├── detail.html # 供应商详情 │ └── edit.html # 供应商新增/编辑 ├── purchase/ │ ├── order-list.html # 采购订单列表 │ ├── order-detail.html # 订单详情 │ └── order-create.html # 创建采购单 ├── inventory/ │ ├── stock-list.html # 库存查询 │ └── stock-alert.html # 库存预警 ├── logistics/ │ └── track.html # 物流跟踪 ├── css/ │ ├── reset.css # 样式重置 │ ├── layout.css # 布局框架(侧边栏 + 顶栏 + 内容区) │ └── components.css # 表格、表单、按钮、弹窗 ├── js/ │ ├── common.js # 公共函数(菜单高亮、弹窗控制) │ └── mock-data.js # 模拟数据 └── assets/ └── icons/ # 图标资源这个结构按业务域分目录,而不是按文件类型分。好处是找一个模块的页面时不用在几十个 HTML 文件里翻。css拆成三层也是常见做法:reset 抹平浏览器差异,layout 管整体骨架,components 管可复用控件。改样式时能快速定位到该改哪个文件。
2.3 布局框架的实现方式
后台系统原型的视觉一致性,八成靠布局框架撑着。这套原型用的是经典的「左侧固定侧边栏 + 顶部导航 + 右侧内容区」结构。核心 CSS 逻辑如下:
/* layout.css —— 三区布局骨架 */ .app-wrapper { display: flex; min-height: 100vh; } .sidebar { width: 220px; flex-shrink: 0; /* 侧边栏不参与压缩 */ background: #1f2d3d; overflow-y: auto; /* 菜单过多时内部滚动 */ } .main-container { flex: 1; /* 占满剩余宽度 */ display: flex; flex-direction: column; } .topbar { height: 56px; flex-shrink: 0; border-bottom: 1px solid #e8e8e8; } .content { flex: 1; padding: 20px; overflow-y: auto; /* 内容区独立滚动 */ background: #f5f7fa; }这里的关键点是flex-shrink: 0和overflow-y: auto的配合。侧边栏固定宽度不压缩,内容区自适应剩余空间;侧边栏和内容区各自独立滚动,互不影响。很多新手写后台布局时用position: fixed定位侧边栏,结果内容区要么被遮挡要么滚动错位,用 flex 能避开这个坑。
提示:如果你的原型需要适配小屏演示,可以在
.sidebar上加一个@media查询,窄屏时把宽度压到 60px 只显示图标,鼠标悬停再展开。
2.4 页面间的导航与状态传递
静态原型没有路由,页面跳转就是<a href="...">。但后台系统有个刚需:当前在哪个菜单,侧边栏对应项要高亮。纯静态页面里,这个状态没法自动感知,常见做法是在每个页面的<body>上打一个标记,然后用 JavaScript 统一处理:
// common.js —— 根据 body 标记高亮当前菜单 document.addEventListener('DOMContentLoaded', function () { // 每个页面在 body 上写><!-- supplier/list.html —— 数据表格骨架 --> <div class="table-wrapper"> <table class="data-table"> <thead> <tr> <th><input type="checkbox" id="check-all"></th> <th>供应商编码</th> <th>供应商名称</th> <th>联系人</th> <th>合作状态</th> <th>操作</th> </tr> </thead> <tbody id="supplier-tbody"> <!-- 数据由 mock-data.js 渲染,原型阶段先写死几行 --> </tbody> </table> <div class="pagination"> <span class="page-info">共 128 条</span> <button class="page-btn" disabled>上一页</button> <button class="page-btn active">1</button> <button class="page-btn">2</button> <button class="page-btn">下一页</button> </div> </div>表格用原生<table>而不是 div 模拟,是因为原型阶段要快速调整列宽和表头对齐,<table>的colspan、rowspan和自动列宽计算比 flex 模拟省事得多。check-all复选框控制全选,对应的 JavaScript 逻辑在common.js里统一处理,所有列表页共用。
3.2 模拟数据的组织方式
原型要看起来“像真的”,就得有像样的假数据。这套原型把数据集中放在mock-data.js里,按业务模块分组:
// mock-data.js —— 供应商模拟数据 var MOCK_SUPPLIERS = [ { code: 'SUP-2024-001', name: '华东电子元件供应商', contact: '张经理', phone: '138****0001', status: 'active', // active | pending | disabled statusText: '合作中' }, { code: 'SUP-2024-002', name: '南方物流服务商', contact: '李主管', phone: '139****0002', status: 'pending', statusText: '待审核' } // ... 更多数据 ]; // 渲染函数:把数据填充到表格 function renderSupplierTable(data) { var tbody = document.getElementById('supplier-tbody'); if (!tbody) return; var html = ''; data.forEach(function (item) { html += '<tr>'; html += '<td><input type="checkbox"></td>'; html += '<td>' + item.code + '</td>'; html += '<td>' + item.name + '</td>'; html += '<td>' + item.contact + '</td>'; html += '<td><span class="status-tag status-' + item.status + '">' + item.statusText + '</span></td>'; html += '<td><a href="detail.html?code=' + item.code + '">查看</a></td>'; html += '</tr>'; }); tbody.innerHTML = html; }数据字段的设计要和真实接口对齐。status用英文枚举值,statusText用中文展示文案,这样后续接真实接口时,前端渲染逻辑不用改,只需要把MOCK_SUPPLIERS换成接口返回的数据。状态标签的样式通过status-active、status-pending这类 class 控制颜色,在components.css里定义。
3.3 采购订单创建页的表单联动
采购订单创建页比列表页复杂,涉及表单校验和行项目动态增删。这套原型里,订单创建页包含供应商选择、收货信息、商品明细表格三块。商品明细支持「添加一行」「删除一行」,核心逻辑如下:
// purchase/order-create.js —— 动态添加商品行 function addOrderItemRow() { var tbody = document.getElementById('order-items'); var rowCount = tbody.querySelectorAll('tr').length; var tr = document.createElement('tr'); tr.innerHTML = '<td><input type="text" name="productCode" placeholder="商品编码"></td>' + '<td><input type="text" name="productName" placeholder="商品名称"></td>' + '<td><input type="number" name="qty" value="1" min="1"></td>' + '<td><input type="number" name="price" value="0.00" step="0.01"></td>' + '<td><span class="row-total">0.00</span></td>' + '<td><button type="button" onclick="removeOrderItemRow(this)">删除</button></td>'; tbody.appendChild(tr); bindRowCalculation(tr); // 绑定数量/单价变化时自动算小计 } // 行内小计计算 function bindRowCalculation(tr) { var qtyInput = tr.querySelector('input[name="qty"]'); var priceInput = tr.querySelector('input[name="price"]'); var totalSpan = tr.querySelector('.row-total'); function calc() { var qty = parseFloat(qtyInput.value) || 0; var price = parseFloat(priceInput.value) || 0; totalSpan.textContent = (qty * price).toFixed(2); calcGrandTotal(); // 重算合计金额 } qtyInput.addEventListener('input', calc); priceInput.addEventListener('input', calc); }这里有两个容易忽略的细节:一是parseFloat后面要跟|| 0,防止用户清空输入框时得到NaN;二是每次行小计变化都要触发合计重算,否则底部总金额对不上。原型阶段这些计算逻辑虽然不接后端,但演示时业务方一定会盯着数字看,算错了很尴尬。
3.4 库存预警页的状态可视化
库存预警页是供应链系统里视觉反馈最重的页面。这套原型用颜色标签和进度条来区分库存状态:正常(绿色)、低于安全库存(橙色)、缺货(红色)。核心渲染逻辑:
// inventory/stock-alert.js —— 库存状态判定与渲染 function getStockLevel(current, safety) { if (current <= 0) return { level: 'danger', text: '缺货' }; if (current < safety) return { level: 'warning', text: '低于安全库存' }; return { level: 'normal', text: '正常' }; } function renderStockRow(item) { var status = getStockLevel(item.currentQty, item.safetyQty); var percent = Math.min(100, (item.currentQty / item.safetyQty) * 100); return '<tr>' + '<td>' + item.productName + '</td>' + '<td>' + item.currentQty + '</td>' + '<td>' + item.safetyQty + '</td>' + '<td><span class="status-tag status-' + status.level + '">' + status.text + '</span></td>' + '<td><div class="progress-bar">' + '<div class="progress-fill progress-' + status.level + '" ' + 'style="width:' + percent + '%"></div>' + '</div></td>' + '</tr>'; }进度条宽度用Math.min(100, ...)限制,防止库存远超安全值时进度条溢出容器。状态标签和进度条共用同一套status-*和progress-*类名,样式在components.css里集中定义,改配色时只改一处。
4. 避坑与常见问题:静态原型最容易翻车的几个地方
4.1 路径问题导致样式和脚本加载失败
现象:本地双击打开页面正常,发给同事后对方打开是白板,样式全丢。
原因:CSS 和 JS 用了绝对路径(如/css/layout.css),或者用了file://协议下不支持的写法。静态原型没有服务器根目录的概念,绝对路径会指向磁盘根目录。
解决:所有资源引用统一用相对路径。同级目录用./,上级目录用../。比如supplier/list.html引用 CSS 要写../css/layout.css。如果原型要发给别人,建议在项目根目录放一个start.bat或说明文档,提示用浏览器直接打开index.html。
4.2 中文编码不一致导致乱码
现象:页面上的中文显示成问号或方块。
原因:HTML 文件保存时用了 GBK 编码,但<meta charset="UTF-8">声明的是 UTF-8,或者反过来。
解决:所有 HTML 文件统一用 UTF-8 保存,并在<head>第一行写<meta charset="UTF-8">。VS Code 右下角可以切换编码,切换后记得重新保存。如果已经乱码,用编辑器「以编码重新打开」功能修正后再另存。
4.3 表格列过多时横向溢出
现象:采购订单明细列数多,页面出现横向滚动条,侧边栏被挤走。
原因:表格没有设置最小宽度,或者外层容器没有overflow-x: auto。
解决:给表格外层包一个.table-wrapper,设置overflow-x: auto;表格本身设min-width,比如min-width: 900px。这样列多时表格内部横向滚动,不影响整体布局。
4.4 弹窗层级被遮挡
现象:点击「新增供应商」弹出模态框,但模态框被侧边栏或顶栏盖住。
原因:模态框的z-index低于侧边栏,或者模态框放在了有overflow: hidden的容器里。
解决:模态框的 HTML 直接放在<body>末尾,不要嵌套在内容区里;z-index设一个足够大的值(如 9999),并确保侧边栏和顶栏的z-index低于它。同时给模态框遮罩层设position: fixed; top: 0; left: 0; width: 100%; height: 100%。
4.5 演示时浏览器缓存旧样式
现象:改了 CSS 后刷新页面没变化,以为改错了文件。
原因:浏览器缓存了旧的 CSS 文件。
解决:开发阶段用Ctrl + F5强制刷新,或者在引用 CSS 时加版本参数,如layout.css?v=2。原型交付前记得把版本参数去掉或统一,避免混乱。
5. 二次开发与改造:把这套原型变成你自己的项目
5.1 替换品牌色和基础样式
这套原型的配色集中在css/components.css顶部的变量区(如果用了 CSS 变量)或者散落在各处的十六进制色值。改造第一步是把主色换掉。常见做法是在:root里定义变量:
:root { --primary-color: #1f2d3d; /* 侧边栏深色 */ --accent-color: #1890ff; /* 按钮、链接主色 */ --success-color: #52c41a; --warning-color: #faad14; --danger-color: #f5222d; --border-color: #e8e8e8; --bg-color: #f5f7fa; }然后把所有硬编码的颜色替换成var(--accent-color)这样的引用。改一处,全站生效。如果原型的 CSS 没有用变量,可以自己加一层,工作量不大但后续维护省心。
5.2 接入真实接口的改造路径
原型转真实项目,核心是把mock-data.js里的静态数组换成fetch请求。改造时建议保留 mock 数据作为降级方案:
// 改造后的数据获取函数 async function fetchSuppliers(params) { // 开发阶段:如果配置了 USE_MOCK,走本地数据 if (window.APP_CONFIG && window.APP_CONFIG.useMock) { return Promise.resolve(MOCK_SUPPLIERS); } var query = new URLSearchParams(params).toString(); var res = await fetch('/api/supplier/list?' + query); if (!res.ok) throw new Error('请求失败: ' + res.status); var json = await res.json(); return json.data; // 约定接口返回 { code, data, message } }这样在接口没通之前,把useMock设为true就能继续演示;接口通了改成false即可。参数用URLSearchParams拼接,避免手动拼字符串时漏掉encodeURIComponent导致中文参数出错。
5.3 从静态原型迁移到框架的时机判断
什么时候该把这套静态原型迁移到 Vue 或 React?我的经验是看三个信号:页面数量超过 20 个、多个页面需要共享复杂状态(比如购物车式的采购单草稿)、团队超过两人同时改前端。如果只是演示和确认需求,静态原型足够了。迁移时不用重写,把每个 HTML 页面拆成组件,CSS 直接复用,JavaScript 里的渲染逻辑改成框架的数据绑定即可。
5.4 一个具体的改造技巧:用 URL 参数驱动页面状态
静态原型里,详情页经常需要根据列表页点击的行来显示不同数据。没有路由的情况下,用 URL 参数是最简单的方案:
// supplier/detail.html 里读取 URL 参数 function getQueryParam(name) { var params = new URLSearchParams(window.location.search); return params.get(name); } var supplierCode = getQueryParam('code'); if (supplierCode) { // 从 mock 数据里找到对应供应商 var supplier = MOCK_SUPPLIERS.find(function (s) { return s.code === supplierCode; }); if (supplier) { document.getElementById('supplier-name').textContent = supplier.name; // ... 填充其他字段 } }这个技巧在原型阶段特别实用,演示时从列表点进详情,数据能对上,看起来就像真系统。改造时把这个逻辑换成接口请求即可,URL 参数的结构不用变。
从那以后我每次拿到静态原型,都强制先跑一遍「路径检查 + 编码检查 + 弹窗层级检查」这三步,再开始改样式。很多看起来是「样式写错了」的问题,其实是资源没加载进来。希望这套原型的拆解能帮你少走点弯路,拿到手就能跑起来、改起来。
本文还有配套的精品资源,点击获取