简介世纪科怡档案管理安装包面向需要搭建档案管理环境的企事业单位档案员、信息化运维人员及软件研究者提供一套完整的原版安装介质可解决旧版档案系统部署、重装与功能验证时缺少原始安装文件的问题。压缩包共48个文件、约48.34MB包含exe安装引导程序、cab与hdr等安装数据包、dll运行库、vts与dat业务数据模板以及pdf格式的使用说明书和txt说明文档覆盖从安装部署到功能了解的多个层面。目前已有547人浏览学习在档案管理软件资料中具有一定关注度。读者可借助安装程序完成系统安装与运行环境配置通过说明书了解档案收集、整理、检索、权限控制、版本管理与备份恢复等模块的使用思路也可观察旧版软件的目录组织与依赖关系为档案系统维护、迁移或二次开发提供参考。适合具备基础计算机操作能力、需要实际部署或研究档案管理软件的人员留存备用。1. 档案管理系统的落地边界先别急着扫先把目录树和权限想清楚做档案管理系统的落地最容易被低估的不是扫描仪分辨率而是档案目录树和权限边界。很多团队把资源包下载下来第一件事就是接扫描仪、装 OCR结果跑了两周发现档案号重复、借阅审批状态改不动、密级字段没地方落。这套档案管理资源包更适合中小机构做电子档案从采集、编目、入库到借阅审计的闭环后端以数据库为核心前端只做必要交互适合需要私有化部署、又不想从零写权限和审计的团队。它不追求大而全先把“一份档案从哪来、谁能看、改过什么、备份在哪”讲清楚。档案管理系统的第一道边界是“档案号”和“目录树”谁主谁从。常见翻车是把目录路径当成档案号的一部分目录一改名历史档案全部对不上。我的做法是档案号独立生成目录树只做分类和检索入口档案移动只改分类关系不改档案号。第二道边界是权限档案门类、密级、动作三个维度必须同时进入过滤条件不能只靠菜单权限。下面从数据库模型开始把这两条边界落到表结构里。2. 档案模型落到数据库目录树、主表和元数据扩展怎么拆2.1 为什么档案管理不能只建一张大表档案门类一多元数据字段就会爆炸。文书档案有发文号、成文日期、签发人会计档案有凭证号、账套、保管期限照片档案有拍摄时间、地点、人物。把这些字段全塞进一张档案主表表会宽到没法维护新增一个门类就要改表结构旧数据还要补默认值。更麻烦的是检索不同门类的查询条件不同宽表索引越建越多写入越来越慢。我一般把档案模型拆成三层目录树表负责分类和层级档案主表放所有门类共用的稳定字段元数据扩展表放可变字段。主表只保留档案号、标题、年度、保管期限、密级、状态、文件哈希、创建人这些高频过滤字段。扩展表用 key-value 结构按档案 ID 关联新增门类只加元数据模板不改主表。这样权限过滤和列表查询走主表详情页再按需加载扩展字段索引压力小很多。还有一个容易忽略的点文件哈希要放主表不要放附件表。档案入库时先算 SHA256重复文件直接拦截比后面查附件表快得多。档案号做唯一约束哈希做普通索引二者组合能挡住大部分重复导入。2.2 三张核心表的 SQL 与索引-- 档案目录树自关联层级码用于快速查子树 CREATE TABLE archive_category ( id BIGINT PRIMARY KEY, parent_id BIGINT NULL, category_code VARCHAR(64) NOT NULL, category_name VARCHAR(128) NOT NULL, level_no INT NOT NULL, sort_no INT NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_archive_category_parent ON archive_category(parent_id, sort_no); CREATE UNIQUE INDEX uk_archive_category_code ON archive_category(category_code); -- 档案主表只放通用字段档案号业务唯一 CREATE TABLE archive_item ( id BIGINT PRIMARY KEY, archive_no VARCHAR(64) NOT NULL, category_id BIGINT NOT NULL, title VARCHAR(512) NOT NULL, archive_year INT NOT NULL, retention_period VARCHAR(16) NOT NULL, security_level VARCHAR(16) NOT NULL, status VARCHAR(16) NOT NULL DEFAULT DRAFT, file_hash CHAR(64) NOT NULL, created_by BIGINT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX uk_archive_item_no ON archive_item(archive_no); CREATE INDEX idx_archive_item_category_year ON archive_item(category_id, archive_year); CREATE INDEX idx_archive_item_hash ON archive_item(file_hash); CREATE INDEX idx_archive_item_security ON archive_item(security_level, status); -- 元数据扩展表不同门类的差异字段放这里 CREATE TABLE archive_metadata ( id BIGINT PRIMARY KEY, archive_id BIGINT NOT NULL, meta_key VARCHAR(64) NOT NULL, meta_value TEXT, UNIQUE KEY uk_archive_meta_key (archive_id, meta_key) );逻辑说明archive_category用parent_id自关联category_code存层级码比如01、0102、010203查某目录下所有档案时用LIKE 0102%比递归查树快。archive_item的archive_no做唯一索引防止并发导入时重复file_hash单独索引去重脚本先查哈希再入库。archive_metadata的联合唯一键保证同一档案同一元数据键只有一条记录。参数说明level_no控制最大层级建议不超过 8 层超过 6 层就要考虑拆目录retention_period用PERMANENT、30Y、10Y这类短码不要存中文长句security_level用PUBLIC、INTERNAL、SECRET三档起步和权限表里的密级过滤值保持一致。status至少包含DRAFT、PENDING、ARCHIVED、BORROWED、RETURNED状态流转不要只靠前端按钮控制。2.3 目录树编码与移动档案的边界目录树最怕“移动目录只改 parent_id”。如果只改父节点层级码和冗余路径不更新子节点查询会漏数据。我的做法是目录移动放在事务里先锁当前目录和子目录再批量重算category_code和level_no最后更新档案的category_id只在需要换分类时执行。档案本身不跟目录路径绑定档案号也不变。实际执行时先查子树-- 查某目录下所有子目录编码前缀匹配 SELECT id, category_code, level_no FROM archive_category WHERE category_code LIKE 0102% ORDER BY category_code;这段 SQL 用于移动前确认影响范围。参数0102%是目标目录的层级码前缀%只放后面不要前后都加否则索引失效。确认子目录数量后在应用层生成新编码批量UPDATE不要用循环单条更新。档案表只更新category_id历史借阅记录和审计日志里的旧分类保留快照方便追溯。提示目录层级超过 6 层时列表查询会明显变慢。与其继续加索引不如把“年度/门类/保管期限”做成筛选条件目录树只保留三到四级。3. 权限与借阅流程RBAC、状态机和审计日志别分家3.1 权限模型为什么按“档案门类密级动作”落只做 RBAC 的档案系统上线后一定会遇到“用户有借阅菜单但能看到所有密级”的问题。菜单权限只能控制页面入口数据权限必须落到查询条件。我的做法是把权限拆成三层功能权限控制按钮和接口数据权限控制门类和密级动作权限控制查看、下载、打印、借阅、导出。三层在同一个权限表里用resource_type区分查询档案列表时拼接category_id和security_level过滤。-- 权限表功能、数据、动作统一存避免三套模型 CREATE TABLE sys_permission ( id BIGINT PRIMARY KEY, perm_code VARCHAR(128) NOT NULL, perm_name VARCHAR(128) NOT NULL, resource_type VARCHAR(32) NOT NULL, -- MENU / API / DATA / ACTION resource_value VARCHAR(256), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX uk_sys_permission_code ON sys_permission(perm_code); -- 角色权限关联 CREATE TABLE sys_role_permission ( role_id BIGINT NOT NULL, permission_id BIGINT NOT NULL, PRIMARY KEY (role_id, permission_id) ); -- 借阅申请表状态机字段单独放不要和档案状态混用 CREATE TABLE borrow_apply ( id BIGINT PRIMARY KEY, archive_id BIGINT NOT NULL, applicant_id BIGINT NOT NULL, approve_user_id BIGINT NULL, state VARCHAR(16) NOT NULL DEFAULT DRAFT, reason VARCHAR(512), apply_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, approve_at TIMESTAMP NULL, return_at TIMESTAMP NULL ); CREATE INDEX idx_borrow_apply_state ON borrow_apply(state, applicant_id);逻辑说明perm_code用archive:borrow:apply这种冒号分段方便前端和后端统一判断resource_type为DATA时resource_value存门类 ID 或密级范围查询时转成条件。borrow_apply.state只存状态码不存“已通过”这种中文展示层再翻译。参数说明resource_value不要存 JSON 大对象门类 ID 用逗号分隔密级用INTERNAL,SECRET这种枚举串解析成本低。approve_user_id允许为空表示待分配审批人return_at为空表示未归还。借阅状态和档案状态分表管理档案的status只表示归档生命周期借阅状态单独走borrow_apply否则一个档案被多人借阅时状态会互相覆盖。3.2 借阅审批状态机把非法流转挡在服务层from enum import Enum class BorrowState(str, Enum): DRAFT DRAFT PENDING PENDING APPROVED APPROVED REJECTED REJECTED RETURNED RETURNED OVERDUE OVERDUE ALLOWED { BorrowState.DRAFT: {BorrowState.PENDING}, BorrowState.PENDING: {BorrowState.APPROVED, BorrowState.REJECTED}, BorrowState.APPROVED: {BorrowState.RETURNED, BorrowState.OVERDUE}, BorrowState.OVERDUE: {BorrowState.RETURNED}, } def transit(current: str, target: str) - str: cur BorrowState(current) tgt BorrowState(target) if tgt not in ALLOWED.get(cur, set()): raise ValueError(f非法借阅状态流转: {current} - {target}) return tgt.value逻辑说明ALLOWED是白名单只允许表里写出的流转DRAFT不能直接跳到RETURNEDREJECTED不能再改APPROVED。服务层在更新borrow_apply.state前先调transit不通过直接抛异常避免有人直接改库把状态改乱。参数说明current必须是数据库里的原状态target是前端传的新状态。状态值统一用大写英文和数据库字段长度 16 对齐。OVERDUE建议由定时任务根据return_at生成不要由用户手动点。审批通过时写approve_at归还时写return_at两个时间字段不要复用。3.3 审计日志写什么字段才够查审计日志不是“记一条操作日志”就够。档案系统被追责时通常要回答四个问题谁、什么时候、对哪份档案、改前改后是什么。日志表至少要有operator_id、action、object_type、object_id、before_json、after_json、ip、trace_id、created_at。before_json和after_json只存变更字段不要存整行大字段否则日志表膨胀很快。CREATE TABLE audit_log ( id BIGINT PRIMARY KEY, operator_id BIGINT NOT NULL, action VARCHAR(64) NOT NULL, object_type VARCHAR(64) NOT NULL, object_id BIGINT NOT NULL, before_json TEXT, after_json TEXT, ip VARCHAR(64), trace_id VARCHAR(64), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_audit_log_object ON audit_log(object_type, object_id, created_at); CREATE INDEX idx_audit_log_operator ON audit_log(operator_id, created_at);逻辑说明object_type用ARCHIVE、BORROW、USER这种短码object_id对应主键查某份档案的变更历史时按object_type object_id走索引。trace_id从网关透传方便把一次请求里的多条日志串起来。参数说明before_json和after_json只记业务字段密码、身份证号、手机号这类敏感字段不入日志ip存字符串兼容 IPv6日志表按月分区或定期归档不要和业务表放同一个库长期跑。审计日志只允许插入不允许业务代码更新和删除。4. 电子文件入库与 OCR批量导入、去重和格式白名单4.1 批量扫描导入脚本import hashlib import sqlite3 from pathlib import Path from datetime import datetime SUPPORTED {.pdf, .ofd, .jpg, .png, .tif, .docx} def sha256_file(path: Path, chunk: int 1024 * 1024) - str: h hashlib.sha256() with open(path, rb) as f: while True: block f.read(chunk) if not block: break h.update(block) return h.hexdigest() def scan_files(root: str): for p in Path(root).rglob(*): if p.is_file() and p.suffix.lower() in SUPPORTED: yield p, sha256_file(p), p.stat().st_size def write_stage(db_path: str, rows): conn sqlite3.connect(db_path) conn.executemany( INSERT OR IGNORE INTO archive_stage(path, file_hash, file_size, created_at) VALUES (?, ?, ?, ?), [(str(p), h, s, datetime.now().isoformat(timespecseconds)) for p, h, s in rows], ) conn.commit() conn.close()逻辑说明SUPPORTED是格式白名单不在名单里的文件直接跳过避免把临时文件、缩略图、隐藏文件扫进来。sha256_file分块读取大文件不会一次性吃满内存。INSERT OR IGNORE依赖file_hash唯一约束重复文件第二次导入不会报错也不会产生重复记录。参数说明chunk默认 1MB机械硬盘可以调到 4MBSSD 保持 1MB 即可。root传待导入目录脚本会递归扫描。archive_stage表要先建CREATE TABLE IF NOT EXISTS archive_stage ( id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT NOT NULL, file_hash TEXT NOT NULL UNIQUE, file_size INTEGER NOT NULL, created_at TEXT NOT NULL );这段建表语句里file_hash唯一是关键没有它INSERT OR IGNORE不会去重。path存绝对路径方便回溯正式入库时再转成相对存储路径。4.2 去重不是只比文件名SHA256 和业务档案号双校验文件名去重最不靠谱。同一份文件改个名字就能重复入库不同门类下同名文件又会被误杀。实际落地时用双校验文件哈希挡住内容重复档案号唯一索引挡住业务重复。导入流程分三步扫描到archive_stage按file_hash和archive_item.file_hash比对命中则标记“疑似重复”再按档案号查主表命中则直接拒绝。两步都通过才写入主表。-- 查疑似重复哈希已存在但档案号不同 SELECT s.path, a.archive_no FROM archive_stage s JOIN archive_item a ON a.file_hash s.file_hash WHERE a.archive_no :current_archive_no;逻辑说明这条 SQL 用于导入前预览current_archive_no是当前批次生成的档案号。结果不为空时不要自动合并先人工确认是不是同一份文件换了档案号。参数:current_archive_no由导入批次生成建议用“年度门类流水号”规则不要用时间戳时间戳可读性差且容易重复。4.3 OCR 结果写回与格式校验OCR 不要直接覆盖原元数据。我的做法是 OCR 结果写archive_metadata的OCR_TEXT键置信度低于阈值的再进人工复核队列。命令行调用常见做法是tesseract input.tif stdout -l chi_sim --psm 6 ocr.txt逻辑说明-l chi_sim指定简体中文语言包--psm 6假设输入是一块统一的文本块适合扫描件正文。输出重定向到ocr.txt再由导入脚本读取不要直接在 shell 里拼 SQL。参数说明input.tif建议先做灰度化和二值化分辨率低于 200dpi 的扫描件 OCR 准确率会明显下降--psm不要迷信默认值表格类档案用--psm 6单行标签用--psm 7。OFD 文件先转 PDF 或图片再 OCR不要直接改扩展名。OCR 文本入库前做长度截断单份档案超过 2 万字符的分段存避免元数据表单行过大。5. 避坑与排查五个上线后最容易翻车的点5.1 入库与检索类问题现象批量导入时档案号冲突导入一半报唯一键错误。原因多是档案号生成规则里用了“当前最大 ID 1”并发导入时两个线程拿到同一个号。解决是把档案号生成收口到数据库序列或单独的发号表导入脚本按批次预生成号段不要边插边查最大值。现象目录树超过五层后档案列表打开要十几秒。原因是用递归查子树每层都走一次数据库。解决是给目录表加层级码查询用前缀匹配同时把“年度、门类、保管期限”做成组合索引。层级码不要存中文存数字短码前缀匹配才能走索引。现象全文检索能搜到密级更高的档案标题。原因是全文索引只存了标题和正文查询时没有拼密级过滤。解决是检索服务在召回阶段就带上security_level和用户可见门类条件不要等结果返回后再过滤否则分页数量会对不上。全文索引里也不要存涉密正文只存可检索的元数据。5.2 权限与备份类问题现象借阅审批状态被直接改库前端显示“已通过”但审计日志没有记录。原因是状态更新走了后台管理工具绕过了服务层。解决是数据库账号分权业务账号只给INSERT/UPDATE必要字段状态字段的更新只允许服务层账号执行同时在borrow_apply表加更新时间戳和操作人字段发现异常能定位。现象数据库备份恢复成功但电子文件打不开。原因是只备份了数据库附件目录没进备份策略。解决是把数据库、附件存储、OCR 文本目录放在同一个备份任务里恢复演练时随机抽 30 份档案按archive_item.file_hash重新算文件哈希哈希对不上就说明附件缺失或损坏。备份文件不要和业务库放同一块磁盘。注意避坑清单里的每一条都建议写成上线检查项不要等用户报障再补。尤其是档案号发号和备份恢复返工成本最高。6. 归档验收脚本抽样30份、重建索引和恢复演练的最小闭环6.1 抽样校验脚本import hashlib import random import sqlite3 def check_sample(db_path: str, sample_size: int 30): conn sqlite3.connect(db_path) rows conn.execute( SELECT id, path, file_hash FROM archive_item ORDER BY RANDOM() LIMIT ?, (sample_size,), ).fetchall() bad [] for rid, path, expected in rows: with open(path, rb) as f: actual hashlib.sha256(f.read()).hexdigest() if actual ! expected: bad.append((rid, path)) conn.close() return bad逻辑说明随机抽 30 份档案按主表存的file_hash重新算文件哈希不一致就记录档案 ID 和路径。参数sample_size默认 30数据量大的时候可以按门类分层抽样每个门类至少抽 5 份。脚本跑完输出bad列表为空才算验收通过。6.2 备份恢复演练的检查表检查项通过标准失败后先看什么数据库恢复表数量和关键表行数一致备份时间点、字符集附件哈希抽样 30 份哈希全部一致附件目录是否纳入备份索引重建检索结果与恢复前一致索引配置、分词器版本权限过滤低权限账号搜不到高密级档案数据权限条件是否拼接恢复演练不要只看“能启动”。先恢复数据库再挂附件目录最后重建检索索引三步都过了才算闭环。索引重建后拿同一个关键词对比恢复前后的结果数量数量对不上先查分词器版本不要急着重跑全量。从那以后我每次上线档案系统都强制先跑一轮 30 份抽样和一次恢复演练不跑完不签字。需要这套资源包直接落地的话按目录先取数据库脚本和导入脚本再取验收脚本不要一上来改前端样式先把档案号、哈希和权限字段对齐后面换门类才不会返工。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
C++非类型模板参数与模板特化实战指南 1. 为什么需要非类型模板参数? 在C模板编程中,我们最常使用的是类型参数(type parameters),比如 template<typename T> 。但有时候,我们需要在编译期传递具体的值而非类型,这就是非类型… · 2026/11/7 10:42:50
SQL中COALESCE函数的原理与应用实践 1. COALESCE函数的基本概念与核心作用 COALESCE函数是SQL标准中定义的一个通用函数,在MySQL、PostgreSQL、Oracle等主流数据库系统中均有实现。这个函数的核心功能是从参数列表中返回第一个非NULL值。其语法结构非常简单:
COALESCE(value1, value2, ..… · 2026/11/8 13:34:20
机电可以考电工证吗?学历不高也能考,含金量到底如何? 机电可以考电工证吗?学历不高也能考,含金量到底如何? 你是不是也这样想: 学历不高怕报不上名 ?其实, 机电专业能不能考电工证 ,这是很多人都在问的问题。答案是: 可以… · 2026/11/9 17:12:44
钦州电工证考试内容怎么准备?实操考试心里没底怕挂科?考前押题帮你稳过! 钦州电工证考试内容怎么准备?实操考试心里没底怕挂科?考前押题帮你稳过! 实操考试心里没底怕挂科?很多准备考电工证的朋友都在担心这个问题。尤其是在钦州,电工证考试内容虽然有明确大纲,但具体怎么准备、怎么应对,还是得靠经验和方法。别担心,本文从… · 2026/11/9 17:12:44
宁河考电工证多少钱真实经历告诉你别踩坑 宁河考电工证多少钱真实经历告诉你别踩坑 刚毕业的李强在新乡找了份公路工程的临时电工岗位,公司说“上岗前必须要有低压电工证”。他一听就懵了,这证还没考,工资都发不下来,怎么办?他跑了几家培训机构,问了一圈价格,最后在宁河某培训机构花了3200… · 2026/11/9 17:12:44
江门电工证体检内部消息:怕考不过白交培训费?看这篇就够了 江门电工证体检内部消息:怕考不过白交培训费?看这篇就够了 怕考不过白交培训费?你不是一个人,这是很多想考江门电工证的朋友最担心的问题。尤其是在体检和考试过程中,如果对流程和标准不了解,很容易在关键环节掉链子,导致培训费打了水漂。不过,好消息… · 2026/11/9 17:12:44
耒阳假电工证怎么选?学历不高怕报不上名,多少钱才能拿证? 耒阳假电工证怎么选?学历不高怕报不上名,多少钱才能拿证? 你是不是也这样想:学历不高,连报名资格都没?别急,耒阳假电工证也不是完全没戏,但关键得选对门道。很多人因为学历低,总觉得电工证、焊工证这些证儿根本就报不了,可实际情况是,只要材料准备… · 2026/11/9 17:12:44
高压电工证深圳补贴怎么报名?别被中介骗了,看完这篇就够了 高压电工证深圳补贴怎么报名?别被中介骗了,看完这篇就够了 你是不是也像我一样,第一次听说【高压电工证深圳补贴】,心里一万个问号?明明是个电工,怎么突然要搞证?补贴又是啥意思?最担心的是—— 不知道去哪报名怕被中介坑… · 2026/11/9 17:10:23
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/9 2:05:04
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/9 3:11:26
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/9 5:24:17
电工证不需要考复审延期怎么办理 通过率揭秘 电工证不需要考复审延期怎么办理 通过率揭秘 不知道去哪报名怕被中介坑?电工证不需要考复审延期怎么办理?最近不少学员都在问这个问题,尤其是刚拿到证的新手,对复审流程一知半解,生怕被培训机构套路。别担心,今天咱们就来聊聊电工证复审的真相,尤其是… · 2026/11/9 0:00:54
砀山哪里考电工证的多 电工证报考别踩坑 郑州报考避坑指南 砀山哪里考电工证的多 电工证报考别踩坑 郑州报考避坑指南 工地太忙根本没时间复习考试,这几乎是所有一线施工人员的共同心声。尤其是像电工这样的特种作业,操作证不仅关系到能不能上工,还直接关系到工资高低和职业发展。可偏偏,很多人连怎么报名、去哪… · 2026/11/9 0:00:54
南方电网电工作业含金量高吗?应届生怎么考怎么干? 南方电网电工作业含金量高吗?应届生怎么考怎么干? 工地太忙根本没时间复习考试,这不是个别现象,而是很多刚毕业的工程类学生面临的现实。南方电网电工作业的证书,听起来门槛不低,但 含金量… · 2026/11/9 0:00:54
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:35
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:58
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:25:08