news 2026/10/10 8:10:44

仿金蝶ERP进销存系统:电商仓储落地方案与SQL Server数据架构解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
仿金蝶ERP进销存系统:电商仓储落地方案与SQL Server数据架构解析

简介:这是一套仿金蝶风格的电商ERP进销存系统源码,面向中小企业信息化管理人员、PHP开发学习者及二次开发工程师,可用于采购、销售、库存、财务等一体化管理场景,帮助理解ERP业务流程与进销存系统实现思路。压缩包共2168个文件,大小约41.98MB,以php后端逻辑、js前端交互、png图片资源为主体,配合css样式、html页面及sql数据库脚本,构成可直接部署运行的网站管理项目,附带readme说明、license授权文件、changelog更新记录等资料,便于对照学习与按模块改造。已有1160人浏览学习。压缩包内保留完整ChangLog版本记录与历史备份文件,可借此梳理系统演进脉络,掌握从订单处理、仓储管理到财务核算的核心代码组织方式,适合作为课程设计、毕业设计或小型企业ERP选型参考。

1. 仿金蝶电商ERP进销存系统:为什么这个方案在电商仓储里依然值得做

仿金蝶电商ERP进销存系统,这类以压缩包形式流通的软件在中小电商团队里并不少见。解压开,你看到的是一套仿照金蝶KIS操作习惯和界面布局开发的进销存软件,背后通常挂着一个SQL Server账套。它能解决的核心问题是:把采购、销售、库存和往来账从Excel表格里解放出来,做成有审核、有流水、能月结的正式业务账。适合三类人:刚起步想低成本引入ERP流程的电商老板,给传统批发贸易公司做信息化项目的实施顾问,以及想通过仿金蝶源码快速理解ERP数据模型的开发者。很多人以为“仿金蝶”是山寨,实际仿的是业务操作习惯,而这套习惯本身已经被大厂验证了二十多年。

2. “仿”在哪一层:从金蝶式菜单到数据字典,先摸清这套ERP的骨架

2.1 仿金蝶仿的是操作习惯:单据三段式才是分界线

金蝶KIS和K3的老用户都很熟悉主控台那种左侧菜单树、右侧业务窗口的布局,但真正有价值的不只是界面,而是单据处理流程:录入、审核、过账,三步分离。录入阶段单据可改可删;审核后业务生效,库存和往来账才会动;过账后生成会计分录,进入财务报表。仿金蝶系统如果把这套状态机抄到位,那它就能支撑正经的进销存业务;如果只抄了界面,审核过账按钮只是摆设,那它本质上还是带界面包装的Excel台账。

我拿到一套陌生系统时,不会先看代码,而是打开一张采购入库单,看按钮区域有没有“审核”“过账”“反过账”三个状态操作。有,说明数据完整性有保障;只有“保存”“删除”,后面接电商订单流时就要格外谨慎。市面上这类压缩包多数用Delphi 7配合SQL Server开发,金蝶早年产品也有大量Delphi技术积累,所以看到Delphi 7写着ERP源码不必抵触。Delphi 7在Win10以上系统里兼容性尚可,主要问题集中在报表控件和ODBC驱动,这个到第5章再展开。

还有一个容易被忽视的细节:主控台和权限是配套的。仿金蝶系统一般会给每个账号分配菜单权限、按钮权限和数据权限,按钮权限如果没放开,能看到“审核”字样但点下去没有任何反应。实施时先给admin账号全套权限,再用普通账号复验,能省掉很多“这系统是不是坏了”的排查时间。

2.2 数据字典是进销存的目录:一条 SQL 拉出全部表清单

要对一套陌生ERP做二次开发,第一步是查数据字典。仿金蝶系统的基础资料表常见t_Item、t_Supplier、t_Customer这样的命名,单据表常见t_SaleBill、t_POOrder、t_StockFlow,字段名常见FInterID(单据内码)、FBillNo(单号)、FStatus(状态:0未审、1已审)、FQty(数量)、FPrice(单价)、FAmount(金额)。其中FInterID是表头与明细表关联的外键,不是单号。能不能把表关系读懂,直接决定后续写同步接口时是走主键关联还是被单号重复坑到。

在SQL Server里先拉一遍模块相关的表和字段,这个动作花三分钟,但能避免后面改错表:

SELECT t.name AS 表名, c.name AS 字段名, tp.name AS 字段类型, c.max_length AS 长度, CAST(ep.value AS nvarchar(200)) AS 字段说明 FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id JOIN sys.types tp ON c.user_type_id = tp.user_type_id LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id AND ep.minor_id = c.column_id WHERE t.name LIKE '%Sale%' OR t.name LIKE '%PO%' OR t.name LIKE '%Inventory%' ORDER BY t.name, c.column_id;

这段SQL的作用是把销售、采购、库存三块的表和字段一次性列出来,包括设计时写的中文说明。参数说明:LIKE里的模块名按实际缩写改就行,比如订单模块叫Order、库存模块叫Stock;如果表里extended_properties没有中文说明,就把LEFT JOIN去掉,用字段名反推含义。重点看每个单据明细表的FInterID是否指向表头FInterID,这一步能立刻判断这套仿金蝶是否按标准主外键设计。很多半成品系统在这里翻车,明细表外键指向单号,单号一重复数据就串。

2.3 进销存主流程:三条业务线在表之间的流转

从数据模型回到业务,仿金蝶ERP的进销存本质上跑三条线,每一条线都是“单据→库存→资金”的映射:

业务线单据链库存影响财务影响
采购采购订单 → 采购入库单 → 应付单库存增加应付账款增加
销售销售订单 → 销售出库单 → 应收单库存减少应收账款增加
库存其他出入库 → 盘点单 → 月结库存调整成本差异

电商场景和线下贸易有个明显差别:订单粒度碎、退换货频繁、还有“仅退款不退货”的情况。所以销售环节往往需要四张单联动:销售订单、销售出库单、退货单、退款单。你先确认手头系统的销售退货是独立单据,还是用红字销售出库单代替。这个选择直接影响后续接口设计:独立单据要单独建流水,红字出库则只要允许负数出库,业务模型完全不同。

2.4 账套与会计期间:登录以后先确认这三项再动业务

初始化之前,还有一件很多人忽略的事:账套期间。仿金蝶系统一般把账套按年划分,每个月有独立的会计期间,比如2025年1期。登录后先去看“系统设置→账套选项”里的启用年度、启用期间和当前期间。当前期间决定了所有单据的默认日期,如果把一张上个月的单子录在这个月,审核后就会落到本月,月末对账就很难受。

另一个要确认的是“是否允许修改已审核单据”这个参数。金蝶原生逻辑审核后不能直接改,只能通过红蓝字冲销或者反审核。仿品有时为了操作方便,默认允许修改,这对数据安全是坏消息。我一般会把允许修改关掉,宁可让操作员多走一次反审核流程,也不让单子在审核后静默变动。这三个参数确认完,再开始搭商品档案。

3. 把压缩包跑起来:环境准备、数据库还原与最小登录验证

3.1 解压后的目录结构:先分清主程序、数据库备份和配置文件

拿到压缩包解压后,里面大致有这几类东西:主程序目录(exe和dll)、数据库要么是.bak备份文件要么是一段.sql脚本、配置文件一般是config.ini或app.config,再配套一份说明文档。我建议先把整个目录复制到纯英文的固定路径,比如D:\ERP\Server,不要放在桌面或带空格的中文目录下,否则数据库附加和组件注册阶段容易出现诡异报错。

配置文件里的连接串是这个样子:

[Database] Server=.\SQLEXPRESS Database=K3Demo User=sa Password=P@ssw0rd

[Database]段里的Server指SQL Server实例名。很多新手把Server写成localhost,本机跑没问题,局域网里其他客户端一登录就失败,因为localhost指向了客户端自己。SQL Server如果装的是命名实例,连接串格式是“IP\实例名,端口”,比如192.168.1.10\MSSQLSERVER,1433。配置文件里还有组件注册路径和报表路径两个参数,一般保持默认,但如果软件启动后提示找不到某个DLL,多半是路径被写死成了绝对地址。

3.2 还原并连接数据库:备份文件如何变成可用账套

拿到.bak文件后,先确认SQL Server版本。仿金蝶系统多用SQL Server 2008 R2到2019之间的版本,备份文件通常向上向下兼容,但高版本备份还原到低版本会直接报错。还原之前先看备份里的逻辑文件名:

sqlcmd -S .\SQLEXPRESS -U sa -P P@ssw0rd -Q "RESTORE FILELISTONLY FROM DISK = N'D:\ERP\K3Demo.bak'"
RESTORE DATABASE K3Demo FROM DISK = N'D:\ERP\K3Demo.bak' WITH MOVE 'K3Demo_Data' TO N'D:\ERP\K3Demo.mdf', MOVE 'K3Demo_Log' TO N'D:\ERP\K3Demo_log.ldf', REPLACE;

FILELISTONLY不真正还原,只是把备份文件里的逻辑名称列出来,免得MOVE子句里的名字写错导致还原中断。REPLACE参数用于覆盖同名数据库,测试环境可以用,生产库不要随手加。还原完成后,再回到配置文件里把Server字段填对,登录后看到账套列表里有K3Demo,数据库这一关就算过了。

3.3 最小登录验证:用一张采购单验证整套链路

登录系统后别急着把所有基础资料配完,先跑一个最小闭环:用admin登录,改掉默认密码;在基础资料里建一个仓库、一个供应商、一个商品;手工录入一张采购入库单,数量填1,审核并过账;打开库存报表看数量变没变;再开一张销售出库单把这件商品出掉,库存归零,资金流水出现应收款。整个过程控制在十分钟内,说明这系统从界面到数据库都是通的。

卡在“审核无效”时,优先检查单据状态字段FStatus。很多仿金蝶系统里0是未审核、1是已审核、2是已过账,界面按钮没反应往往是权限表没给当前账号分配审核权。这种情况去用户权限管理里把“单据审核”权限勾上,不用动代码。

4. 核心业务模块配置:商品、采购、销售、库存的打通

4.1 商品档案初始化:编码规则是后续所有单据的第一道约束

商品档案是整个进销存的地基,所有单据、报表、库存流水都挂在FItemID上。编码规则是第一道约束。我一般用“类别码+顺序流水号”,比如SP0001代表正常销售商品、JC0001代表材料、FW0001代表运费,长度控制在10位以内,全大写字母和数字,不要用中文和空格。一旦编码被采购单、销售单、盘点单引用,后期改编码的代价极高。

插入商品档案,在仿金蝶系统里对应t_Item表:

-- 商品基础资料:FUnitID 对应计量单位表的主键 INSERT INTO t_Item (FNumber, FName, FModel, FUnitID, FPrice, FSalePrice) VALUES ('SP0001', N'女装T恤', N'M-黑色', 1, 39.5000, 99.0000);

FUnitID这个字段最容易踩坑。很多系统界面显示单位名称,但数据库里存的是ID。如果直接看t_Unit表里ID从1开始,就觉得FUnitID填1没问题,其实填的是删除过又重建的记录,商品根本没关联上正确单位。我一般会先查一下计量单位表再插入:

SELECT FInterID, FName FROM t_Unit WHERE FStatus = 1;

把它当作必查项,把界面单位名称映射到FInterID,而不是想当然填1。

4.2 采购入库与应付账款:单据过账是记账的分界线

采购业务的单据链在仿金蝶系统里通常是“采购订单→采购入库单→采购发票/应付单”。采购订单可以省,但采购入库单不能省,因为库存增加和应付账款都挂在入库单上。操作顺序是:选择供应商、选择商品、填数量和单价、保存、审核、过账。审核后库存表实时变更,过账后生成财务凭证。

如果你发现这套系统“审核”和“过账”是同一个动作,那说明它简化了流程。这种简化版适合小贸易公司,但电商场景下经常要退补差价、红蓝字调整,没有反过账功能会很难受。我的建议是优先找支持反过账的版本,至少能在月末结账前把错误单据退回去重做。

核对采购价的SQL,用来防止入库单价格虚高:

-- 查看某商品最近5次采购价格 SELECT TOP 5 PO.FBillNo, POL.FQty, POL.FPrice, CAST(POL.FQty * POL.FPrice AS decimal(18,2)) AS FAmount, PO.FDate FROM t_POOrder PO JOIN t_POOrderEntry POL ON PO.FInterID = POL.FInterID WHERE POL.FItemID = 12345 AND PO.FStatus >= 1 ORDER BY PO.FDate DESC;

参数说明:FItemID换成实际商品的内码,不是商品编码。FStatus>=1表示只统计审核后的单据,避免把草稿单算进价格。FAmount用decimal(18,2)保证结果保留到分,这个精度问题在第5章会重点讲。

4.3 销售出库与应收账款:电商订单怎么落成销售单

电商订单最让人头疼的是拆合单。一个订单多个包裹,一个包裹多个商品,消费者还可能把赠品也当商品下单。常见做法是把平台订单先合并汇总成一张销售出库单,明细按SKU累加数量,运费通过一个叫“运费”的特殊商品或者金额调整来处理。这样既满足财务对账,又不需要给系统加一个复杂的电商订单模块。

最小存储过程,把订单内容写入销售单头、明细并返回金额:

CREATE PROCEDURE sp_CreateSaleBill @FBillNo nvarchar(50), @FCustomerID int, @FDate datetime, @FItemID int, @FQty decimal(18,2), @FPrice decimal(18,4), @FAmount decimal(18,2) OUTPUT AS BEGIN DECLARE @FInterID int; INSERT INTO t_SaleBill (FBillNo, FCustomerID, FDate, FStatus) VALUES (@FBillNo, @FCustomerID, @FDate, 1); SET @FInterID = SCOPE_IDENTITY(); INSERT INTO t_SaleBillEntry (FInterID, FItemID, FQty, FPrice, FAmount) VALUES (@FInterID, @FItemID, @FQty, @FPrice, @FQty * @FPrice); SET @FAmount = @FQty * @FPrice; END;

这段代码的核心是把“生成单据”封装成数据库操作,外部程序只传业务参数,不直接碰库存表。注意FAmount是OUTPUT参数,实际写入时仍然按数量乘单价重算,防止调用方传一个和单价数量对不上的金额进来。FPrice用decimal(18,4)而不是decimal(18,2),因为手工改价后,大数量订单的舍入误差要在最后一步统一处理。

4.4 成本算法选型:移动平均法更适合电商,全月一次加权适合批发

仿金蝶系统在存货核算模块通常提供移动平均法和全月一次加权平均法,有的还带标准成本法、先进先出法和周期成本法。成本算法的选择直接决定月末工作量。移动平均法每次采购入库后重新计算库存平均单价,出库单上的成本就是当时的加权成本,实时且直观;全月一次加权平时出库单只显示预估成本,月末按整月数据倒算,适合价格平稳、退货不多的批发业务。

维度移动平均法全月一次加权
成本实时性高,出库即出成本月底才能确定
月末工作量低需要大规模重算
频繁退换货按最近成本冲回,简单需逐笔回冲,容易错
负库存影响仍会乱,但可容忍会让月末成本彻底失真

电商场景我几乎一律选移动平均法,同时关闭“允许负库存”。之前有个做直播电商的客户,出库量瞬时很大,开了负库存之后成本一路乱到家。负库存意味着系统里的库存数量已经不可信,任何成本算法在这种数据上都会算出奇怪结果。

5. 仿金蝶电商ERP避坑:连接异常、精度陷阱与红蓝单据

5.1 数据库连接异常:服务器重启后客户端集体掉线

现象:客户端登录时提示“无法连接服务器”或“连接超时”,服务端看SQL Server进程似乎还在。

原因:最常见的是SQL Server服务没设自动启动,Windows更新后服务器重启,实例停在停止状态。第二个原因是配置文件的Server字段写的是localhost,本机没问题,但局域网客户端连过来,localhost指向了客户端自己。装了命名实例之后,连接串没改成“IP\实例名,端口”,也会连不上。

解决:打开SQL Server配置管理器,把SQL Server服务和SQL Server Agent服务都设为“自动”。数据库账号用混合模式,不要只依赖Windows身份验证,避免切换域用户时全挂。连接字符串固定成IP\实例名,1433,防火墙放行TCP 1433端口。还有SQL Server Browser服务在很多系统里默认关闭,通过局域网命名实例连接需要它,一起设为自动。血泪经验:之前有台服务器sa密码为空,内网被扫描后数据库被加密勒索,还原后第一件事就是改sa密码并限制可登录IP。

5.2 金额精度陷阱:float 字段让对账差一分钱

现象:销售明细金额合计和销售单表头金额不一致,财务对账差一分钱,差异金额不固定。

原因:单据明细表的金额字段用了float类型。SQL Server的float是二进制浮点,0.1在里面是不精确的,累加次数一多就会出现微小偏移。另一个原因是计算顺序:先四舍五入单价再乘数量,和先乘数量再四舍五入,结果不一样。

解决:把所有金额、单价字段改成decimal类型,金额用decimal(18,2),单价用decimal(18,4)。查询统计时统一舍入规则:

-- 统一金额计算顺序,避免精度漂移 SELECT FBillNo, CAST(FQty AS decimal(18,2)) AS FQty, CAST(FPrice AS decimal(18,4)) AS FPrice, CAST(ROUND(FQty * FPrice, 2) AS decimal(18,2)) AS FAmount FROM t_SaleBillEntry;

ROUND放在乘法外面是关键。先把单价舍入到两位小数,再乘一个999件的大订单,一单差好几块。这个问题在进销存里属于查半天想不起来的那一类,很多老实施顾问遇到对账不平会去翻存储过程,我建议先查字段类型,命中率更高。

5.3 红蓝字单据:退货数量录成正数,库存越冲越多

现象:电商退货单处理多了以后,某商品库存不降反升,月底盘点发现账面数比实物数多出一截。

原因:仿金蝶系统的退货逻辑往往靠数量正负号区分方向。销售退货单的数量应该是负数,界面上一旦有人填了正数,库存反冲就变成了正冲,等于又做了一次销售。很多简化版系统没有防错校验。

解决:在数据层加一道保险,用触发器拦截退货明细中的正数量:

CREATE TRIGGER tr_SaleReturnCheck ON t_SaleReturnEntry AFTER INSERT, UPDATE AS BEGIN IF EXISTS (SELECT 1 FROM inserted WHERE FQty > 0) BEGIN ROLLBACK; RAISERROR(N'退货数量必须为负数', 16, 1); END END;

触发器的逻辑是回滚正数退货并报错,这样外部程序绕过界面直接写库也逃不过校验。前提是确认系统的退货单确实约定负数,如果它用的是独立退货类型单据,就不需要这触发器,改成在单据类型维度限制。用CHECK约束也可以,但触发器能给出明确中文报错,实施时排查效率更高。

5.4 负库存是怎么产生的:出库时没有校验即时库存

现象:库存表里某个仓库数量变成负数,总仓实物却有货,盘点差异被记到负数的仓库,成本核算全乱。

原因:很多仿金蝶系统保存出库单时只校验单据本身,不校验即时库存。多仓库模式下,出库单的仓库字段允许为空,系统默认取第一个仓库,操作员一疏忽就串仓。加上“允许负库存”参数默认打开,问题一直潜伏。

解决:系统参数里把“允许负库存”关掉,出库单仓库字段设为必填。已产生的负库存用盘点单调整,不要直接改数据库:

-- 盘点调整:把账存数量修正为实存数量 UPDATE t_Inventory SET FQty = @ActualQty WHERE FItemID = @FItemID AND FStockID = @FStockID;

这里@ActualQty是盘点出来的实数,直接覆盖账存。但生产环境无论什么系统都不要这样直接UPDATE,要走盘点单让系统生成流水。这段SQL只作为停业维护时的数据修复方案,执行前必须备份原值,否则审计时讲不清库存为什么跳变。

6. 把进销存接到电商订单流:最小接口与账实一致自检

当进销存跑顺之后,真正带来效率的是和电商平台打通。我不建议直接改数据库表来写订单,风险很高。最稳的做法是把写操作封装成存储过程或Web API,外部系统只碰参数不碰表,从根上隔离误操作。

先做一个库存查询视图,运营抓数据就不用看一堆内部字段:

CREATE VIEW v_Stock_Available AS SELECT i.FNumber AS 商品编码, s.FName AS 仓库, inv.FQty AS 可用库存 FROM t_Inventory inv JOIN t_Item i ON inv.FItemID = i.FInterID JOIN t_Stock s ON inv.FStockID = s.FInterID WHERE inv.FQty > 0;

然后是账实一致性自检SQL。我每周会把库存流水和即时库存表拉一遍,提前发现单据漏审核或流水丢失:

SELECT t.FItemID, SUM(t.FQty) AS 流水净量, inv.FQty AS 账存数量 FROM ( SELECT FItemID, FQty FROM t_StockFlow WHERE FType = 'IN' UNION ALL SELECT FItemID, -FQty FROM t_StockFlow WHERE FType = 'OUT' ) t JOIN t_Inventory inv ON inv.FItemID = t.FItemID GROUP BY t.FItemID, inv.FQty HAVING ABS(SUM(t.FQty) - inv.FQty) > 0.001;

我的做法是把入库流水和出库流水分开处理,出库的FQty取负,SUM出来就是净变动。如果流水净量和即时库存表账存数量差异超过0.001,说明有单据没审核或流水不完整。多仓库环境下,把FItemID和FStockID同时加进JOIN条件和GROUP BY,否则会把不同仓库的差值混在一起。

我第一次把电商订单接入这类系统的时候,图省事写了个直接改库存表的同步程序,跑了半个月发现财务账和库存账脱节,最后只能一张一张补审核。后来我给自己立下规矩:任何改变库存的操作必须经过单据审核,外部系统一律通过存储过程写入。进销存这种系统不怕慢,就怕账不平,希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 8:10:35

CentOS 7.9下certbot自动续期SSL证书:从安装到nginx完整接入指南

1. 为什么选择certbot:证书过期恐惧症的终极解药先交代一下背景。我手头维护着几台CentOS服务器,上面跑着nginx、Tomcat之类的服务,前几年一直用阿里云的免费证书。阿里云免费证书本身没什么毛病,一年申请一次,但痛点在…

作者头像 李华
网站建设 2026/10/10 8:10:11

可编程PMIC实现多路电源管理:PCA9422与PIC32MX695F512L实战

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

作者头像 李华
网站建设 2026/10/10 8:09:02

开源掌机5W全解析:从硬件原理、演进简史到入坑避坑指南

最近我在整理柜子时翻出一台老开源掌机,装上电池居然还能开机。旁边就是手机,里面随便装个模拟器都能跑同样的游戏,可我还是愿意花半小时把那台小掌机充满电、调好音量、再插上耳机。这问题我想过很久:手机明明更方便,…

作者头像 李华
网站建设 2026/10/10 8:08:50

PCA9422+PIC32MX实现可监控可配置嵌入式电源管理

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

作者头像 李华
网站建设 2026/10/10 8:08:46

PCA9422与STM32F107VC协同实现嵌入式电源管理设计

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

作者头像 李华
网站建设 2026/10/10 8:04:57

世界技能大赛网络安全赛项A模块:系统加固实战指南

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

作者头像 李华