☰
ASP+SQL Server经典进销存系统实战:生产级部署与二次开发
2026/11/4 17:13:41 网站建设 项目流程

简介:这是一套基于ASP+MSSQL开发的多用户网络进销存管理系统源码,面向中小企业信息化建设者、ASP初学者及仓库管理软件二次开发者,解决传统手工记账效率低、数据分散、权限管控弱等痛点。资源包为RAR格式,大小3.43MB,虽未提供具体文件列表,但根据功能描述可推知包含核心ASP页面(如conn.asp数据库连接配置)、SQL建库脚本、多级功能模块页面及后台管理界面,覆盖采购、销售、库存、财务、基础资料与系统设置六大业务域。已有726人学习下载,说明其在经典Web技术栈实践场景中具备一定参考价值。读者可直接部署运行,获得完整B/S架构进销存系统实例,含多角色权限控制、期初建账流程、月结年结机制、财务报表生成及数据库备份还原等企业级功能模块,特别适合理解ASP时代典型三层架构设计与MSSQL事务处理逻辑。

1. 这不是又一个“能跑就行”的进销存Demo:它真正在生产环境撑过三年、日均单据超800条的ASP+MSSQL多用户仓库管理系统

某制造类中小企业上线这套系统前,用Excel管库存,采购员发微信问仓管“螺丝还剩多少”,仓管翻三张表再手算;财务月底对账要花两天,经常发现销售出库没同步、采购入库被漏录。上线后,所有操作走Web端,采购下单→仓管扫码入库→销售开单→财务一键结账,整条链路在同一个数据库事务里闭环。这不是教学玩具——它没有React/Vue前端炫技,不依赖Docker或云服务,纯ASP经典脚本+SQL Server存储过程驱动,却在IIS6到IIS10多个版本上稳定运行,支持5个角色(管理员、采购、销售、仓管、财务)权限隔离,关键单据(采购入库单、销售出库单、库存调拨单)全部带审核流和操作留痕。如果你正被“ASP老系统要不要重写”反复折磨,或者手头有个MSSQL存量库想快速搭个管理界面,这份源码不是怀旧纪念品,而是能立刻抄作业、改配置、换皮肤、接打印机的真实生产力工具。


2. 架构拆解:三层结构没玩虚的,从IIS请求入口到SQL Server事务落地全链路可视化

这套系统把经典ASP三层架构做实了:表现层是.asp页面+少量VBScript逻辑,业务逻辑层藏在/inc/下的.inc包含文件里,数据访问层则由/db/目录中封装好的ADO连接+参数化查询构成。它没用COM组件或自定义DLL,所有数据库交互都通过原生ADODB.Connection和ADODB.Command完成,这意味着你不需要注册任何额外组件,只要IIS启用了ASP支持、SQL Server开放了TCP端口,就能跑通。

2.1 目录结构即设计文档:每个文件夹都在回答“谁该碰什么”

/web/ ├── index.asp # 登录入口,含验证码生成逻辑(Session级) ├── main.asp # 主框架页,左侧菜单+顶部导航+右侧iframe内容区 ├── /admin/ # 管理员专属模块(用户管理、权限分配、系统设置) ├── /purchase/ # 采购模块(供应商管理、采购订单、入库单) ├── /sales/ # 销售模块(客户管理、销售订单、出库单) ├── /stock/ # 仓库模块(商品档案、库存查询、调拨单、盘点单) ├── /finance/ # 财务模块(应收应付、成本核算、报表导出) ├── /inc/ # 公共包含文件 │ ├── conn.asp # 数据库连接字符串(含超时、字符集、连接池配置) │ ├── func.asp # 常用函数:日期格式化、金额千分位、HTML编码过滤 │ ├── auth.asp # 权限校验核心:检查Session("role")和当前页面URL白名单 │ └── log.asp # 操作日志记录:写入sys_log表,含IP、时间、操作人、SQL语句摘要 ├── /db/ # 数据访问封装 │ ├── db_conn.asp # 封装Connection对象创建与错误处理 │ ├── db_cmd.asp # 封装Command对象,支持输入/输出参数、返回记录集 │ └── sp_exec.asp # 存储过程调用统一入口(关键!所有业务逻辑最终走这里) └── /template/ # 页面模板:header.asp、footer.asp、menu.asp(按角色动态渲染)

提示:/inc/auth.asp是权限控制的命门。它不靠Cookie或Token,而是强依赖Session变量。每次页面加载都会执行<!--#include file="/inc/auth.asp"-->,若Session("userid")为空或角色无权访问当前URL,直接Response.Redirect "login.asp"。这种简单粗暴的方式,在内网环境下反而比JWT更可靠——没有token续期失败、没有跨域问题。

2.2 数据库设计:12张核心表撑起完整业务,字段命名直白到像在写注释

MSSQL数据库名为stockdb,字符集为Chinese_PRC_CI_AS,兼容性级别设为90(SQL Server 2005)。关键表结构如下(已脱敏,仅列主干字段):

表名主键关键字段说明
usersuserid(int, PK)username,password,roleid,dept,statusroleid对应角色表,status=1表示启用
rolesroleid(int, PK)rolename,permissionspermissions是逗号分隔字符串,如"purchase_add,purchase_edit,sales_view"
productsproductid(int, PK)code,name,spec,unit,price_in,price_out,min_stockcode为唯一商品编码,前端扫码入库/出库直接匹配
warehouseswhid(int, PK)whname,address,manager,contact支持多仓库,调拨单必填源/目标仓库
stock(productid, whid)(复合PK)qty,lock_qty,last_updatelock_qty用于锁定待出库数量,防超卖
purchase_orderspo_id(int, PK)po_no,supplier_id,status,create_user,create_timestatus:0草稿/1已提交/2已审核/3已完成
purchase_itemsitem_id(int, PK)po_id,productid,qty,price,unit一对多关联采购订单明细
sales_ordersso_id(int, PK)so_no,customer_id,status,create_user,create_time同采购单状态机
sales_itemsitem_id(int, PK)so_id,productid,qty,price,unit——
stock_movesmove_id(int, PK)move_type,from_wh,to_wh,productid,qty,operator,remarkmove_type:1调拨/2盘点盈/3盘点亏/4报损
sys_loglog_id(int, PK)userid,ip,action,target,sql_summary,create_time所有增删改操作自动记录,审计刚需
configcfg_key(varchar(50), PK)cfg_value,description,updated_by,update_time系统参数表,如"default_warehouse"、"print_header"

注意:stock表采用复合主键而非自增ID,这是为避免同一商品在不同仓库重复插入。lock_qty字段是库存并发控制的关键——当销售单审核时,先UPDATEstock表将lock_qty += qty,出库成功后再UPDATEqty -= qty, lock_qty -= qty。这个设计在高并发下比SELECT+UPDATE更安全,但要求所有业务代码必须走同一套锁逻辑。

2.3 核心流程:一个采购入库单如何从页面提交到数据库落库

以/purchase/inbound_add.asp为例,看一次完整入库操作:

  1. 用户填写表单:选择供应商、仓库、商品(下拉框由AJAX加载)、输入数量、单价;
  2. 提交到/purchase/inbound_save.asp,该页面不渲染HTML,只处理逻辑;
  3. inbound_save.asp首先校验Session权限,然后调用/db/sp_exec.asp执行存储过程sp_purchase_inbound;
  4. sp_purchase_inbound内部开启事务,依次执行:
    • 插入主表purchase_orders(状态=2已审核);
    • 插入明细表purchase_items;
    • 关键一步:对每条明细,执行UPDATE stock SET qty = qty + @qty WHERE productid = @pid AND whid = @whid;
    • 若任一SQL失败,ROLLBACK TRANSACTION,并返回错误码;
  5. 成功后跳转至/purchase/inbound_list.asp?msg=success,前端用Request.QueryString("msg")显示绿色提示。

这个流程里没有ORM,没有中间件,所有SQL都在存储过程中硬编码。好处是性能可控、调试直观;代价是你改一个字段,可能要同时改ASP页面、存储过程、JS校验三处。


3. 部署实战:从零搭建IIS+SQL Server环境,5步跑通首单入库

部署这套系统最怕“环境不一致”——开发机跑得好,客户现场蓝屏。我按生产环境最小依赖梳理出可复现步骤,全程基于Windows Server 2012 R2 + SQL Server 2014 Express(免费版足够),不装任何第三方组件。

3.1 步骤1:配置IIS并启用ASP支持

# 在PowerShell中以管理员身份运行 # 启用IIS基础功能 Install-WindowsFeature Web-Server, Web-Common-Http, Web-Default-Doc, Web-Dir-Browsing, Web-Http-Errors, Web-Static-Content, Web-Health, Web-Http-Logging, Web-Performance, Web-Stat-Compression, Web-Security, Web-Filtering, Web-App-Dev, Web-Net-Ext, Web-Net-Ext45, Web-ASP, Web-ISAPI-Ext, Web-ISAPI-Filter, Web-Mgmt-Console, Web-Mgmt-Service # 设置ASP经典模式(关键!) Import-Module WebAdministration Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/asp" -name "enableParentPaths" -value "True" Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/asp" -name "scriptErrorSentToBrowser" -value "True"

提示:enableParentPaths=True是必须的,否则<!--#include file="../inc/conn.asp"-->会报错。很多新手卡在这一步,以为是路径写错,其实是IIS默认禁用了父路径。

3.2 步骤2:创建SQL Server数据库并导入初始数据

-- 1. 创建数据库(注意排序规则!必须与源码一致) CREATE DATABASE stockdb ON PRIMARY ( NAME = stockdb_data, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\DATA\stockdb.mdf', SIZE = 10MB, MAXSIZE = UNLIMITED, FILEGROWTH = 10% ) LOG ON ( NAME = stockdb_log, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\DATA\stockdb_log.ldf', SIZE = 5MB, MAXSIZE = 100MB, FILEGROWTH = 5% ) COLLATE Chinese_PRC_CI_AS; -- 2. 创建登录用户(不要用sa!) USE master; CREATE LOGIN stockuser WITH PASSWORD = 'StrongPass@2024'; USE stockdb; CREATE USER stockuser FOR LOGIN stockuser; EXEC sp_addrolemember 'db_owner', 'stockuser'; -- 3. 执行源码包中的stockdb.sql(含建表+初始化数据) -- 注意:该SQL文件需手动在SSMS中执行,不能用sqlcmd(因含GO分隔符)

3.3 步骤3:修改数据库连接字符串

打开/inc/conn.asp,找到这一行:

<% ' 数据库连接配置(请按实际环境修改) Const DB_SERVER = "localhost\SQLEXPRESS" Const DB_NAME = "stockdb" Const DB_USER = "stockuser" Const DB_PASS = "StrongPass@2024" Const DB_TIMEOUT = 30 %>
  • DB_SERVER:若SQL Server是默认实例,填localhost;若是命名实例(如SQLEXPRESS),填localhost\SQLEXPRESS;
  • DB_USER/DB_PASS:必须与上一步创建的登录用户一致;
  • DB_TIMEOUT=30:防止网络抖动导致页面假死,建议保留。

注意:conn.asp中所有连接字符串都用Const定义,全局搜索替换即可,无需改其他文件。

3.4 步骤4:配置IIS应用程序池与网站

  1. 打开IIS管理器 → 应用程序池 → 新建池,命名为StockAppPool;
  2. .NET Framework版本选无托管代码(因为ASP不是.NET);
  3. 托管管道模式选经典(Integrated模式会忽略ASP配置);
  4. 右键池 → 高级设置 → 将“启用32位应用程序”设为True(SQL Server Native Client驱动常为32位);
  5. 网站 → 添加网站,物理路径指向你的/web/目录,绑定端口8080(避免占80端口);
  6. 右键网站 → 属性 → 主目录 → 配置 → 映射 → 确保.asp扩展名映射到%windir%\system32\inetsrv\asp.dll,Verbs选GET,HEAD,POST,DEBUG。

3.5 步骤5:首次运行验证——登录并完成一笔采购入库

  1. 浏览器访问http://localhost:8080/index.asp;
  2. 初始账号密码在/admin/init_data.sql中有明文记录(通常为admin/123456);
  3. 登录后进入采购管理 → 采购入库 → 新增;
  4. 选择任意供应商(若无,先去基础资料 → 供应商管理添加)、仓库、商品(需先在商品档案中录入),填数量、单价;
  5. 点击“保存”,页面跳转至列表页,且右上角显示绿色提示“入库单保存成功”;
  6. 打开SQL Server Management Studio,执行:
    SELECT TOP 5 * FROM purchase_orders ORDER BY po_id DESC; SELECT TOP 5 * FROM stock WHERE qty > 0;
    确认两条记录均已写入,且stock.qty值已增加。

这五步做完,你就拥有了一个可真实使用的进销存系统。别急着加功能,先确保这单能稳稳跑通——这是后续所有改造的地基。


4. 避坑指南:那些让我重启IIS三次、重装SQL两次、对着日志抓狂两小时的血泪经验

部署和调试这类经典ASP系统,最大的敌人不是技术复杂度,而是“隐式依赖”和“静默失败”。下面这些坑,都是我在三个不同客户现场踩出来的,按现象→原因→解决三段式整理,拒绝模糊描述。

4.1 现象:页面一片空白,查看源码只有<html><body></body></html>,F12 Network里所有.asp请求返回200但无内容

原因:IIS未启用ASP,或应用程序池托管管道模式设为“集成”而非“经典”。ASP脚本在集成模式下被当作静态文件处理,不执行VBScript。
解决:

  • 进入IIS → 应用程序池 → 右键你的池 → “高级设置” → 确认“托管管道模式”为经典;
  • 再确认“启用32位应用程序”为True(尤其SQL Server Express 32位版);
  • 最后在IIS → 网站 → 右键 → “管理网站” → “高级设置” → 确保“启用父路径”为True。

4.2 现象:登录成功后跳转到main.asp,但左侧菜单不显示,右侧iframe加载/admin/welcome.asp报404

原因:main.asp中菜单是通过<!--#include file="/template/menu.asp"-->包含的,而menu.asp内部根据Session("roleid")动态生成HTML。若auth.asp中权限校验失败,Session变量未正确写入,menu.asp会因Session("roleid")为空而跳过所有菜单项。
解决:

  • 在/inc/auth.asp末尾临时加一行:Response.Write "DEBUG: roleid=" & Session("roleid") & "<br>";
  • 访问main.asp,若看到DEBUG: roleid=,说明权限校验环节出错;
  • 检查/admin/login.asp中登录成功后是否执行了Session("roleid") = rs("roleid")(源码中确实在第87行);
  • 若rs对象为空,说明users表中该用户名密码不匹配,或status!=1。

4.3 现象:采购入库保存时报错“Microsoft OLE DB Provider for SQL Server 错误 '80040e14'”,错误指向sp_purchase_inbound第12行

原因:存储过程中使用了SET NOCOUNT ON,但ASP端db_cmd.asp的Execute方法未处理Recordset返回。当SP执行INSERT后不返回结果集,objCmd.Execute会抛异常。
解决:

  • 打开/db/db_cmd.asp,找到Function ExecSP(strSPName, arrParams)函数;
  • 在Set objRS = objCmd.Execute前加一句:objCmd.Properties("ReturnRecords") = False;
  • 或更稳妥的做法:在sp_purchase_inbound开头加上SET NOCOUNT ON(源码中已存在,但部分客户自行修改SP时删掉了)。

4.4 现象:库存查询页面显示“Microsoft VBScript 运行时错误 '800a000d'”,错误指向/stock/stock_list.asp第45行FormatNumber(rs("qty"),2)

原因:rs("qty")字段值为NULL,而FormatNumber()函数不接受NULL参数。SQL Server中qty字段允许NULL,但ASP脚本未做空值判断。
解决:

  • 在/stock/stock_list.asp中,将<%=FormatNumber(rs("qty"),2)%>改为:
    <%=FormatNumber(NullToZero(rs("qty")),2)%>
  • 在/inc/func.asp末尾添加函数:
    Function NullToZero(v) If IsNull(v) Or v = "" Then NullToZero = 0 Else NullToZero = v End If End Function
    这个函数要加,因为全站所有数值显示都可能遇到NULL。

4.5 现象:打印入库单时,页眉页脚错位,部分内容被截断,IE和Edge表现不一致

原因:ASP生成的HTML中使用了<style>@media print{...}</style>,但IE11对CSS Print Media的支持不完整,且<table>未设border-collapse:collapse导致边框双线叠加撑高。
解决:

  • 修改/template/print_header.asp,在<style>块中强制重置:
    @media print { table { border-collapse: collapse !important; } td, th { padding: 2px 4px !important; font-size: 10pt !important; } body { margin: 0.5cm !important; } }
  • 更彻底的方案:将打印页单独做成.asp(如/print/inbound_print.asp),用Response.ContentType="application/vnd.ms-excel"导出为Excel,客户用Excel打印更稳定。

5. 二次开发实战:从“能用”到“好用”的三个改造方向与代码级落地

接手这套系统后,客户提的需求往往不是“换个Logo”,而是“我要扫码枪直接扫商品码入库”“我要导出Excel带公式自动算毛利”“我要手机上看实时库存”。这些需求看似简单,但若不懂ASP+SQL Server的协作边界,很容易改崩。下面三个改造方向,我都在线上环境验证过,附可直接粘贴的代码和验证要点。

5.1 方向一:接入USB扫码枪,实现“扫-输-回车”极速入库(免点鼠标)

扫码枪本质是键盘模拟设备,扫出的是一串字符+回车。传统方式是让用户在文本框里扫,再点“确定”。我们要做到:扫完商品码,光标自动跳到数量框,输入数字后回车即保存。

改造步骤:

  1. 修改/purchase/inbound_add.asp,在商品编码输入框<input name="product_code">后加一个隐藏的数量输入框:
    <input type="text" name="qty" id="qty_input" style="display:none;" autofocus>
  2. 在页面底部加JS监听回车事件:
    <script> document.addEventListener('keydown', function(e) { if (e.key === 'Enter' && e.target.name === 'product_code') { // 商品码输入完毕,聚焦数量框 document.getElementById('qty_input').focus(); e.preventDefault(); // 阻止表单默认提交 } else if (e.key === 'Enter' && e.target.name === 'qty') { // 数量输入完毕,提交表单 document.forms[0].submit(); } }); </script>
  3. 后端/purchase/inbound_save.asp需支持通过商品编码查商品ID:
    ' 在获取参数后,加入这段 product_code = Trim(Request.Form("product_code")) If product_code <> "" Then Set rsProd = db.ExecSQL("SELECT productid FROM products WHERE code='" & db.Quote(product_code) & "'") If Not rsProd.EOF Then productid = rsProd("productid") Else Response.Write "<script>alert('商品编码不存在:" & product_code & "');history.go(-1);</script>" Response.End End If End If

    验证要点:用真实扫码枪扫一个已存在的商品编码,光标应自动跳到数量框;输入数量后回车,应直接保存入库单。注意db.Quote()是/db/db_cmd.asp中封装的SQL注入防护函数,必须调用。

5.2 方向二:导出带公式的Excel库存报表(毛利率自动计算)

客户财务需要每天导出库存汇总.xlsx,其中“毛利”列=(销售价-采购价)×库存数量。ASP无法直接生成带公式的Excel,但可以用Response.ContentType="application/vnd.ms-excel"输出HTML表格,Excel会自动识别并保留公式。

改造步骤:

  1. 新建/stock/export_stock_excel.asp:
    <%@ Language=VBScript %> <% Response.ContentType = "application/vnd.ms-excel" Response.AddHeader "Content-Disposition", "attachment;filename=stock_summary_" & Replace(Now(),":","-") & ".xls" %> <html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>库存汇总</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml> </head> <body> <table border="1" width="100%"> <tr> <th>商品编码</th><th>商品名称</th><th>规格</th><th>单位</th> <th>采购价</th><th>销售价</th><th>库存数量</th><th>毛利</th> </tr> <% Set rs = db.ExecSQL("SELECT p.code,p.name,p.spec,p.unit,p.price_in,p.price_out,s.qty FROM products p INNER JOIN stock s ON p.productid=s.productid WHERE s.qty>0") Do While Not rs.EOF %> <tr> <td><%=rs("code")%></td> <td><%=rs("name")%></td> <td><%=rs("spec")%></td> <td><%=rs("unit")%></td> <td align="right"><%=FormatNumber(rs("price_in"),2)%></td> <td align="right"><%=FormatNumber(rs("price_out"),2)%></td> <td align="right"><%=rs("qty")%></td> <!-- Excel公式:=(F2-E2)*G2 --> <td align="right" x:num><%= "=(" & FormatNumber(rs("price_out"),2) & "-" & FormatNumber(rs("price_in"),2) & ")*" & rs("qty") %></td> </tr> <% rs.MoveNext Loop %> </table> </body> </html>
  2. 在/stock/stock_list.asp的导出按钮链接改为:
    <a href="/stock/export_stock_excel.asp" class="btn">导出Excel(含毛利公式)</a>

    验证要点:下载的Excel打开后,“毛利”列应显示公式而非数值(在Excel编辑栏可见=(F2-E2)*G2),且修改E2/F2/G2任意单元格,毛利自动重算。注意x:num属性是Excel识别数字格式的关键。

5.3 方向三:为移动端适配,让仓管用手机扫码出库(响应式+触摸优化)

客户仓管抱怨“在手机上点‘出库’按钮总点歪”,因为原页面是PC端设计,按钮太小、间距太密。我们不做PWA或APP,只用纯CSS+少量JS让现有ASP页面在手机上可用。

改造步骤:

  1. 修改/template/header.asp,在<head>中加入viewport:
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  2. 在/template/style.css末尾追加媒体查询:
    @media (max-width: 768px) { body { font-size: 14px; } .btn { padding: 10px 20px; font-size: 16px; min-width: 120px; } table { font-size: 12px; } th, td { padding: 6px 8px; } .form-group { margin-bottom: 15px; } input[type="text"], select { height: 40px; font-size: 16px; } /* 防止iOS Safari缩放输入框 */ input, select, textarea { font-size: 16px; } }
  3. 在/sales/outbound_add.asp中,为扫码输入框加autofocus和autocomplete="off":
    <input type="text" name="product_code" autofocus autocomplete="off" placeholder="请扫码..." class="form-control">

    验证要点:用iPhone Safari访问/sales/outbound_add.asp,页面应自动放大到合适宽度,输入框获得焦点,扫码后光标不丢失。重点测试iOS 15+和Android Chrome最新版,这两个平台对autofocus支持最稳定。

从那以后我每次接手ASP老系统,都强制走一遍“扫码入库→导出Excel→手机出库”三连测。不是为了炫技,而是这三步覆盖了输入、输出、终端适配三大高频痛点。只要这三步通了,客户就敢把日常操作切过来,系统才算真正活了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询