进销存(采购、销售、库存)系统是管理层监控业务流程、提高运营效率的利器。而在进销存系统中,“基础数据板块”犹如系统的基石,它决定了后续业务环节的准确性和可扩展性。
- 为什么要讲进销存? 通过系统化管理,帮助企业降低库存成本、提升采购与销售决策效率; 为各部门协同提供统一数据平台,打破信息孤岛; 对接财务、生产、供应链等模块,实现全面数字化运维。
- 什么是进销存? 采购(进):从供应商处获取商品并入库; 销售(销):将产品出库并交付给客户; 库存(存):对仓库中物资的实时监控、管理与调拨。
- 基础数据板块如何搭建? 它涵盖了最核心的主数据:产品、仓库、供应商、客户、付款方式等; 打好基础数据的规范化与一致性,才能确保业务流程顺畅; 本文将以“产品”、“仓库”为例,手把手教你架构设计、流程图、代码示例与落地建议。
本文你将了解:
- 1.功能概述
- 2.产品(基础数据):产品信息管理、产品销售价格表、产品分类、产品信息查询
- 3.仓库(基础数据):仓库信息管理、仓位信息管理、辅助表:库区、货架、批次;仓库数据查询
- 4.数据流设计
- 5.开发架构
- 6.流程图解析
- 7.实现效果展示
//进销存系统--https://s.fanruan.com/zc378
二、功能概述
基础数据板块的主要职责:
- 数据录入与维护:通过页面或接口录入、更新主数据;
- 数据校验与规范:保证字段完整、格式统一、避免脏数据;
- 数据查询与导出:支持多维度查询、分页、Excel 导出;
- 权限与日志:根据角色控制增删改查权限,并记录操作日志。
这些功能看似简单,却对整个进销存系统的稳定性和用户体验有着决定性影响。
三、产品(基础数据)
1.产品信息管理
功能说明:管理 SKU、名称、型号、规格、条码、单位、品牌等核心信息。
表设计:sql
CREATE TABLE product ( id BIGINT PRIMARY KEY AUTO_INCREMENT, sku VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, model VARCHAR(100), spec VARCHAR(100), barcode VARCHAR(50), unit VARCHAR(20), brand VARCHAR(50), status TINYINT DEFAULT 1 COMMENT '1=启用,0=停用', created_at DATETIME, updated_at DATETIME);
后端接口示例(Spring Boot + MyBatis):java
@RestController@RequestMapping("/api/product")public class ProductController { @Autowired private ProductService productService; @PostMapping("/create") public ResponseVO<Long> create(@RequestBody ProductDTO dto) { Long id = productService.create(dto); return ResponseVO.success(id); } @PutMapping("/update") public ResponseVO<Boolean> update(@RequestBody ProductDTO dto) { return ResponseVO.success(productService.update(dto)); } @GetMapping("/list") public ResponseVO<PageVO<ProductVO>> list(ProductQuery query) { return ResponseVO.success(productService.list(query)); }}
前端示例(Vue3 + Element-Plus):html
<template> <el-form :model="formData" label-width="100px"> <el-form-item label="SKU"> <el-input v-model="formData.sku"></el-input> </el-form-item> <el-form-item label="名称"> <el-input v-model="formData.name"></el-input> </el-form-item> <!-- ... 其他字段 --> <el-form-item> <el-button type="primary" @click="onSubmit">保存</el-button> </el-form-item> </el-form> <el-table :data="tableData" stripe style="margin-top: 20px;"> <el-table-column prop="sku" label="SKU"/> <el-table-column prop="name" label="名称"/> <el-table-column prop="brand" label="品牌"/> <el-table-column prop="status" label="状态"> <template #default="{ row }"> <el-tag :type="row.status===1?'success':'info'"> {{ row.status===1?'启用':'停用' }} </el-tag> </template> </el-table-column> <el-table-column label="操作"> <template #default="{ row }"> <el-button size="mini" @click="edit(row)">编辑</el-button> </template> </el-table-column> </el-table></template><script setup>import { ref, onMounted } from 'vue';import { ElMessage } from 'element-plus';import api from '@/api';const formData = ref({ sku: '', name: '', model: '', spec: '', barcode: '', unit: '', brand: '', status: 1 });const tableData = ref([]);const loadList = async () => { const res = await api.product.list({ page: 1, size: 10 }); tableData.value = res.records;};const onSubmit = async () => { try { await api.product.create(formData.value); ElMessage.success('保存成功'); loadList(); } catch (e) { ElMessage.error('保存失败'); }};const edit = (row) => { formData.value = { ...row };};onMounted(loadList);</script>
2.产品销售价格表
功能说明:维护不同客户、不同渠道的价格策略,支持批量导入与周期生效。
表设计:sql
CREATE TABLE product_price ( id BIGINT AUTO_INCREMENT PRIMARY KEY, product_id BIGINT NOT NULL, customer_id BIGINT, channel VARCHAR(20), price DECIMAL(10,2) NOT NULL, effective_date DATE, created_at DATETIME, updated_at DATETIME, FOREIGN KEY (product_id) REFERENCES product(id));
核心代码(批量导入 Excel):java
public void importPrices(MultipartFile file) { List<ProductPriceDTO> list = ExcelUtil.read(file, ProductPriceDTO.class); list.forEach(dto -> productPriceMapper.upsert(dto));}
- Excel 模板:表头需包含 productSku、customerCode、channel、price、effectiveDate
- Upsert 实现:根据 product_id + customer_id + channel 唯一键冲突时更新价格
3.产品分类
功能说明:支持树形层级分类,便于后续查询与报表统计。
表设计:sql
CREATE TABLE product_category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, parent_id BIGINT DEFAULT 0, name VARCHAR(50) NOT NULL, level INT DEFAULT 1, sort_order INT DEFAULT 0);
获取分类树(MyBatis 递归查询):xml
<select id="listTree" resultType="ProductCategoryVO"> WITH RECURSIVE cte AS ( SELECT * FROM product_category WHERE parent_id=0 UNION ALL SELECT pc.* FROM product_category pc JOIN cte ON pc.parent_id = cte.id ) SELECT * FROM cte ORDER BY level, sort_order;</select>
前端树形展示(Element-Plus):html
<el-tree :data="treeData" node-key="id" default-expand-all :props="{ children: 'children', label: 'name' }"></el-tree>
4.产品信息查询
功能说明:结合分类、品牌、价格区间等多维度筛选,支持分页排序。
示例接口:java
public PageVO<ProductVO> query(ProductQuery query) { Page<Product> page = new Page<>(query.getPage(), query.getSize()); IPage<ProductVO> result = productMapper.query(page, query); return new PageVO<>(result.getTotal(), result.getRecords());}
SQL 示例:sql
SELECT p.*, pc.name AS category_name, pp.price FROM product p LEFT JOIN product_category pc ON p.category_id = pc.id LEFT JOIN ( SELECT product_id, MIN(price) AS price FROM product_price WHERE effective_date <= CURRENT_DATE() GROUP BY product_id ) pp ON p.id = pp.product_id WHERE p.status = 1 AND (p.brand = #{brand} OR #{brand} IS NULL) AND (pc.id = #{categoryId} OR #{categoryId} IS NULL) AND (pp.price BETWEEN #{minPrice} AND #{maxPrice}) ORDER BY p.updated_at DESC LIMIT #{offset}, #{size};
四、仓库(基础数据)
1.仓库信息管理
功能说明:包括仓库名称、地址、负责人、联系信息、启用状态等。
表设计:sql
CREATE TABLE warehouse ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, address VARCHAR(200), manager VARCHAR(50), contact VARCHAR(50), status TINYINT DEFAULT 1, created_at DATETIME, updated_at DATETIME);
2.仓位信息管理
功能说明:维护仓库内各仓位(库区、货架、货位)结构,支持容量与状态管理。
表设计:sql
CREATE TABLE location ( id BIGINT PRIMARY KEY AUTO_INCREMENT, warehouse_id BIGINT, zone VARCHAR(50), shelf VARCHAR(50), position VARCHAR(50), capacity INT, status TINYINT DEFAULT 1, created_at DATETIME, updated_at DATETIME, FOREIGN KEY (warehouse_id) REFERENCES warehouse(id));
3.辅助表:库区、货架、批次
- 库区表(zone)
CREATE TABLE zone ( code VARCHAR(20) PRIMARY KEY, name VARCHAR(50), warehouse_id BIGINT);
- 货架表(shelf)
CREATE TABLE shelf ( code VARCHAR(20) PRIMARY KEY, zone_code VARCHAR(20), level INT);
- 批次表(batch)
CREATE TABLE batch ( id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, warehouse_id BIGINT, batch_no VARCHAR(50), production_date DATE, expiry_date DATE);
4.仓库数据查询
查询示例:根据仓库、库区、货架维度,实时查看库存汇总。
sqlSELECT w.name AS warehouse, z.name AS zone, s.code AS shelf, SUM(st.qty) AS total_qty FROM stock st JOIN warehouse w ON st.warehouse_id = w.id JOIN zone z ON st.zone_code = z.code JOIN shelf s ON st.shelf_code = s.code GROUP BY w.name, z.name, s.code;
前端实时看板(ECharts + Vue):
jsimport * as echarts from 'echarts';const chart = echarts.init(document.getElementById('stock-chart'));chart.setOption({ title: { text: '库存汇总' }, tooltip: {}, xAxis: { type: 'category', data: ['仓库A-库区1', '仓库A-库区2', '仓库B-库区1'] }, yAxis: { type: 'value' }, series: [{ type: 'bar', data: [120, 200, 150] }]});
五、数据流设计
mermaidgraph TD; subgraph 基础数据板块 P[产品信息] --> PP[价格表] P --> PC[产品分类] W[仓库信息] --> L[仓位信息] L --> Z[库区] L --> S[货架] P & W & L -->|输出| BI[业务数据] end subgraph 业务模块 BI --> Procurement[采购模块] BI --> Sales[销售模块] BI --> Inventory[库存模块] end
- 说明:基础数据板块持续向各业务模块提供主数据;业务模块完成交易后,可通过事件通知依赖基础数据的其他环节。
六、开发架构
1.架构图
plantuml@startumlpackage "前端应用" { [Vue3] --> [API 网关]}package "后端服务" { [API 网关] --> [基础数据微服务] [API 网关] --> [业务数据微服务]}package "数据库" { [主数据 DB] [业务数据 DB]}[基础数据微服务] ..> [主数据 DB]@enduml
2.技术选型
- 前端:Vue3、Pinia、Element-Plus、ECharts;
- 后端:Spring Boot、MyBatis-Plus、Spring Cloud Gateway;
- 数据库:MySQL;
- 缓存:Redis;
- 消息队列:Kafka;
- 接口规范:OpenAPI 3.0;
- 部署:Docker、Kubernetes、Helm。
七、流程图解析
mermaidstateDiagram [*] --> 编辑页面 编辑页面 --> Validate: 输入校验 Validate --> Save: 保存请求 Save --> DB: 写入主数据表 DB --> MQ: 发布变更事件 MQ --> Cache: 更新缓存 DB --> Response: 返回结果 Response --> [*]
- 用户在前端录入或修改数据;
- 前端做基础校验后调用后台 API;
- 后端做业务校验(唯一约束、外键检查),持久化主数据表;
- 发布消息到 Kafka,以便下游缓存或搜索索引同步;
- 更新 Redis 缓存或 ElasticSearch 索引;
- 返回前端操作结果。
八、开发技巧与最佳实践
- 字段注释与字典表 所有字段统一做注释,枚举类型使用通用字典表维护,前后端动态拉取,便于扩展。
- 接口幂等设计 写操作(创建/修改)时传入唯一请求 ID,重复请求直接返回结果,防止双击或网络重试导致的重复创建。
- 分页优化 对大数据量列表,采用 Keyset Pagination(基于索引的游标分页),而非传统 OFFSET LIMIT。
- 权限控制 通过注解 + AOP 实现细粒度权限,按业务模块、操作类型(增删改查)管控。
- 缓存策略 基础数据相对静态,合理使用 Redis 缓存并结合消息队列做缓存失效/更新,保证一致性。
- 全链路监控 集成 OpenTelemetry + Prometheus + Grafana,监控 API 响应时间、数据库慢查询、消息队列堆积等。
- 自动化测试 后端接口使用 Postman/Newman 自动化回归测试;前端使用 Cypress 端到端测试;
- 数据库迁移 使用 Flyway 或 Liquibase 管理 schema 变更,确保多环境一致。
九、实现效果展示
- UI 界面: 产品管理、仓库管理、分类树、价格表、批量导入等模块一应俱全; 看板页面可自定义列、导出 Excel、打印报表。
- 接口测试: 100% 接口覆盖,集成 Postman 自动化测试; 自动生成 Swagger 文档,支持 Mock 和在线调试。
- 性能指标: 单表 200 万条数据分页查询平均 < 50ms; 批量导入(1 万行)处理时间 < 2s; Redis 缓存命中率 ≥ 95%。
- 日志监控: 集成 ELK(Stack) 实时查看操作日志与异常; 关键接口新增慢查询告警; Kafka 消息未消费告警。
十、常见问题解答(FAQ)
1. 为什么要把基础数据与业务数据分离在不同数据库?
- 将基础数据和业务数据分离有助于降低表之间的耦合度,提升读写性能,同时满足不同生命周期的数据管理需求。
- 基础数据(如产品、仓库信息)更新频率较低,但稳定性、准确性要求高;而业务数据(如出入库、销售订单)写入频繁且量大。如果放在同库同表容易造成热点表、锁竞争,影响整体系统性能。
- 此外,分库还能在权限、备份、容灾上做到更灵活的策略。
2. 当产品分类层级特别深时,如何保证查询性能?
对于深度树形结构,常见做法是:
1)使用闭包表(Closure Table)或物化路径(Materialized Path),将所有祖先信息存入辅助表或字段,查询时直接通过 LIKE 或表连接获取;
2)将分类树缓存到 Redis,当分类不频繁变更时,通过缓存读取,提高性能;
3)对极端大表,结合 ElasticSearch 做全文索引与过滤,分担数据库压力;
4)对于前端展示,可以分两步加载:“根节点+预加载下一级” 的惰性加载策略,避免一次性拉取过多数据。
以上即完整的“基础数据板块”开发指南,覆盖从需求、设计、实现到落地的各个环节。如需进一步定制化或覆盖供应商、客户等其他主数据模块,欢迎随时交流!