
简介这份供应链系统页面原型资源面向产品经理、UI设计师、前端开发者及供应链业务人员用于在开发前期直观呈现采购、库存、生产计划、物流配送、销售分销、财务与报表分析等核心模块的界面布局与交互流程帮助团队在需求沟通与方案评审阶段快速对齐认知。压缩包共299个文件约661KB以87个html页面为主体辅以126个gif与43个png界面素材、14张jpg配图以及少量js、css、scc样式脚本和3个xlsx数据表覆盖登录、菜单、表单、图表等典型页面元素。目前已有1175人学习下载。通过逐页浏览原型读者可梳理各模块的字段、按钮与导航关系理解供应链流程如何串联为后续视觉设计与功能开发提供可复用的参考蓝本降低沟通与返工成本。1. 供应链系统页面原型从一堆静态 HTML 到能跑的业务骨架很多做后台管理系统的开发者都遇到过这种场景产品经理丢过来一句“先出个供应链系统的页面原型”然后就没有然后了。没有设计稿没有接口文档甚至连字段定义都没对齐。这时候如果直接上框架写组件大概率是白干——需求一变组件全废。我一般会先用纯 HTML CSS 把核心页面搭出来不依赖任何构建工具双击就能在浏览器里看效果。这份供应链系统页面原型就是干这个的它把供应商管理、采购订单、库存看板、物流跟踪这几个高频模块的页面结构全部用静态 HTML 铺开适合需要快速对齐需求的前端、需要给客户演示的产品以及想学后台布局的新手。拿到手就能改改完就能给业务方看省掉大量来回扯皮的时间。2. 技术选型与目录结构为什么不用框架反而更合适2.1 纯 HTML 方案的取舍逻辑供应链系统的页面原型和普通官网不一样它的核心诉求是“结构清晰、字段密集、表格多”。用 Vue 或 React 写当然可以但引入构建工具之后改一个字段名要等热更新给非技术同事看还要教他们装环境。纯 HTML 方案的好处是零门槛浏览器打开就能看记事本就能改发给谁都能直接跑。常见做法是用一套轻量 CSS 框架打底比如 Bootstrap 或者 Tailwind 的 CDN 版本再配合少量自定义样式。这样既保证了表格、表单、卡片的视觉一致性又不用自己从零写栅格。我一般会在head里直接引 CDN不搞本地构建保证文件拷到任何地方都能用。!-- 页面头部引入 CDN 样式与图标库 -- head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title供应链管理系统 - 采购订单/title !-- Bootstrap 负责栅格与基础组件样式 -- link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/css/bootstrap.min.css !-- 图标库用于侧边栏与操作按钮 -- link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap-icons1.10.0/font/bootstrap-icons.css !-- 自定义样式覆盖放在最后保证优先级 -- link relstylesheet href../css/custom.css /head这段代码的关键点在于加载顺序Bootstrap 先加载自定义样式后加载这样custom.css里的规则才能覆盖框架默认值。图标库单独引入是因为供应链系统里大量用到“编辑”“删除”“查看详情”这类操作按钮纯文字太占地方。参数上viewport那行不能省否则在平板上看表格会挤成一团。2.2 目录结构怎么划分才不乱原型项目最怕的就是文件堆在一起改了一个页面找不到对应的样式。我一般按“页面 资源”两个维度来分supply-chain-prototype/ ├── index.html # 登录页入口 ├── pages/ │ ├── supplier-list.html # 供应商列表 │ ├── purchase-order.html # 采购订单管理 │ ├── inventory.html # 库存看板 │ └── logistics.html # 物流跟踪 ├── css/ │ ├── bootstrap.min.css # 框架样式本地备份 │ └── custom.css # 项目自定义样式 ├── js/ │ ├── mock-data.js # 模拟数据方便演示 │ └── common.js # 公共交互逻辑 └── assets/ └── logo.png # 系统 Logo这个结构的好处是页面和资源分离pages/下每个文件对应一个业务模块css/和js/放公共依赖。mock-data.js是我强烈建议保留的因为原型阶段没有后端表格里的数据全靠它撑场面。改数据不用动 HTML 结构演示的时候直接改 JS 数组就行。2.3 页面之间的跳转关系原型不是孤立的页面供应链系统的核心链路是“供应商 → 采购订单 → 库存 → 物流”。在supplier-list.html里点击某个供应商的“查看订单”应该跳到purchase-order.html并带上供应商 ID。纯 HTML 方案里用 URL 参数传递// common.js统一的页面跳转方法携带业务参数 function navigateTo(page, params) { // 将参数对象拼接成 URL 查询字符串 const query new URLSearchParams(params).toString(); // 跳转到目标页面例如 purchase-order.html?supplierId1001 window.location.href ${page}?${query}; } // 在供应商列表页调用 document.querySelectorAll(.btn-view-order).forEach(btn { btn.addEventListener(click, () { // 从按钮的 data 属性读取供应商 ID const supplierId btn.dataset.supplierId; navigateTo(purchase-order.html, { supplierId }); }); });URLSearchParams会自动处理编码问题比手动拼字符串靠谱。>!-- 供应商列表表格支持横向滚动避免字段过多时挤压 -- div classtable-responsive table classtable table-hover table-striped align-middle thead classtable-dark tr th scopecol供应商编码/th th scopecol供应商名称/th th scopecol联系人/th th scopecol联系电话/th th scopecol合作状态/th th scopecol最近订单/th th scopecol classtext-center操作/th /tr /thead tbody idsupplierTableBody !-- 数据由 mock-data.js 动态渲染保持 HTML 干净 -- /tbody /table /divtable-responsive是必须加的供应链系统的表格字段通常超过 8 列不加这个在小屏幕上会溢出。align-middle让单元格内容垂直居中视觉上更整齐。thead用table-dark深色背景和内容区形成对比方便快速定位表头。tbody留空由 JS 动态填充这样改数据不用动 HTML。3.2 用 mock 数据渲染表格行原型阶段没有后端但表格不能空着。我一般会在mock-data.js里定义一个数组字段名和表头一一对应然后用map生成 HTML 字符串插入tbody。// mock-data.js供应商模拟数据字段与表格列对应 const suppliers [ { code: SUP-1001, name: 华东电子元件厂, contact: 张工, phone: 13800001111, status: 合作中, lastOrder: 2025-03-12 }, { code: SUP-1002, name: 南方物流包装有限公司, contact: 李经理, phone: 13900002222, status: 待审核, lastOrder: — }, { code: SUP-1003, name: 西部原材料供应站, contact: 王主管, phone: 13700003333, status: 已暂停, lastOrder: 2024-11-05 } ]; // 渲染供应商表格 function renderSupplierTable() { const tbody document.getElementById(supplierTableBody); if (!tbody) return; // 根据合作状态生成不同颜色的徽章 const statusBadge (status) { const map { 合作中: success, 待审核: warning, 已暂停: secondary }; return span classbadge bg-${map[status] || secondary}${status}/span; }; tbody.innerHTML suppliers.map(s tr td${s.code}/td td${s.name}/td td${s.contact}/td td${s.phone}/td td${statusBadge(s.status)}/td td${s.lastOrder}/td td classtext-center button classbtn btn-sm btn-outline-primary btn-view-order>!-- 采购订单筛选栏供应商下拉 状态筛选 日期范围 -- div classrow g-3 mb-4 div classcol-md-3 label classform-label供应商/label select classform-select idfilterSupplier option value全部供应商/option !-- 选项由 JS 从 mock 数据生成 -- /select /div div classcol-md-3 label classform-label订单状态/label select classform-select idfilterStatus option value全部状态/option option valuepending待确认/option option valueshipped已发货/option option valuereceived已入库/option /select /div div classcol-md-4 label classform-label下单日期/label input typedate classform-control idfilterDate /div div classcol-md-2 d-flex align-items-end button classbtn btn-primary w-100 idbtnFilter筛选/button /div /div筛选栏用 Bootstrap 的栅格系统分成四列g-3控制列间距。供应商下拉的选项不是写死的而是从suppliers数组动态生成这样新增供应商时不用改 HTML。筛选按钮绑定点击事件后根据当前选中的条件过滤orders数组重新渲染表格。原型阶段不需要真实请求但交互逻辑要完整否则演示时点按钮没反应会很尴尬。// 根据筛选条件过滤订单并重新渲染 function filterOrders() { const supplierCode document.getElementById(filterSupplier).value; const status document.getElementById(filterStatus).value; const date document.getElementById(filterDate).value; // 逐条件过滤条件为空时跳过 const filtered orders.filter(o { if (supplierCode o.supplierCode ! supplierCode) return false; if (status o.status ! status) return false; if (date o.orderDate ! date) return false; return true; }); renderOrderTable(filtered); } // 绑定筛选按钮事件 document.getElementById(btnFilter).addEventListener(click, filterOrders);filter里的三个if是典型的链式过滤写法每个条件独立判断互不影响。renderOrderTable接收过滤后的数组内部逻辑和供应商表格类似只是列不同。这种写法在原型阶段足够用后期接真实接口时只需要把orders换成fetch返回的数据即可。4. 避坑与常见问题原型阶段最容易翻车的几个点4.1 表格字段太多导致横向溢出现象在 1366px 宽度的笔记本上打开采购订单页表格右侧的“操作”列被截断按钮点不到。原因字段超过 10 列时即使加了table-responsive如果容器宽度不够仍然会出现滚动条不明显或者布局错乱。解决给表格设置min-width强制触发横向滚动同时把不重要的列在原型阶段隐藏只保留核心字段。/* custom.css表格最小宽度保证字段不被挤压 */ .table-responsive table { min-width: 1200px; /* 根据实际字段数量调整 */ }4.2 动态渲染后事件绑定失效现象用innerHTML渲染表格后之前用querySelectorAll绑定的按钮点击事件全部失效。原因innerHTML会销毁原有 DOM 节点重新创建新节点旧的事件监听器自然不存在了。解决要么在渲染完成后再绑定事件要么用事件委托把监听器挂在tbody上。// 事件委托监听 tbody 上的点击通过 target 判断来源 document.getElementById(supplierTableBody).addEventListener(click, (e) { if (e.target.classList.contains(btn-view-order)) { const supplierId e.target.dataset.supplierId; navigateTo(purchase-order.html, { supplierId }); } });4.3 日期格式不统一导致筛选失败现象筛选日期时选了2025-03-12但订单数据里的日期是2025/03/12导致过滤结果为空。原因input typedate返回的格式固定是YYYY-MM-DD而 mock 数据里手写的日期格式不统一。解决在mock-data.js里统一用YYYY-MM-DD格式或者在过滤前做一次格式转换。4.4 页面跳转后参数丢失现象从供应商列表跳到采购订单页URL 里带了supplierId但页面加载后筛选下拉没有选中对应供应商。原因目标页面没有在DOMContentLoaded里读取 URL 参数并设置下拉框的值。解决在目标页面的初始化逻辑里加一段参数回填。// 采购订单页初始化读取 URL 参数并回填筛选条件 document.addEventListener(DOMContentLoaded, () { const params new URLSearchParams(location.search); const supplierId params.get(supplierId); if (supplierId) { document.getElementById(filterSupplier).value supplierId; filterOrders(); // 立即执行一次筛选 } });4.5 CDN 资源加载失败导致样式全丢现象把原型发给同事对方打开后页面没有任何样式表格变成纯文本堆叠。原因对方网络环境访问不了 CDNBootstrap 和图标库加载失败。解决把 CDN 文件下载到本地css/和js/目录引用相对路径。原型项目体积不大本地化之后拷 U 盘都能跑。5. 二次开发与改造从静态原型到可交互 Demo 的升级路径5.1 把 mock 数据抽成独立 JSON 文件原型跑通之后下一步通常是让数据可配置。我一般会把mock-data.js里的数组抽成独立的.json文件用fetch加载。这样做的好处是产品和业务方可以直接改 JSON 文件不用碰 JS 代码。// 从 JSON 文件加载供应商数据 async function loadSuppliers() { const res await fetch(../data/suppliers.json); if (!res.ok) throw new Error(数据加载失败); return res.json(); } // 使用示例 loadSuppliers().then(data { suppliers data; // 替换全局变量 renderSupplierTable(); }).catch(err { console.error(err); // 降级使用内置的默认数据 });fetch返回的是 Promise用async/await写更直观。res.ok判断 HTTP 状态码是否在 200-299 之间失败时抛出异常。.catch里做降级处理保证 JSON 文件缺失时页面仍然能显示默认数据。这个改造点适合已经确定字段结构的项目如果字段还在频繁变动建议先保持 JS 内联。5.2 引入轻量路由实现页面无刷新切换纯 HTML 多页面方案在页面跳转时会白屏一下体验不够流畅。如果想让原型更接近真实系统可以引入一个轻量路由库比如page.js或navigo把多个页面合并成单页应用。改造步骤不复杂把每个页面的内容抽成template或 JS 模板字符串路由根据 URL 切换渲染内容。// 使用 page.js 定义路由规则 page(/, () renderPage(login)); page(/supplier, () renderPage(supplierList)); page(/order, () renderPage(purchaseOrder)); page(/inventory, () renderPage(inventory)); page.start(); // 渲染函数根据页面名称加载对应模板 function renderPage(name) { const app document.getElementById(app); const templates { supplierList: document.getElementById(tpl-supplier).innerHTML, purchaseOrder: document.getElementById(tpl-order).innerHTML, inventory: document.getElementById(tpl-inventory).innerHTML }; app.innerHTML templates[name] || p页面不存在/p; // 渲染后重新绑定事件 bindEvents(name); }page.js的 API 很简洁page(/path, callback)定义路由page.start()启动监听。renderPage从template标签里读取 HTML 片段插入主容器。注意每次渲染后要重新绑定事件因为 DOM 被替换了。这个改造适合原型已经稳定、需要给客户做演示的场景如果只是内部对齐需求多页面方案更省事。5.3 用 CSS 变量统一主题色供应链系统的页面多如果每个页面都写死颜色值后期换主题会改到崩溃。我一般会在custom.css里定义一组 CSS 变量所有页面引用变量而不是具体色值。/* custom.css主题变量定义 */ :root { --primary-color: #0d6efd; /* 主色调用于按钮和链接 */ --sidebar-bg: #1a1d21; /* 侧边栏背景 */ --table-header-bg: #343a40; /* 表头背景 */ --success-color: #198754; /* 成功状态 */ --warning-color: #ffc107; /* 警告状态 */ } /* 使用变量 */ .sidebar { background-color: var(--sidebar-bg); } .btn-primary { background-color: var(--primary-color); border-color: var(--primary-color); }改主题时只需要改:root里的几个值全站生效。这个技巧在原型阶段可能觉得多余但一旦项目进入迭代期省下的时间非常可观。我一般会在项目启动时就加上后面不管怎么改需求颜色始终统一。5.4 验证改造是否成功的三个检查点改完之后怎么确认没改坏我习惯走一遍这三个检查点第一打开浏览器控制台看有没有 404 或 JS 报错第二把每个页面的核心交互点一遍筛选、跳转、按钮点击是否正常第三把窗口缩到 768px 宽看表格和筛选栏有没有错位。这三个检查点花不了五分钟但能挡住大部分低级问题。提示改造过程中如果遇到fetch跨域问题不要急着搭后端先把 JSON 文件放在和 HTML 同目录下用相对路径加载。原型阶段不需要处理跨域那是接真实接口时才需要考虑的事。从那以后我每次交付原型之前都会强制走一遍“控制台无报错、核心交互全通、窄屏不错位”这三步踩过的坑多了就变成了肌肉记忆。希望帮到你。本文还有配套的精品资源点击获取