ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

教材征订系统详细设计说明书:从表结构到状态机的完整指南

教材征订系统详细设计说明书:从表结构到状态机的完整指南

简介:这是一份教材管理系统院系征订系统的详细设计说明书,围绕教材信息维护、条件查询、增删改、密码管理、导入导出与身份验证等核心需求,给出从需求分析到系统设计的完整方案,适合系统分析、软件开发人员及高校课程设计参考。资源包内包含1个doc文档,压缩包大小3.96MB,文档涵盖总体设计、需求概述、数据库设计、系统架构与技术选型、安全性与权限管理、性能优化与测试等章节,并附有顶层及二层数据流图、软件结构与模块描述说明。读者可据此理解B/S架构与MVC模式在教材管理场景中的落地思路,学习教材、用户、订单等表结构设计、角色权限控制以及数据缓存、索引优化等要点,也可参照其章节组织方式撰写自己的软件工程设计文档。该资源已有126人学习/下载,适合需要快速建立教材管理系统整体设计框架,或正在完成相关课程设计、毕业设计的技术人员。

1. 教材管理系统院系征订系统:这份详细设计说明书到底在解决什么

每年春秋两季的教材征订,是高校教务链条里最容易被低估的环节。院系教学秘书要在截止时间前收集几十门课的教材需求,教材科要汇总各院系数据去对供应商下单,中途只要有一个班级的教材版本填错,后续的退书换书成本就全压在库房。教材管理系统里的院系征订子系统,就是把“发通知、院系填报、教务处审核、教材科汇总、订单流转”整条链路搬到线上;而这份 .doc 格式的《详细设计说明书》,就是给开发和测试的施工图。它不是需求文档那种“我们要做教材征订”的空话,而是把表结构、状态机、接口参数、异常分支一条条定死。适合三种人看:高校信息中心的自研团队、接高校项目的软件公司、想规范流程的教材科负责人,也适合刚入行的开发,想搞明白一份详细设计说明书到底要详细到什么程度。

2. 先抠需求边界:院系征订系统要管哪些事、不管哪些事

详细设计说明书最容易犯的错,是上来就画大架构,先贴一张微服务图,再说“支持高并发”。但对于教材征订这个场景,学期初的填报峰值也就几百个用户同时在线,真正卡壳的不是并发,而是业务规则没定义明白。所以我会先带着项目组把“系统边界”讲透:哪些属于院系征订系统,哪些属于教材管理系统里其他模块,哪些根本不归系统管。

2.1 业务角色与用例:教学秘书、教务处、教材科、学生各看到什么

在详细设计说明书的“功能需求”部分,第一个设计决策是定义角色。高校里的实际分工通常是这样:教材科负责维护教材目录和供应商信息,并创建每个学期的征订批次;教务处负责审核教材选用是否符合教学计划;院系教学秘书负责给每个班级课程填报指定教材和数量。学生一般不直接进系统,教材需求由教学秘书代报。把这条业务链路理清之后,角色和用例就能落成一张权限矩阵。

用表来抽象,这个表要写进说明书:

角色关键操作数据权限典型误区
教材科管理员创建征订批次、维护教材库、汇总订单全部数据可读,可写基础数据误把供应商对账也塞进本系统
教务处审核员查看填报明细、审核通过/退回只读填报数据,可写审核结论审核和退回规则没说清
院系教学秘书填报、暂存、重新提交只能看本院系数据没有草稿能力,误填即生效

说明书里配套要写用例,每个用例包含前置条件、主流程、异常分支。举例,UC-04“教学秘书填报教材”的异常分支就该有三条:填报提交时征订批次已截止;同一门课重复填报;教材在教材库中被停用。别小看这些分支,测试用例就是从它们生成的。

可执行步骤这部分,我一般会建议项目组做四步:

  1. 拿着上一年度的纸质征订通知和 Excel 模板,把所有需要填写的列出来,标出哪些是院系填的、哪些是教材科汇总时生成的。
  2. 找两位教学秘书做一次访谈,问“上一季哪张表你填得最痛苦”,把她们的回复原话写到会议记录里。
  3. 整理出统一动词,例如“创建批次”“填报”“退回”“提交”,确保文档里每个功能点对应且只对应一个用例。
  4. 由产品负责人划定边界,把“供应商到货进度跟踪”“教材出入库”这些相邻模块标记为外部系统,只在接口层面约定。

这样做才能保证详细设计说明书不是需求说明书的复述,而是能让开发直接建表、写代码的设计文档。

2.2 手工模式到系统模式的差距:为什么 Excel 汇总会翻车

如果不做系统,教材征订通常靠 Excel。每个院系发一张表,收回几十个文件,教材科再手工合并。这个过程有三个必然翻车的点:第一,教材名称不统一,“高数(上)”和“高等数学 上册”是同一本书,但 VLOOKUP 匹配不上;第二,ISBN 录入不规范,有人带短横线,有人不带;第三,截止时间靠催,教秘提交后想改就得重新传文件。详细设计说明书要回答的就是:系统如何消灭这三种问题。

对应到设计决策上:

手工模式痛点系统设计对策详细设计说明书里的落点
教材名称/ISBN不统一教材库统一维护,提供下拉选择,禁止手输教材库表结构、基础数据接口
重复提交、版本覆盖明细表唯一索引、状态机控制提交动作数据库设计、状态流转表
时间难约束批次状态自动启动/关闭,过期禁止填报征订批次表、定时任务状态
审核无留痕审核人和操作时间落库,接口幂等控制审核记录表、接口错误码

在说明书的功能描述里,我习惯把每一个表单页面的关键业务规则都定义出来。例如“选教材”这个动作,规则是:教学秘书按班级课程添加教材,教材必须来自当前可用的教材目录,教材状态为“启用”,数量默认取该课程选课人数,允许手改但必须大于零。这些规则看起来琐碎,但如果没有写在详细设计说明书里,开发就会为了省事做成一个纯文本输入框,后面所有问题都从这里冒出来。

选型理由也要写清楚。之所以把“教材唯一标识”放在教材库而不是让各院系自己填,是因为后面的订单汇总需要按出版社、供应商维度对数量做合计。如果用书名匹配,同一本书在 Excel 里三个写法,汇总时就会变成三行订单,供应商发货时就会一脸懵。所以,基础数据的统一是详细设计说明书里优先级最高的事。

最后还要定义“什么不属于本系统”。常见越界是“教材费用结算”,这个通常和财务系统、学生缴费系统联动,院系征订系统只负责确认数量和订单,不负责收钱;另外“教室排课”也不该在这里处理。边界写清楚后,后续接口联调时就能挡住很多不必要的变更。这一章内容就围绕边界和角色展开,让开发拿到说明书第一反应不是“从哪个表开始建”,而是“哪些事别做”。

3. 把说明书拆成模块:总体架构与功能模块的写法

进入详细设计说明书的“总体设计”部分,这里不是写愿景,而是写组件边界。教材管理系统一般还会包含课程管理、师资管理和教材库管理,院系征订系统作为其中一个子系统,不需要重复设计这些基础能力,但必须说清楚自己依赖哪些数据、对外暴露哪些功能。我会把子系统放在一张 A4 宽的模块上下文图里,中心是院系征订子系统,左边是教材库、课程库、组织架构库,右边是供应商系统和审计日志,箭头只标关键数据流。

3.1 用模块划分说话:基础数据、征订计划、院系填报、审核汇总、订单流转

推荐把子系统拆成五个内聚模块,每个模块对应详细设计说明书的一章,也对应一个开发任务包:

  • 基础数据模块:负责教材目录、出版社、班级课程关系、教材状态维护。这个模块的代码量不大,但数据质量决定其余模块能不能跑起来。
  • 征订计划模块:负责创建学期征订批次、设置各院系填报起止时间、控制批次启停。批次设计是整个系统的时间轴。
  • 院系填报模块:教学秘书入口,负责草稿维护、按课程选择教材、填写数量、提交。这是使用频率最高、交互细节最多的模块。
  • 审核汇总模块:教务处/教材科审核,支持批量通过、单个退回,生成院系汇总和全校汇总。审核动作必须留操作日志。
  • 订单流转模块:把审核通过的明细按供应商拆单,生成采购订单,后续对接教材入库。这个模块会往外抛数据,要定义好接口。

每个模块在说明书里要写四件事:功能范围、涉及角色、外部接口、核心数据。以下表格节选“院系填报模块”:

项目内容
功能范围草稿增删改查、按课程批量选教材、数量计算、提交/撤回
涉及角色院系教学秘书
外部接口调用课程服务获取班级课程表,调用基础数据模块获取教材目录
核心数据征订明细 enroll_item

我给开发评审时有个口头禅:模块之间只允许通过明确的接口通信,不许直接改对方的表。很多返工就是因为填报模块为了显示方便,直接读了订单模块的数据,结果两边对状态判断不一致。这个约束写进说明书,后期责任边界就清晰了。

为什么要拆成五块而不是按页面拆?按页面拆的结果通常是每个页面连着自己的隐藏逻辑,到汇总时发现同一本教材在填报页和审核页里用了两个状态字段。按模块拆以后,填报模块只关心“这条明细现在能不能提交”,审核模块只关心“这条明细能不能通过”,各自的状态只归各自管,汇总页只是读取结果。

3.2 画架构图和时序图的习惯:让开发不靠猜

详细设计说明书必然要画图,但图纸质量参差不齐。常见问题有两种:一是把时序图画成流程图,二是图里出现“系统内部”四字却不展开。我会在说明书里规定一套最小画图习惯:架构图用模块矩形加连线,不标具体服务器;时序图只画业务关键路径,不要每个数据库操作都画;所有图必须配文字说明,图里出现的每个组件都要在正文有定义。

一个典型的征订主流程,我会在文档里用文字描述,不依赖工具格式,因为项目组可能有人不会用标准 UML。文字流程如下:

教材科发起征订批次并设置截止时间 -> 系统通知各院系 -> 教学秘书进入填报页,创建草稿 -> 按班级课程从教材库选择教材,填写数量 -> 提交审核 -> 教务处审核,若通过则教材科汇总,若退回则教学秘书修改后重新提交 -> 教材科汇总生成采购订单 -> 订单流转到供应商。

在说明书里配一张时序图脚本,参与者是教学秘书、前端、征订服务、审核服务、教材库。消息关键点要标注“校验批次未截止”“校验教材为启用状态”“锁定填报数据”。这里每个校验点都对应后面接口设计的一个异常码。

时序图画到什么程度?我一般要求一条链路最多十个消息,超过就拆分。像“保存草稿”和“提交审核”是两条时序,不要混在一起。开发照着时序图写代码时,基本不需要再猜业务逻辑了。还有一张部署视图也要画,说明应用服务和数据库服务器怎么部署,但不用精确到 IP,只标逻辑节点。

说明书在总体设计部分还要说明异常处理原则。例如“批次未启用”“批次已截止”“教材已停用”“数量超出选课人数上限”都是业务异常,不能简单抛异常返回 500,要在接口层返回明确业务码。这个决定写在模块设计里,前后端就有共同语言。否则前端收到一个 500 只能弹“系统错误”,教学秘书根本不知道是时间过了还是教材选错。

4. 数据库与接口设计:表结构、状态机和四个必须说清的参数

进入详细设计说明书的下半部分,也是评审会上最容易被点名挑战的部分。数据库设计和接口设计不能拍脑袋,每个字段、每个状态、每个参数都要有业务解释。下面以最小但完整的四张表为例,逐表讲清楚字段、约束、状态机,以及接口入参出参。

4.1 核心表设计:教材库、征订计划、填报明细、订单汇总

四张核心表是 textbook(教材库)、subscription_batch(征订批次)、enroll_item(征订明细)、order_summary(订单汇总)。为什么是四张而不是更多?因为教材管理系统还有班级、课程、供应商等基础表,那些属于公共基础数据,这里只列征订子系统自己拥有写权限的表。

表名关键字段说明
textbookid, isbn, title, author, publisher_id, edition, price, statusstatus 区分启用/停用,ISBN 不唯一
subscription_batchid, name, semester, start_time, end_time, statusstatus 取草稿/进行中/已截止/已归档
enroll_itemid, batch_id, dept_id, class_id, course_id, textbook_id, student_count, quantity, applicant_id, status唯一索引 batch_id+dept_id+class_id+course_id+textbook_id
order_summaryid, batch_id, supplier_id, total_count, total_amount, created_at由 enroll_item 汇总生成

为什么 ISBN 不唯一?因为同一书目会因出版年份、印次不同产生不同定价记录,而教学秘书选教材时只需要对应到教材库中一条“启用”状态的记录。如果强行把 ISBN 当唯一主键,后续供应商调价和维护就非常痛苦。所以 textbook 表用自增主键,isbn 加普通索引,在查询时下钻到具体版本记录。

enroll_item 表的唯一索引是个关键设计。它解决了两个问题:一是防止同一班级同一门课重复填报同一本教材;二是给接口幂等提供数据库层面的保障。如果开发时图省事不加这个唯一索引,线上就会看到一条教材需求在汇总里出现两份,金额翻倍。数量 quantity 要设一个默认值,默认取班级选课人数 student_count,同时允许教学秘书手动调整,但校验上限不能超过班级人数的一倍,防止把全班数量误填成两倍。

状态字段建议统一使用 tinyint,并在说明书里配一个字典表说明每个数字含义。时间字段全部用 datetime,不要用字符串,否则排序和时区处理都是坑。金额用 decimal(10,2),不要用 float。这些看似基础,却是评审时最能发现方案是否用心的点。

4.2 状态机与接口约定:从草稿到已审核的流转,接口入参出参怎么定

状态机必须定义成表格,每个动作的权限、流向、可操作角色都要写清楚。以 enroll_item 为例:

当前状态操作目标状态可操作角色
草稿 draft提交 submit待审核 submitted教学秘书
待审核 submitted通过 approve已通过 approved教务处
待审核 submitted退回 reject已退回 rejected教务处
已退回 rejected重新提交 resubmit待审核 submitted教学秘书
已通过 approved无--

说明书里还要明确禁止跨状态操作,例如草稿不能直接进入汇总,已通过不能再编辑。这套状态机同时决定了界面按钮的显隐,前端拿到状态字段就知道渲染成什么样。

接口约定不要求列出全部接口,但要覆盖五个核心操作:创建征订批次、提交填报、审核通过、审核退回、汇总订单。

操作路径关键参数返回
创建征订批次POST /api/subscription/batchname, semester, startTime, endTimebatchId
提交填报POST /api/enroll/submitbatchId, items[], applicantIdsubmitId
审核通过POST /api/enroll/approveitemIds[], approverupdatedCount
审核退回POST /api/enroll/rejectitemId, reasonupdatedCount
汇总订单POST /api/order/summarizebatchId, supplierIdsorderList

这里重点说“提交填报”的入参和出参,因为它是教学秘书每天都要点的操作。入参里 batchId 必须校验批次是否处于“进行中”状态;items 是明细数组,每个元素包含 classId、courseId、textbookId、quantity;applicantId 从登录态获取,不允许前端传。返回参数统一为 code、message、data。错误码要在说明书里预先定义,例如 1001 批次不存在,1002 批次已截止,1003 教材已停用,1004 重复提交。前段可以拿 code 精确展示错误文案,而不是面对一个 500。

4.3 四个必须说清的参数:批次状态、数量取整、审核锁定、并发幂等

这部分是评审会上最容易被忽略却又最容易出故障的四个点,必须写进说明书。

第一个是批次状态的联动参数。subscription_batch 有两个时间字段,但状态不能仅仅由时间字段推导。比如学期还没到,即使数据库里时间到了,批次也不应该自动变成“已截止”。正确做法是维护状态字段,由定时任务在每天零点扫描 end_time,把超过截止时间的批次从“进行中”置为“已截止”。这样报表查询和权限控制都依赖状态字段,而不是依赖前端判断时间。

第二个是数量取整规则。教材征订经常碰到合班课、选修课,选课人数可能是一个班拆成两个方向。学生数量可能带小数?不会,但订单数量要按最小包装单位取整。我见过一个项目没有写取整规则,开发按四舍五入,结果 500.4 册书被算成 500 册,供应商发货时少了半本,实际按整本补。说明书里应写明:数量一律向上取整到整数,且取整规则放在后端统一处理,前端只展示结果。

第三个是审核锁定规则。当教务处点击“通过”后,这条明细的状态变成 approved,同时要有一个锁定标志,禁止任何人再修改数量。有时教学秘书在截止后才发现人数漏报,需要走“新增补报”流程,而不是直接改原明细。这就在状态机之外多了一个补报入口,说明书里要说明补报产生的明细与原明细如何关联,避免汇总时重复计算。

第四个是并发幂等参数。“提交填报”这个接口要支持幂等,前端生成唯一请求号 submitId,后端收到请求后先查这一批明细是否已经提交过,如果已提交则直接返回原结果。数据库层的唯一索引是兜底,但业务层也要有请求记录表,才能区分“用户重复点击”和“系统超时重试”。照这个思路写,开发就清楚该在哪个环节加锁、哪个环节查重。

5. 常见问题与避坑:征订系统从设计说明书到落地的五个坑

详细设计说明书写得再漂亮,落地时还是会碰到一堆实际坑。下面五条是我在多个类似项目里见到的高频问题,整理成“现象、原因、解决”三段式,你在写说明书的风险章节时可以直接参考。

5.1 订单汇总金额对不上,差几毛钱

现象是订单汇总表里的总金额和明细表里每一笔累计对不上,经常差几分钱。原因是 textbook 表的价格字段用了浮点型,或者“一次印刷价格调整”后没有保留历史版本,导致汇总时读到的是新价格,而填报人提交时看到的是旧价格。解决是金额一律用 decimal(10,2),并且把“教材价格”拆到独立版本表里,每次调价生成一条新版本记录,明细表保存当时的版本 id。说明书里要写清楚:汇总金额基于哪一版价格计算,谁来确认最终折扣,否则财务对账永远说不清。

5.2 教学秘书误填的数据直接进入汇总

现象是填报页只要点了保存,数据就出现在汇总列表里,教学秘书想改还要找管理员开后门。原因是设计时只设计了一个“是否提交”布尔字段,开发为了省事把保存和提交混在一起。解决是给 enroll_item 增加完整状态机,保存只落到草稿,提交才进入待审核。草稿数据不允许出现在汇总查询里。这个坑在说明书里如果不写,开发一定按最简单的布尔字段做,等到上线后需求方发现不对,返工成本就高了。

5.3 新学期启动后,上个学期的数据还在“填报中”

现象是新学期创建了征订批次,但各院系填报页还能看到上学期的旧数据,甚至还能继续提交。原因是批次状态没有在学期切换时自动迁移,开发只做了“批次启用”和“批次停用”两个操作,忘了“归档”。解决是批次状态至少要有四种:草稿、进行中、已截止、已归档。每学期结束时运行定时任务,把所有已截止批次自动置为已归档,归档后所有接口拒绝修改并只提供只读查询。说明书里要写清归档后哪些接口还能访问,哪些接口返回错误码。

5.4 教学秘书双击提交,生成两条一模一样的数据

现象是文件夹里出现两条相同明细,汇总后数量翻倍。原因是前端只做了按钮防抖,后端接口没有做幂等控制,两个请求几乎同时到了数据库,唯一索引如果没建就双份入库。解决是 enroll_item 表加组合唯一索引,接口层用 submitId 记录请求状态,同一个 submitId 多次调用只返回第一次结果。说明书要把这个规则放在接口设计的错误码里,明确 1004 表示重复提交,不能当成普通失败。

5.5 开发、测试、产品看的不是同一版说明书

现象是测试拿着旧文档写用例,开发按新需求改完代码,两边对不上,开会才发现有人用微信把文档传来传去覆盖了。原因是 doc 文件没有版本管理。解决是把详细设计说明书源稿放进 Git 仓库,文档里每个章节标注版本号,每次评审通过后打一次 tag。另外,网上有人用 wenku doc downloader 之类的工具从文库抓现成的详细设计说明书模板,我不是反对参考,而是提醒你,模板里的表名、状态码、角色划分都是别人的业务模型,直接套用等于把你自己的征订流程弯到别人的轨道上。拿模板做目录参考可以,拿它替代业务调研就是给自己挖坑。

6. 用需求追溯矩阵和版本管理把说明书变成活文档

最后分享一个我一直在用的验证技巧,不是泛泛的“写完要评审”,而是需求追溯矩阵。做法很简单:拿一个表格,把每一条需求编号和功能模块、数据库表、接口、测试用例对照起来。评审时一旦有人问“这个功能怎么没做”,就看矩阵里有没有对应编号和落点,没有就是需求没进设计,而不是吵来吵去。

以教材征订为例,追溯矩阵可以长这样:

需求编号需求描述功能模块核心表接口测试用例
REQ-001创建学期征订批次征订计划模块subscription_batchPOST /api/subscription/batchTC-001 批次时间校验
REQ-002院系按课程填报教材院系填报模块enroll_itemPOST /api/enroll/submitTC-011 重复提交拦截

矩阵建好之后,写详细设计说明书就有了路标:从一个需求出发,顺着矩阵检查是否所有字段都在表设计里有定义,所有操作是否在接口清单里有对应。用这个习惯,说明书就不会出现“需求里写了审核退回,但接口清单里只有审核通过”这种缺胳膊少腿的问题。

版本管理上,我的习惯是 doc 格式只用于评审打印和归档,真正的编辑源文件放在 Markdown 或在线文档里,每次变更记录一条更新说明。开发过程最怕的不是文档写得少,而是文档写得漂亮却没人按它执行。以前我不看重这些,结果有一版说明书改了接口参数没同步给前端,上线前两方吵得不可开交。后来每期都建追溯矩阵,返工明显少了。希望帮到你。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进