Python+Django实战|企业办公用品申领管理系统:物资入库、库存预警、申领审批、归还登记、损耗统计、供应商对账

一、项目背景与痛点

企事业单位、办公园区、各类团队日常运转中,纸笔、文件夹、键鼠、饮用水、清洁用品等办公用品是高频消耗物资。目前多数单位仍采用人工登记、纸质申领单、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. 可视化分析

    • 物资消耗热力图展示
    • 成本分布饼状图分析
    • 库存变化趋势折线图

四、核心能力模块详解

1. 物资分类与档案管理模块

搭建标准化物资体系,区分消耗品与耐用品,为全流程管理打基础:

  • 多级分类:分为办公耗材、电子配件、清洁用品、劳保用品等一级分类,下设二级子类;
  • 物资档案:记录物资名称、规格、单位、参考单价、物资类型(消耗/耐用品);
  • 库存基数:设置安全库存阈值,作为预警依据;
  • 状态管控:区分正常、停用、淘汰三类物资状态。

2. 采购入库模块

统一登记采购信息,自动更新库存,留存入库台账:

  • 供应商关联:选择对应供货商家,记录采购单号、采购日期;
  • 批量入库:支持单种/多种物资批量录入数量、单价;
  • 库存联动:入库后自动累加当前库存数量;
  • 入库台账:所有采购记录永久留存,可按时间、供应商检索。

3. 库存监控与预警模块(核心亮点)

实时监控库存水位,杜绝物资断供与积压问题:

  • 实时库存:每笔领用、入库自动刷新库存数量;
  • 低库存预警:库存低于设置安全值时页面高亮提醒,推送补货提示;
  • 库存查询:按分类、名称快速检索物资现有存量;
  • 库存流水:查看物资出入库历史明细,追溯变动记录。

4. 员工申领与多级审批模块

线上化申领流程,告别纸质单据与跑腿签字:

  • 申领填写:员工选择物资、填写申领数量、使用事由;
  • 权限限制:可配置单人/部门月度领用限额,超额拦截;
  • 两级审批:部门主管初审 → 物资管理员终审;
  • 进度查询:员工可实时查看单据待审核、通过、驳回状态。

5. 领用与归还登记模块

区分消耗品与耐用品,差异化管理,防止资产流失:

  • 消耗品:申领通过后直接核销库存,无需归还;
  • 耐用品(电脑、工具等):登记借用时间,设置预计归还日期;
  • 归还核验:归还后更新状态,超时借用自动标记;
  • 领用台账:按员工、部门汇总领用记录。

6. 物资损耗统计模块

自动核算消耗数据,分析使用情况,辅助成本管控:

  • 部门统计:按部门统计月度/季度领用总量、对应成本;
  • 物资损耗:统计各类物资消耗占比,识别高消耗品类;
  • 异常分析:筛选高频超额领用记录,排查浪费行为;
  • 数据排行:各部门物资使用量排行展示。

7. 供应商管理与对账模块

统一管理供货商信息,简化月度对账工作:

  • 供应商档案:记录商家名称、联系方式、主营品类、合作状态;
  • 供货记录:关联该供应商所有采购单据;
  • 月度对账:按周期汇总采购金额、货品明细,生成对账清单;
  • 比价参考:留存历史采购单价,方便后期比价采购。

8. 单据检索与导出模块

各类台账单据可查询、可导出,满足行政与财务归档需求:

  • 多条件筛选:按时间、部门、人员、物资检索出入库、申领单据;
  • Excel导出:入库单、申领单、对账表一键导出;
  • 单据归档:电子单据长期保存,替代纸质档案。

五、创新价值与亮点

  1. 消耗品+耐用品差异化管理 针对一次性耗材和可循环借用物资采用不同流程,兼顾领用效率与资产安全;
  2. 库存智能预警 低于安全库存自动提醒补货,彻底解决临时缺料问题;
  3. 线上多级审批 全流程线上流转,免去纸质单据与线下签字,提升办公效率;
  4. 领用限额管控 配置部门/个人领用上限,有效遏制物资浪费,节约办公成本;
  5. 采购+领用+对账一体化 整合物资全链路业务,行政、财务对账一站式完成。

六、应用前景与落地场景

  • 中小型企业行政部 全公司办公用品统一采购、申领、库存管理;
  • 机关/事业单位
  • 单位公共物资规范化台账管理,满足审计要求;
  • 产业/商务园区
  • 园区公共物资、保洁、安防用品集中管控;
  • 多部门团队/项目部
  • 分部物资分区管理,数据相互隔离;
  • 毕业设计/求职项目 行政物资类管理系统,业务场景真实、实用性强。

七、完整代码结构示例

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流程开发与数据管控,也是毕业设计、求职简历中行政类系统的优质选择。

后续迭代规划

  1. 新增消息提醒,审批节点、库存预警、借用逾期自动推送通知;
  2. 支持多物资合并申领,一张单据申领多种办公用品;
  3. 新增月度采购计划功能,根据消耗数据自动生成采购清单;
  4. 开发移动端页面,手机端完成申领、审批、库存查询操作。

相关推荐
Wonderful U1 小时前
Python+Django实战|企业客户关系管理系统(CRM):客户档案、跟进记录、商机管理、合同签约、回款追踪、客户分层、数据分析
python·数据分析·django
plainGeekDev1 小时前
网络状态监听 → ConnectivityManager + Flow
android·java·kotlin
楠目1 小时前
CVE-2013-4547 Nginx URI解析漏洞利用总结
android
码云骑士1 小时前
18-生成器不只是省内存(上)-yield的状态机模型与帧暂停
c语言·开发语言·python
长空任鸟飞_阿康2 小时前
RAG 文档摄入全链路,从原理到生产落地
vue.js·人工智能·python
程序猿零零漆2 小时前
Python核心进阶三连:闭包装饰器、深浅拷贝、网络编程从原理到实战
网络·python
Coffeeee2 小时前
不能用公司的打包机,AI帮我实现了一套比打包机更好用的Android包构建/分发流程
android·人工智能·ai编程
yongche_shi2 小时前
ragas官方文档中文版(十六)
python·ai·智能体·ragas·使用工具
三块可乐两块冰2 小时前
rag学习5
linux·前端·python