一、项目背景与痛点
企事业单位、办公园区、各类团队日常运转中,纸笔、文件夹、键鼠、饮用水、清洁用品等办公用品是高频消耗物资。目前多数单位仍采用人工登记、纸质申领单、Excel台账的管理方式,随着人员增多、物资品类变多,管理乱象频发,核心痛点总结如下:
- 入库出库台账混乱:物资采购入库、员工领用全靠手写登记,账目分散,物资流向无法追溯,账实不符问题普遍;
- 库存管控缺失:无法实时查看剩余库存,经常出现物资耗尽才紧急采购,影响正常办公,也无低库存自动提醒;
- 申领流程繁琐:员工填写纸质单据、逐层签字审批,来回跑腿效率低,审批进度无法实时查询;
- 借用物资无归还机制:电脑、打印机、工具等非消耗品被领用后长期不归还,资产流失严重;
- 损耗与成本无法统计:各部门领用总量、物资月度损耗、采购成本依靠人工核算,财务对账难度大;
- 供应商管理零散:多家供货商家信息、历史报价、对账记录没有统一台账,比价、结算十分不便;
- 部门领用无管控:无领用限额设置,部分人员过度申领造成物资浪费,无法规范节约办公成本。
针对传统办公用品管理的各类弊端,本次基于Python+Django4.2+MySQL+Ajax+ECharts 搭建轻量化办公用品申领管理系统,实现物资分类、采购入库、库存预警、线上申领、多级审批、借用归还、损耗统计、供应商对账全套闭环能力。本项目开辟办公物资管理 全新赛道,和日志、天气、智能在线考试、智能图书、考勤、会议室、固定资产、CRM、售后、教培排课等往期所有项目业务、功能、代码完全无重复。
二、核心目标与定位
本项目核心目标:搭建数字化办公用品全流程管理平台,实现物资分类建档→采购入库→库存实时监控→员工线上申领→多级审批→物资领用/借用→到期归还→损耗统计→供应商对账完整闭环,替代纸质单据与Excel台账,规范申领流程、严控库存、减少浪费、精准核算办公物资成本。
项目精准定位:面向政企单位、中小企业、办公园区的轻量化物资管理系统,采用Django原生MVT架构,部署简单、资源占用低;划分系统管理员、物资管理员、部门主管、普通员工四类角色,权限逐级隔离、数据按部门区分;适配行政部门统一管控全公司办公用品的场景,主打流程线上化、库存可视化、成本可量化、对账便捷化。
核心设计理念:物资分类标准化、出入库台账电子化、申领审批流程化、库存预警智能化、成本统计自动化,解决传统办公物资管理低效、浪费、账目不清的核心问题。
三、整体技术方案
本项目基于 Django 原生 MVT 分层架构开发,采用模块化设计思想,将办公物资管理系统拆分为多个核心功能层,各层之间通过清晰的接口进行数据交互。整体技术方案围绕"数据驱动、流程闭环、权限隔离、可视化分析"四大核心理念构建。
3.1 系统分层架构
系统采用七层架构设计,从物资分类到供应商对账形成完整业务闭环:
#mermaid-svg-THvv3PRTRmMlc2og{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-THvv3PRTRmMlc2og .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-THvv3PRTRmMlc2og .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-THvv3PRTRmMlc2og .error-icon{fill:#552222;}#mermaid-svg-THvv3PRTRmMlc2og .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-THvv3PRTRmMlc2og .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-THvv3PRTRmMlc2og .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-THvv3PRTRmMlc2og .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-THvv3PRTRmMlc2og .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-THvv3PRTRmMlc2og .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-THvv3PRTRmMlc2og .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-THvv3PRTRmMlc2og .marker{fill:#333333;stroke:#333333;}#mermaid-svg-THvv3PRTRmMlc2og .marker.cross{stroke:#333333;}#mermaid-svg-THvv3PRTRmMlc2og svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-THvv3PRTRmMlc2og p{margin:0;}#mermaid-svg-THvv3PRTRmMlc2og .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-THvv3PRTRmMlc2og .cluster-label text{fill:#333;}#mermaid-svg-THvv3PRTRmMlc2og .cluster-label span{color:#333;}#mermaid-svg-THvv3PRTRmMlc2og .cluster-label span p{background-color:transparent;}#mermaid-svg-THvv3PRTRmMlc2og .label text,#mermaid-svg-THvv3PRTRmMlc2og span{fill:#333;color:#333;}#mermaid-svg-THvv3PRTRmMlc2og .node rect,#mermaid-svg-THvv3PRTRmMlc2og .node circle,#mermaid-svg-THvv3PRTRmMlc2og .node ellipse,#mermaid-svg-THvv3PRTRmMlc2og .node polygon,#mermaid-svg-THvv3PRTRmMlc2og .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-THvv3PRTRmMlc2og .rough-node .label text,#mermaid-svg-THvv3PRTRmMlc2og .node .label text,#mermaid-svg-THvv3PRTRmMlc2og .image-shape .label,#mermaid-svg-THvv3PRTRmMlc2og .icon-shape .label{text-anchor:middle;}#mermaid-svg-THvv3PRTRmMlc2og .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-THvv3PRTRmMlc2og .rough-node .label,#mermaid-svg-THvv3PRTRmMlc2og .node .label,#mermaid-svg-THvv3PRTRmMlc2og .image-shape .label,#mermaid-svg-THvv3PRTRmMlc2og .icon-shape .label{text-align:center;}#mermaid-svg-THvv3PRTRmMlc2og .node.clickable{cursor:pointer;}#mermaid-svg-THvv3PRTRmMlc2og .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-THvv3PRTRmMlc2og .arrowheadPath{fill:#333333;}#mermaid-svg-THvv3PRTRmMlc2og .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-THvv3PRTRmMlc2og .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-THvv3PRTRmMlc2og .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-THvv3PRTRmMlc2og .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-THvv3PRTRmMlc2og .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-THvv3PRTRmMlc2og .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-THvv3PRTRmMlc2og .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-THvv3PRTRmMlc2og .cluster text{fill:#333;}#mermaid-svg-THvv3PRTRmMlc2og .cluster span{color:#333;}#mermaid-svg-THvv3PRTRmMlc2og div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-THvv3PRTRmMlc2og .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-THvv3PRTRmMlc2og rect.text{fill:none;stroke-width:0;}#mermaid-svg-THvv3PRTRmMlc2og .icon-shape,#mermaid-svg-THvv3PRTRmMlc2og .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-THvv3PRTRmMlc2og .icon-shape p,#mermaid-svg-THvv3PRTRmMlc2og .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-THvv3PRTRmMlc2og .icon-shape .label rect,#mermaid-svg-THvv3PRTRmMlc2og .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-THvv3PRTRmMlc2og .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-THvv3PRTRmMlc2og .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-THvv3PRTRmMlc2og :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 底层技术底座
后端框架:Python3.11 + Django4.2
数据存储:MySQL 8.0
时间处理:datetime 模块
前端交互:Ajax 技术
状态管理:自定义枚举类
权限体系:多角色+部门中间件
数据统计:ORM 聚合函数
可视化:ECharts 图表库
物资分类层
品类划分、物资档案维护
采购入库层
采购登记、批量入库、台账记录
库存监控层
实时库存、低库存预警
申领提交层
员工选择物资、填写申领数量
多级审批层
部门主管+物资管理员审核
领用归还层
消耗品核销、耐用品归还登记
损耗统计层
部门领用、物资损耗统计
供应商对账层
供货记录、月度对账、成本核算
3.2 核心技术栈清单
后端技术栈
- Web 框架:Python 3.11 + Django 4.2 原生 MVT 轻量化架构
- 数据库:MySQL 8.0,结构化存储办公物资全链路数据
- 时间处理:datetime 模块实现借用时长、入库时间计算
- 异步交互:Ajax 技术完成申领、审批、状态切换无刷新操作
- 状态管控:自定义枚举类,统一管理库存、单据、归还状态
- 权限控制:自定义中间件,实现四类角色+部门双重数据隔离
- 数据计算:Django ORM 聚合函数统计领用、损耗、采购金额
前端与可视化
- 数据可视化:ECharts 制作物资消耗、成本分析图表
- 交互体验:基于 Ajax 的无刷新操作,提升用户体验
- 响应式设计:适配不同屏幕尺寸的管理界面
3.3 核心设计理念
-
数据驱动决策
- 实时库存监控与预警机制
- 物资消耗趋势分析与预测
- 采购成本与供应商绩效评估
-
流程闭环管理
- 从采购到报废的全生命周期跟踪
- 多级审批流程确保合规性
- 领用-归还-损耗的完整记录链
-
权限精细管控
- 基于角色+部门的双重权限体系
- 数据隔离保障信息安全
- 操作日志全程可追溯
-
可视化分析
- 物资消耗热力图展示
- 成本分布饼状图分析
- 库存变化趋势折线图
四、核心能力模块详解
1. 物资分类与档案管理模块
搭建标准化物资体系,区分消耗品与耐用品,为全流程管理打基础:
- 多级分类:分为办公耗材、电子配件、清洁用品、劳保用品等一级分类,下设二级子类;
- 物资档案:记录物资名称、规格、单位、参考单价、物资类型(消耗/耐用品);
- 库存基数:设置安全库存阈值,作为预警依据;
- 状态管控:区分正常、停用、淘汰三类物资状态。
2. 采购入库模块
统一登记采购信息,自动更新库存,留存入库台账:
- 供应商关联:选择对应供货商家,记录采购单号、采购日期;
- 批量入库:支持单种/多种物资批量录入数量、单价;
- 库存联动:入库后自动累加当前库存数量;
- 入库台账:所有采购记录永久留存,可按时间、供应商检索。
3. 库存监控与预警模块(核心亮点)
实时监控库存水位,杜绝物资断供与积压问题:
- 实时库存:每笔领用、入库自动刷新库存数量;
- 低库存预警:库存低于设置安全值时页面高亮提醒,推送补货提示;
- 库存查询:按分类、名称快速检索物资现有存量;
- 库存流水:查看物资出入库历史明细,追溯变动记录。
4. 员工申领与多级审批模块
线上化申领流程,告别纸质单据与跑腿签字:
- 申领填写:员工选择物资、填写申领数量、使用事由;
- 权限限制:可配置单人/部门月度领用限额,超额拦截;
- 两级审批:部门主管初审 → 物资管理员终审;
- 进度查询:员工可实时查看单据待审核、通过、驳回状态。
5. 领用与归还登记模块
区分消耗品与耐用品,差异化管理,防止资产流失:
- 消耗品:申领通过后直接核销库存,无需归还;
- 耐用品(电脑、工具等):登记借用时间,设置预计归还日期;
- 归还核验:归还后更新状态,超时借用自动标记;
- 领用台账:按员工、部门汇总领用记录。
6. 物资损耗统计模块
自动核算消耗数据,分析使用情况,辅助成本管控:
- 部门统计:按部门统计月度/季度领用总量、对应成本;
- 物资损耗:统计各类物资消耗占比,识别高消耗品类;
- 异常分析:筛选高频超额领用记录,排查浪费行为;
- 数据排行:各部门物资使用量排行展示。
7. 供应商管理与对账模块
统一管理供货商信息,简化月度对账工作:
- 供应商档案:记录商家名称、联系方式、主营品类、合作状态;
- 供货记录:关联该供应商所有采购单据;
- 月度对账:按周期汇总采购金额、货品明细,生成对账清单;
- 比价参考:留存历史采购单价,方便后期比价采购。
8. 单据检索与导出模块
各类台账单据可查询、可导出,满足行政与财务归档需求:
- 多条件筛选:按时间、部门、人员、物资检索出入库、申领单据;
- Excel导出:入库单、申领单、对账表一键导出;
- 单据归档:电子单据长期保存,替代纸质档案。
五、创新价值与亮点
- 消耗品+耐用品差异化管理 针对一次性耗材和可循环借用物资采用不同流程,兼顾领用效率与资产安全;
- 库存智能预警 低于安全库存自动提醒补货,彻底解决临时缺料问题;
- 线上多级审批 全流程线上流转,免去纸质单据与线下签字,提升办公效率;
- 领用限额管控 配置部门/个人领用上限,有效遏制物资浪费,节约办公成本;
- 采购+领用+对账一体化 整合物资全链路业务,行政、财务对账一站式完成。
六、应用前景与落地场景
- 中小型企业行政部 全公司办公用品统一采购、申领、库存管理;
- 机关/事业单位
- 单位公共物资规范化台账管理,满足审计要求;
- 产业/商务园区
- 园区公共物资、保洁、安防用品集中管控;
- 多部门团队/项目部
- 分部物资分区管理,数据相互隔离;
- 毕业设计/求职项目 行政物资类管理系统,业务场景真实、实用性强。
七、完整代码结构示例
1. 项目整体目录结构
python
django-office-supplies/
├── manage.py
├── supplies_project/
│ ├── settings.py # 数据库、库存阈值、权限配置
│ ├── urls.py # 全局路由分发
│ └── middleware.py # 角色&部门权限中间件
├── apps/
│ ├── user_dept_role/ # 用户、部门、角色权限模块
│ ├── goods_category/ # 物资分类、档案模块
│ ├── purchase_in/ # 采购入库、入库台账模块
│ ├── stock_warn/ # 库存监控、低库存预警模块
│ ├── apply_order/ # 物资申领、单据模块
│ ├── audit_flow/ # 多级审批流程模块
│ ├── borrow_back/ # 借用、归还登记模块
│ ├── loss_stat/ # 领用损耗统计模块
│ └── supplier_book/ # 供应商、对账模块
├── core/
│ ├── stock_check.py # 库存预警校验工具
│ ├── time_calc.py # 借用时长、时间计算工具
│ ├── limit_check.py # 领用限额校验工具
│ └── excel_export.py # 单据导出工具
├── static/
├── templates/
├── media/
├── requirements.txt
└── readme.md
</pre>
### 2. 核心可运行代码片段
#### 示例1:物资、入库、申领、归还、供应商核心数据模型
```python
from django.db import models
from django.contrib.auth.models
# 物资类型
GOODS_TYPE = (
("consume", "消耗品"),
("durables", "耐用品"),
)
# 申领单据状态
APPLY_STATUS = (
("wait_dept", "部门待审"),
("wait_admin", "物资待审"),
("pass", "审批通过"),
("reject", "审批驳回"),
)
# 借用状态
BORROW_STATUS = (
("borrow", "借用中"),
("back", "已归还"),
("overdue", "逾期未还"),
)
class Supplier(models.Model):
"""供应商模型"""
sup_name = models.CharField(max=50, verbose="供应商名称")
phone = models.CharField(max=11, verbose="联系电话")
main_goods = models.CharField(max=100, verbose="主营物资")
is_valid = models.BooleanField(default=True, verbose="是否合作")
create_time = models.DateTimeField(auto_now_add=True)
class GoodsCategory(models.Model):
"""物资分类"""
cat_name = models.CharField(max=50, verbose="分类名称")
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL)
create_time = models.DateTimeField(auto_now_add=True)
class OfficeGoods(models.Model):
"""办公用品主模型"""
category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE)
goods_name = models.CharField(max=60, verbose="物资名称")
spec = models.CharField(max=40, blank=True, verbose="规格")
unit = models.CharField(max=10, verbose="单位")
price = models.DecimalField(max_digits=8, decimal_places=2, verbose="参考单价")
goods_type = models.CharField(max=10, choices=GOODS_TYPE)
stock = models.IntegerField(default=0, verbose="当前库存")
safe_stock = models.IntegerField(default=10, verbose="安全库存")
is_enable = models.BooleanField(default=True)
create_time = models.DateTimeField(auto_now_add=True)
class PurchaseRecord(models.Model):
"""采购入库记录"""
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
goods = models.ForeignKey(OfficeGoods, on_delete=models.CASCADE)
purchase_num = models.IntegerField(verbose="采购数量")
purchase_price = models.DecimalField(max_digits=8, decimal_places=2)
purchase_time = models.DateTime()
create_time = models.DateTime(auto_now_add=True)
class ApplyOrder(models.Model):
"""物资申领单"""
apply_user = models.ForeignKey(User, on_delete=models.CASCADE, related="apply_user")
dept = models.CharField(max=50, verbose="所属部门")
goods = models.ForeignKey(OfficeGoods, on_delete=models.CASCADE)
apply_num = models.IntegerField(verbose="申领数量")
reason = models.TextField(blank=True, verbose="申领事由")
apply_status = models.CharField(max=12, choices=APPLY_STATUS, default="wait_dept")
create_time = models.DateTime(auto_now_add=True)
class BorrowRecord(models.Model):
"""耐用品借用归还记录"""
apply_order = models.ForeignKey(ApplyOrder, on_delete=models.CASCADE)
borrow_user = models.ForeignKey(User, on_delete=models.CASCADE)
borrow_time = models.DateTime(verbose="借用时间")
expect_back = models.DateTime(verbose="预计归还时间")
actual_back = models.DateTime(null=True, blank=True)
borrow_status = models.CharField(max=10, choices=BORROW_STATUS, default="borrow")
create_time = models.DateTime(auto_now_add=True)
示例2:库存预警校验工具(core/stock_check.py)
python
class StockCheck:
"""库存预警校验"""
@classmethod
def is_warn(cls, goods_obj):
"""判断是否低于安全库存"""
return goods.stock <= goods.safe_stock
示例3:物资申领提交视图
python
from django.views import View
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.shortcuts import redirect
from django.contrib import messages
from apps.goods_category.models import OfficeGoods
from apps.apply_order.models import ApplyOrder
from core.limit_check import LimitCheck
@method_decorator(login_required, name="dispatch")
class ApplyGoodsView(View):
def post(self, request):
goods_id = request.POST.get("goods_id")
apply_num = int(request.POST.get("num", 0))
dept = request.POST.get("dept")
reason = request.POST.get("reason")
# 基础校验
if apply_num <= 0:
messages.error("申领数量必须大于0!")
return redirect("apply_goods")
try:
goods = OfficeGoods.objects.get(id=goods_id, is_enable=True)
except OfficeGoods.DoesNotExist:
messages.error("物资不存在或已停用!")
return redirect("apply_goods")
# 校验库存
if apply_num > goods.stock:
messages.error("申领数量超出当前库存!")
return redirect("apply_goods")
# 校验部门领用限额
if not LimitCheck.check_dept_limit(request.user, dept, apply_num):
messages.error("本月该部门领用已达上限,无法继续申领!")
return redirect("apply_goods")
# 创建申领单
ApplyOrder.objects.create(
apply_user=request.user,
dept=dept,
goods=goods,
apply_num=apply_num,
reason=reason
)
messages.success("申领单提交成功,等待部门审核!")
return redirect("apply_list")
八、总结与展望
本篇博客聚焦企业办公用品物资管理 全新赛道,基于Python+Django打造采购、库存、申领、审批、归还、对账一体化系统,和日志、天气、智能在线考试、智能图书、考勤、会议室、固定资产、CRM、售后、教培排课等所有往期项目完全独立。项目融合库存算法、流程审批、多角色权限、台账管理、数据统计、Excel导出等技术,深度贴合企业行政日常工作,业务落地性极强。
系统区分消耗品与耐用品的差异化管理,结合库存预警、领用限额等实用功能,既适合学习Django流程开发与数据管控,也是毕业设计、求职简历中行政类系统的优质选择。
后续迭代规划
- 新增消息提醒,审批节点、库存预警、借用逾期自动推送通知;
- 支持多物资合并申领,一张单据申领多种办公用品;
- 新增月度采购计划功能,根据消耗数据自动生成采购清单;
- 开发移动端页面,手机端完成申领、审批、库存查询操作。