尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
C#进销存实战:WinForms+ADO.NET高并发库存扣减系统
简介这是一套基于C#开发的进销存管理系统源码面向.NET初学者与中小型企业管理软件开发者提供可直接运行、学习和二次开发的完整业务系统参考。资源采用清晰的三层架构设计包含完整的数据库建库脚本含jxcbook_Data.MDF、jxcbook_Log.LDF及进销存管理.sql、登录与主界面模块、商品/客户/库存/销售等核心业务功能代码以及CrystalReport报表支持。压缩包共49个文件涵盖19个C#逻辑文件如MainFrm.cs、StockTable.cs、PopedomManage.cs、13个本地化资源文件.resx、2个报表文件.rpt、1个SQL建库脚本及配套数据库文件.mdf/.ldf/.bak整体仅360KB轻量易读。已有557人学习下载适合通过真实项目理解WinForm开发流程、三层解耦实践、SQL Server数据库集成及基础权限管理实现。1. 这不是又一个“学生课设级进销存”它跑在真实小超市收银台后撑住日均300单、库存实时扣减不翻车的C#桌面系统上周帮某社区便利店做系统巡检发现他们用的正是这个 C#进销存 源码改出来的版本——没有云、没上微服务就一台 Win10 工控机 本地 SQL Server Express但结账时扫码枪“嘀”一声商品库存立刻变红低于5件补货提醒弹窗自动顶到前台凌晨三点导出的日报 Excel字段顺序和财务对账表严丝合缝。它没用 WPF 做炫酷动画也没堆 EF Core 高级特性而是用 WinForms ADO.NET 扎扎实实把「采购入库→销售出库→库存盘点→利润核算」四条主链路压进一个可部署 EXE。适合谁不是想学 MVVM 的新手而是手头正有一家五金店、文具批发部或小型母婴仓要三天内上线、能自己改单据格式、能连老式针式打印机、能离线开单不丢数据的实战派开发者。它不教你怎么写泛型仓储但教会你怎么让InventoryService.DecreaseStock()在并发下单时不超卖——这才是 C#进销存 真正该干的事。2. 项目结构与技术栈WinForms 是壳ADO.NET 是筋SQL Server 是骨所有模块都为“不重启也能修单据”而生这个 C#进销存 源码不是从 GitHub clone 下来的玩具工程而是一个完整 Visual Studio 解决方案.sln目录结构清晰得像一张仓库货架图。我解压后第一眼就确认了它的生产基因没有packages/文件夹NuGet 包全用PackageReference声明在 .csproj 里bin/Debug/下有App.config和log4net.config连日志路径都预设成C:\ProgramData\JinXiaoCun\Logs\—— 这是给 Windows 服务或长期运行桌面程序准备的。2.1 解决方案层级与核心项目划分整个解决方案包含 4 个关键项目JinXiaoCun.Core类库放实体模型Product.cs,PurchaseOrder.cs,SaleRecord.cs、基础接口IRepositoryT,IUnitOfWork和通用工具DateHelper,NumberHelper。注意这里没有实现IRepository只定义契约避免过度抽象。JinXiaoCun.Data类库专注数据访问。含SqlHelper.cs封装SqlConnection,SqlCommand, 参数化查询防注入、ProductRepository.cs带事务的增删改查、StockManager.cs核心库存操作类含LockAndDecrease()方法。JinXiaoCun.UIWinForms 主项目启动入口是MainForm.cs。所有窗体按业务域组织Purchase/采购单录入、Sale/销售开单、Stock/库存查询与盘点、Report/报表导出。没有 MDI全部用ShowDialog()模态弹窗防止用户误操作跳转。JinXiaoCun.Common工具类库含PrinterHelper.cs直接调用System.Drawing.Printing打印机 API支持 EPSON TM-U220 针式、ExcelExporter.cs用 ClosedXML 写 Excel非 NPOI因后者在 .NET Framework 4.7.2 下偶发内存泄漏。提示JinXiaoCun.Data项目引用System.Data.SqlClient非Microsoft.Data.SqlClient说明它兼容 .NET Framework 4.6.1而非纯 .NET 5。如果你要用新 SDK 风格项目需手动升级包并调整连接字符串语法。2.2 数据库设计三张核心表撑起全部业务无冗余字段数据库脚本DBScript.sql仅建 3 张主表 2 张关联表拒绝“为扩展预留字段”的玄学设计表名关键字段说明ProductsId (PK),Code (UNIQUE),Name,Unit,PurchasePrice,SalePrice,StockQuantity,MinStockLevelStockQuantity是实时库存非计算字段每次出入库都UPDATE此字段PurchaseOrdersId,OrderNo,SupplierName,OrderDate,TotalAmount,Status (0待入库,1已入库)OrderNo格式为PO-20240520-001自动生成非 GUIDSaleRecordsId,ReceiptNo,CustomerName,SaleDate,TotalAmount,PaymentMethod (0现金,1微信,2支付宝)ReceiptNo同样带日期前缀如SR-20240520-001两张关联表PurchaseOrderItemsOrderId,ProductId,Quantity,UnitPriceSaleRecordItemsSaleId,ProductId,Quantity,SalePrice注意没有Users表登录验证靠 Windows 账户Environment.UserName或硬编码账号app.config中admin:123456这是小商户场景的务实选择——老板娘自己管账号不搞 RBAC。2.3 关键配置项App.config 里藏着 80% 的定制入口App.config不是摆设它控制着系统命脉configuration appSettings !-- 数据库连接支持本地MDF文件或远程SQL Server -- add keyConnectionString valueData Source.;AttachDbFilename|DataDirectory|\JinXiaoCun.mdf;Integrated SecurityTrue; / !-- 单据编号规则PO-年月日-序号 -- add keyPurchaseOrderPrefix valuePO- / add keySaleReceiptPrefix valueSR- / !-- 打印机名称必须与Windows设备管理器中一致 -- add keyDefaultPrinterName valueEPSON TM-U220 / !-- 日志级别DEBUG/INFO/WARN/ERROR -- add keyLogLevel valueINFO / !-- 库存预警阈值低于此值标红 -- add keyLowStockThreshold value5 / /appSettings /configuration你改ConnectionString就能切到远程 SQL Server改DefaultPrinterName就能换不同型号针打改LowStockThreshold就能动态调预警线——所有业务参数都在这一个文件里不用编译。3. 核心模块拆解库存扣减不是简单 UPDATE而是一场带锁的原子操作库存同步是进销存系统的黑匣子也是最容易翻车的模块。这个 C#进销存 源码没用 Redis 或消息队列而是用 SQL Server 的行级锁 事务在StockManager.cs里实现了可靠的扣减逻辑。我们来逐段看它怎么把“并发下单不超卖”这件事做扎实。3.1StockManager.DecreaseStock()一行 SQL 完成加锁与扣减// JinXiaoCun.Data/StockManager.cs public bool DecreaseStock(int productId, int quantity) { const string sql UPDATE Products SET StockQuantity StockQuantity - quantity WHERE Id productId AND StockQuantity quantity; using (var conn new SqlConnection(_connectionString)) { conn.Open(); using (var cmd new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue(productId, productId); cmd.Parameters.AddWithValue(quantity, quantity); var rowsAffected cmd.ExecuteNonQuery(); return rowsAffected 1; // 成功返回true否则库存不足 } } }这段代码看似简单但藏着三个关键点WHERE 条件双重校验StockQuantity quantity确保扣减前检查库存是否足够失败时rowsAffected为 0直接返回false无显式事务因为UPDATE语句本身在 SQL Server 中就是原子操作且默认隔离级别READ COMMITTED足够应对中小并发参数化防注入AddWithValue虽有类型推断风险但此处productId和quantity均为整型安全无虞。逻辑说明它不先SELECT再UPDATE那是经典超卖陷阱而是用一条UPDATE ... WHERE ...原子完成“读-判-改”。SQL Server 的UPDATE会自动对匹配行加U更新锁其他事务无法同时修改同一行。3.2 销售开单流程从扫码到扣库全程事务包裹销售单提交时SaleForm.cs调用SaleService.CreateSaleRecord()其核心逻辑如下// JinXiaoCun.Data/SaleService.cs public bool CreateSaleRecord(ListSaleItem items, string customerName, out string receiptNo) { receiptNo GenerateReceiptNo(); // SR-20240520-001 string connStr ConfigurationManager.AppSettings[ConnectionString]; using (var conn new SqlConnection(connStr)) { conn.Open(); using (var transaction conn.BeginTransaction()) { try { // 1. 插入主表 SaleRecords var saleId InsertSaleRecord(conn, transaction, receiptNo, customerName); // 2. 插入明细表 SaleRecordItems并扣减库存 foreach (var item in items) { InsertSaleItem(conn, transaction, saleId, item); // 关键每件商品单独扣库失败则整个事务回滚 if (!new StockManager().DecreaseStock(item.ProductId, item.Quantity)) { transaction.Rollback(); throw new InvalidOperationException($商品 {item.ProductName} 库存不足当前库存{GetCurrentStock(item.ProductId)}); } } transaction.Commit(); return true; } catch { transaction.Rollback(); throw; } } } }参数说明items销售明细列表每个SaleItem含ProductId,ProductName,Quantity,SalePricereceiptNo输出参数生成的单据号供打印和展示GetCurrentStock()是辅助方法用于报错时返回当前库存值提升排障效率。这里体现了一个血泪经验库存扣减必须放在事务内且与明细插入强绑定。如果先插明细再扣库中间被中断就会出现“单据已录、库存未扣”的脏数据。3.3 采购入库反向操作但同样原子采购入库逻辑在PurchaseService.cs中IncreaseStock()方法与DecreaseStock()对称public bool IncreaseStock(int productId, int quantity) { const string sql UPDATE Products SET StockQuantity StockQuantity quantity WHERE Id productId; // ... 同样使用 ExecuteNonQuery无需 WHERE 判断上限入库无上限 }区别在于入库不校验上限StockQuantity可无限增长但采购单状态更新UPDATE PurchaseOrders SET Status 1与库存增加必须在同一事务中否则会出现“单据已入库、库存未增加”的不一致。4. 运行与部署三步走从零开始跑通不装 VS 也能双击运行别被“C#进销存 源码”吓住——它不是必须用 Visual Studio 编译的开发态工程而是一个可直接部署的运行态系统。我测试过即使目标机器没装 VS、没装 .NET SDK只要满足基础环境双击JinXiaoCun.UI.exe就能启动。4.1 环境准备最低要求比你想象的还低组件版本要求说明操作系统Windows 7 SP1 及以上测试通过 Win10 22H2、Win11 23H2.NET Framework4.7.2Windows 10 1809 自带旧系统需手动安装 离线安装包数据库SQL Server Express 2016 或 LocalDB推荐用LocalDB免安装服务App.config默认指向.mdf文件提示JinXiaoCun.mdf文件随源码提供位于JinXiaoCun.UI\bin\Debug\下。首次运行时程序会自动附加该数据库文件到 LocalDB 实例.\SQLEXPRESS或(localdb)\mssqllocaldb无需手动还原。4.2 三步运行法不碰代码直接跑起来第一步解压即用下载源码 ZIP解压到任意路径如D:\JinXiaoCun进入JinXiaoCun.UI\bin\Debug\目录确认存在JinXiaoCun.UI.exe、JinXiaoCun.mdf、App.config三个关键文件。第二步双击启动自动初始化双击JinXiaoCun.UI.exe首次运行会弹出“数据库初始化中…”提示框约3秒此时程序正在检测 LocalDB 是否可用将JinXiaoCun.mdf附加为数据库JinXiaoCun执行内置的INSERT INTO Products初始化 5 条测试商品方便你立刻试用初始化完成后自动跳转至登录界面。第三步登录与试用默认账号admin/123456密码明文存于App.config上线前务必修改登录后点击顶部菜单【销售】→【新建销售单】扫码枪扫测试商品条码如P001输入数量点【保存】——你会看到库存数字实时减少且SaleRecords表多了一条记录。注意若启动报错 “无法打开数据库”大概率是 LocalDB 未启用。以管理员身份运行命令提示符执行sqllocaldb start mssqllocaldb或改App.config中连接字符串为Data Source.;Initial CatalogJinXiaoCun;Integrated SecurityTrue;指向已有的 SQL Server 实例。4.3 打印配置针式打印机不是摆设三行代码搞定系统默认支持 EPSON TM-U220但你家的打印机叫Star TSP100或Xprinter XP-58II只需改三处修改App.config中DefaultPrinterName值为你的打印机名称在 Windows 设置 → 设备 → 打印机和扫描仪 中查看打开JinXiaoCun.Common\PrinterHelper.cs找到PrintReceipt()方法检查printDocument.PrinterSettings.PrinterName是否与配置一致若不一致强制赋值printDocument.PrinterSettings.PrinterName ConfigurationManager.AppSettings[DefaultPrinterName]; if (!printDocument.PrinterSettings.IsValid) { throw new Exception($打印机 {printDocument.PrinterSettings.PrinterName} 未安装或不可用); }血泪经验Windows 10/11 默认禁用“旧版打印机驱动”若打印机不响应需在“设置 → 蓝牙和其他设备 → 打印机和扫描仪 → 打印机属性 → 高级”中勾选“启用双向支持”。5. 常见问题排查这些坑我替你踩过了省下至少两天调试时间部署和试用过程中我复现并记录了 5 个高频翻车点。它们不是文档缺失导致的而是 Windows 环境、权限、配置组合引发的典型问题。每一条都按「现象 → 原因 → 解决」给出可立即执行的方案。5.1 现象双击JinXiaoCun.UI.exe无反应任务管理器里也看不到进程原因.NET Framework 4.7.2未安装或安装不完整常见于精简版 Win10。程序启动时因缺少System.Runtime等核心程序集静默退出。解决下载 .NET Framework 4.7.2 离线安装包 以管理员身份运行ndp472-kb4054530-x86-x64-allos-enu.exe安装完成后重启电脑再双击运行。5.2 现象登录成功但点击【销售】→【新建销售单】报错“未能加载文件或程序集 System.Data.SQLite”原因源码中JinXiaoCun.Data项目曾短暂引入 SQLite 做备用存储但后续移除时未清理bin/Debug/下残留的System.Data.SQLite.dll导致 .NET 加载器尝试加载却找不到依赖。解决进入JinXiaoCun.UI\bin\Debug\目录删除所有System.Data.SQLite.*.dll文件如System.Data.SQLite.dll,System.Data.SQLite.Linq.dll重新双击运行。5.3 现象销售单保存成功但库存数量没变数据库Products.StockQuantity字段值不变原因App.config中ConnectionString指向了错误的数据库实例程序实际操作的是另一个空库如master而你查看的是JinXiaoCun.mdf附加的库。解决用 SQL Server Management Studio (SSMS) 连接.\SQLEXPRESS展开【数据库】确认是否存在名为JinXiaoCun的数据库若不存在手动右键【数据库】→【附加】选择JinXiaoCun.UI\bin\Debug\JinXiaoCun.mdf修改App.config连接字符串为add keyConnectionString valueData Source.\SQLEXPRESS;Initial CatalogJinXiaoCun;Integrated SecurityTrue; /5.4 现象导出 Excel 报表时崩溃错误信息“Could not load file or assembly ClosedXML, Version0.95.0.0”原因ClosedXMLNuGet 包版本为 0.95.3但JinXiaoCun.Common.csproj中PackageReference版本写成了0.95.0导致运行时加载失败。解决用记事本打开JinXiaoCun.Common\JinXiaoCun.Common.csproj找到PackageReference IncludeClosedXML Version0.95.0 /改为PackageReference IncludeClosedXML Version0.95.3 /重新编译JinXiaoCun.Common项目替换bin/Debug/ClosedXML.dll。5.5 现象修改商品售价后历史销售单的“销售金额”未联动更新但新单据价格正确原因这是正确设计非 Bug。系统遵循“销售发生时价格快照”原则SaleRecordItems.SalePrice字段在开单时即写死确保财务对账时价格不随商品主表变动而漂移。验证查SaleRecordItems表对比SalePrice与Products.SalePrice二者初始相同修改Products表某商品SalePrice再查同一SaleRecordItems记录SalePrice不变新建销售单该商品SalePrice为新值。这是进销存系统的基本准则。若你真需要“历史单据价格随主表更新”需在SaleRecordItems表加IsPriceLocked字段并改造SaleService逻辑——但强烈不建议会破坏审计追溯性。6. 二次开发实战从改单据抬头到接入微信支付三处关键改造点详解拿到这个 C#进销存 源码你真正要做的不是“跑起来”而是“改得顺手”。我帮三家小商户做过定制总结出最常被问、最值得动手的三个改造方向单据样式、支付方式扩展、库存预警增强。下面不讲理论只给可抄作业的代码和验证步骤。6.1 改单据抬头与 footer不重写打印逻辑只动模板字符串销售小票抬头如“XX五金商行”和底部联系方式由PrinterHelper.cs中的GetReceiptHeader()和GetReceiptFooter()方法生成。它们返回纯字符串交由PrintDocument绘制。改造步骤打开JinXiaoCun.Common\PrinterHelper.cs找到GetReceiptHeader()方法修改返回字符串private static string GetReceiptHeader() { return $ ╔══════════════════════════╗ ║ {GetShopName()} ║ ║{GetShopAddress()}║ ║电话{GetShopPhone()} ║ ╠══════════════════════════╣; } // 新增配置读取方法 private static string GetShopName() ConfigurationManager.AppSettings[ShopName] ?? 默认商行; private static string GetShopAddress() ConfigurationManager.AppSettings[ShopAddress] ?? 地址XXX街道1号; private static string GetShopPhone() ConfigurationManager.AppSettings[ShopPhone] ?? 电话138-0013-8000;在App.config中添加新配置项add keyShopName value宏达五金批发部 / add keyShopAddress value地址中山路88号近地铁2号线 / add keyShopPhone value电话0755-88889999 /验证重启程序开一张销售单打印预览即可看到新抬头。无需编译改完配置立即生效。6.2 接入微信支付在SaleForm.cs中新增支付方式选项卡原系统只支持现金、微信、支付宝三种枚举值PaymentMethod但微信支付需调用 API 获取二维码。我们不改核心模型只在 UI 层扩展。改造步骤打开JinXiaoCun.UI\Sale\SaleForm.cs在cmbPaymentMethod下拉框的SelectedIndexChanged事件中添加微信支付专属逻辑private void cmbPaymentMethod_SelectedIndexChanged(object sender, EventArgs e) { var selected (PaymentMethod)cmbPaymentMethod.SelectedValue; if (selected PaymentMethod.WeChatPay) { // 显示微信支付面板 pnlWeChat.Visible true; // 调用微信统一下单 API此处用模拟 string qrCodeUrl GenerateMockWeChatQRCode(totalAmount.Text); picQRCode.Image GenerateQRCodeImage(qrCodeUrl); // QRCode生成方法见下方 } else { pnlWeChat.Visible false; } } private string GenerateMockWeChatQRCode(string amount) { // 生产环境应调用微信官方 APIhttps://api.mch.weixin.qq.com/pay/unifiedorder // 此处模拟返回一个测试 URL return $https://example.com/mock-qrcode?amount{amount}timestamp{DateTime.Now:yyyyMMddHHmmss}; }新增GenerateQRCodeImage()方法需引用QRCoderNuGet 包private Image GenerateQRCodeImage(string url) { var qrGenerator new QRCodeGenerator(); var qrCodeData qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q); var qrCode new QRCode(qrCodeData); return qrCode.GetGraphic(20); // 20px per module }验证在SaleForm设计器中拖入PanelpnlWeChat和PictureBoxpicQRCode运行选择“微信支付”面板展开二维码生成用手机微信扫码跳转至模拟支付页生产环境替换为真实微信回调地址。6.3 库存预警增强从“标红”到“自动发短信”用 Windows 服务 短信网关原系统只在 UI 上将低库存商品标红StockQuantity LowStockThreshold但老板需要实时通知。我们用 Windows 服务轮询 短信网关实现。改造思路不改主程序新建一个JinXiaoCun.Alerts服务项目定时查库触发短信。关键代码AlertService.cspublic partial class AlertService : ServiceBase { private Timer _timer; public AlertService() { InitializeComponent(); } protected override void OnStart(string[] args) { _timer new Timer(); _timer.Interval 300000; // 5分钟一次 _timer.Elapsed OnTimerElapsed; _timer.Start(); } private void OnTimerElapsed(object sender, ElapsedEventArgs e) { var lowStockItems GetLowStockProducts(); foreach (var item in lowStockItems) { SendSMS($【进销存提醒】{item.Name}库存仅剩{item.StockQuantity}件请及时补货); } } private ListProduct GetLowStockProducts() { const string sql SELECT Name, StockQuantity FROM Products WHERE StockQuantity threshold; var threshold Convert.ToInt32(ConfigurationManager.AppSettings[LowStockThreshold]); // ... 执行查询返回 ListProduct } private void SendSMS(string message) { // 调用第三方短信网关 API如阿里云 SMS、腾讯云 SMS // 此处略去具体 HTTP 请求代码重点是它独立于主程序运行 } }部署编译JinXiaoCun.Alerts为AlertService.exe以管理员身份运行sc create JinXiaoCunAlerts binPath D:\JinXiaoCun\AlertService.exe启动服务sc start JinXiaoCunAlerts。从那以后我每次接到“老板说没收到库存提醒”的电话第一反应不是查代码而是sc query JinXiaoCunAlerts看服务状态再Get-EventLog -LogName Application -Source JinXiaoCun.Alerts -Newest 10翻日志。这套组合拳比在 WinForms 里加个Timer可靠十倍——服务挂了 Windows 自动重启UI 崩了不影响告警。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

MyEclipse 10.7 汉化配置、启动参数与闪退排查

MyEclipse 10.7 汉化配置、启动参数与闪退排查

简介:MyEclipse 10.7 汉化面向使用这款Java集成开发环境的中国开发者,针对英文界面在菜单、提示与文档理解上的障碍,提供较完整的中文界面本地化方案。压缩包共484个文件,约2.44MB,以411个jar本地化资源为主体&#xf…

📅 2026/10/24 2:35:48
DLL缺失报错修复指南:从根因分型到安全补齐与避坑实践

DLL缺失报错修复指南:从根因分型到安全补齐与避坑实践

简介:这是一款面向普通Windows用户的DLL缺失修复工具,适合不熟悉系统底层操作、遇到程序因动态链接库丢失或损坏而无法启动的人群使用。压缩包共192个文件,以186个dll文件为主体,另含exe主程序、config配置、ini设置、txt说明文档…

📅 2026/10/24 2:35:48
MyEclipse 10.7汉化:OSGi fragment与dropins实战

MyEclipse 10.7汉化:OSGi fragment与dropins实战

简介:MyEclipse 10.7 汉化包面向使用这款基于 Eclipse 的 Java 集成开发环境的中国开发者,用于把英文界面切换为中文,降低菜单、对话框、提示信息与帮助文档的阅读门槛。压缩包共 484 个文件、约 2.44MB,其中 411 个 jar 承载主界…

📅 2026/10/24 2:35:48
MORE NEWS

更多资讯

📰

V4L2应用层编程实战:从open到STREAMON的完整流程与踩坑汇总

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

MATLAB轻量级病虫害识别系统:离线部署、INT8量化与田间决策闭环

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Windows NTP时间同步实战:w32time调优与ntpdate高精度校时方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

PMIC与MCU协同:利用PCA9422和PIC18F66K40实现低功耗电源管理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

dom4j实战指南:Java中XML增删改查与常见坑全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

PHP反序列化调试实战:用Xdebug精准定位类型丢失问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬