markdown复制## 1. 项目背景与需求分析
去年帮朋友的小公司梳理办公用品管理时,发现他们还在用Excel手工记录耗材出入库。行政人员每周要花3小时核对库存,漏记错记频发,月底盘点时实际库存和账面差异经常超过15%。这种场景在20人以下的小微企业尤为普遍——既用不起动辄上万的ERP系统,又承受着管理混乱带来的隐性成本。
这个库存管理软件正是瞄准这个痛点:为20人以下团队提供零学习成本的轻量级解决方案。核心要解决三个问题:
- 实时库存可视化(避免突然缺货)
- 自动化流水记录(取代手工台账)
- 低值易耗品预警(如墨盒余量监测)
与中大型企业的库存系统不同,小微场景需要特别关注:
1. 硬件成本:必须支持普通PC运行,不能要求服务器
2. 操作门槛:界面要比Excel更简单
3. 部署复杂度:最好能免安装直接使用
## 2. 技术方案选型
### 2.1 架构设计权衡
考虑过三种实现路径:
- **传统C/S架构**:用C#+SQLite(部署简单但跨平台差)
- **纯Web方案**:PHP+MySQL(需要环境配置)
- **混合方案**:Electron+本地数据库(最终选择)
选择Electron(17.0)+Vue3的组合基于以下实测数据:
- 打包后体积控制在80MB以内
- 内存占用峰值不超过300MB(实测10万条记录场景)
- 启动时间<2秒(机械硬盘环境)
> 关键提示:Electron应用体积优化必须配置:
> ```javascript
> // vue.config.js
> chainWebpack: config => {
> config.externals({
> 'electron': 'require("electron")',
> // 其他非必要依赖...
> })
> }
> ```
### 2.2 数据库选型对比
| 方案 | 写入速度(条/秒) | 10万数据体积 | 备份便利性 |
|-------------|----------------|-------------|-----------|
| SQLite | 850 | 12MB | 单文件拷贝 |
| IndexedDB | 1200 | 45MB | 需导出工具 |
| JSON文件 | 65 | 78MB | 直接可读 |
最终选用SQLite3的理由:
- 事务支持完善(避免并发修改冲突)
- 内置FTS5扩展(支持耗材名称模糊搜索)
- 与Node.js生态无缝集成
## 3. 核心功能实现细节
### 3.1 库存流水设计
采用双流水表结构解决历史追溯问题:
```sql
-- 当前库存快照表
CREATE TABLE stock (
item_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
spec TEXT, -- 规格如"A4/70g"
total INTEGER DEFAULT 0,
threshold INTEGER -- 预警阈值
);
-- 事务流水表
CREATE TABLE ledger (
id INTEGER PRIMARY KEY,
item_id INTEGER REFERENCES stock,
qty INTEGER, -- 正数为入库,负数为出库
operator TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
note TEXT
);
关键技巧:
- 使用触发器自动更新stock表:
sql复制CREATE TRIGGER update_stock AFTER INSERT ON ledger BEGIN UPDATE stock SET total = total + NEW.qty WHERE item_id = NEW.item_id; END; - 为timestamp字段建立索引(查询速度提升8倍)
3.2 条码扫描集成
通过串口通信对接常见扫码枪(如Honeywell 1900):
javascript复制const { SerialPort } = require('serialport')
const port = new SerialPort({
path: 'COM3',
baudRate: 9600,
dataBits: 8
})
port.on('data', data => {
const barcode = data.toString().trim()
// 与库存条目匹配逻辑...
})
常见问题处理:
- 乱码问题:设置正确的编码(通常GB18030)
- 重复读取:添加500ms防抖处理
- 特殊字符:过滤ASCII 0-31的控制字符
4. 实际部署中的经验教训
4.1 数据迁移陷阱
从Excel迁移数据时踩过的坑:
- 耗材名称不一致(如"HP 416墨盒" vs "惠普416黑色墨盒")
- 单位混乱(有的按"个",有的按"盒"记录)
解决方案:
- 开发预处理工具统一规范:
- 品牌别名标准化(HP→惠普)
- 单位自动换算(1盒=12支)
- 导入时强制关联旧编号:
sql复制INSERT INTO stock (name, spec, total) VALUES (?, ?, ?) RETURNING item_id;
4.2 打印功能优化
小企业常用针式打印机(如EPSON LQ-630K),需特殊处理:
javascript复制const escpos = require('escpos')
escpos.USB = require('escpos-usb')
const device = new escpos.USB(0x04b8, 0x0202) // 厂商ID/产品ID
device.open(err => {
const printer = new escpos.Printer(device)
printer
.font('B')
.align('CT')
.text('耗材领用单')
.cut()
.close()
})
重要提醒:Windows系统需要先安装打印机驱动,否则会报"ENOENT"错误
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
5. 扩展性设计
5.1 多仓库支持
通过location字段扩展:
sql复制ALTER TABLE stock ADD COLUMN location TEXT DEFAULT '主仓库';
ALTER TABLE ledger ADD COLUMN location TEXT;
界面添加仓库切换器:
vue复制<select v-model="currentLocation">
<option v-for="loc in locations" :value="loc">
{{ loc }}
</option>
</select>
5.2 耗材图片管理
使用Base64存储小图(<100KB):
javascript复制function fileToBase64(file) {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onload = e => resolve(e.target.result)
reader.readAsDataURL(file)
})
}
数据库新增字段:
sql复制ALTER TABLE stock ADD COLUMN image TEXT;
6. 性能优化实录
当库存记录超过5万条时遇到的卡顿问题:
问题现象:
- 耗材查询响应时间>3秒
- 领用操作延迟明显
解决方案:
- 添加复合索引:
sql复制CREATE INDEX idx_stock_search ON stock(name, spec); - 分页加载(每页50条):
sql复制SELECT * FROM ledger WHERE item_id = ? ORDER BY timestamp DESC LIMIT 50 OFFSET ?; - 预计算常用统计:
sql复制-- 每日使用量物化视图 CREATE TABLE stats_daily AS SELECT date(timestamp) as day, item_id, SUM(-qty) as used_qty FROM ledger WHERE qty < 0 GROUP BY day, item_id;
优化后效果:
- 查询响应<200ms
- 内存占用降低40%
7. 替代方案对比
与常见办公软件的库存管理功能对比:
| 功能 | 本系统 | Excel | 钉钉 | 企业微信 |
|---|---|---|---|---|
| 条码扫描 | ✓ | ✗ | ✗ | ✗ |
| 实时库存预警 | ✓ | ✗ | ✓ | ✓ |
| 离线使用 | ✓ | ✓ | ✗ | ✗ |
| 领用审批流 | ✗ | ✗ | ✓ | ✓ |
| 数据迁移成本 | 中 | 无 | 高 | 高 |
适合本系统的场景:
- 无专职IT人员的小团队
- 已有扫码枪等硬件设备
- 对审批流程要求不高
8. 实际部署案例
在某设计公司(15人团队)的落地数据:
部署前:
- 每月耗材浪费约1200元
- 平均每周2次紧急采购
- 库存盘点误差率18%
部署后:
- 设置预警阈值后浪费降低至300元/月
- 实现提前3天补货
- 误差率降至3%以下
典型问题处理记录:
- 扫码枪偶尔漏读:
- 原因:USB供电不足
- 解决:更换带外接电源的USB Hub
- 历史数据查询慢:
- 原因:未按月份分表
- 解决:按年月自动分表(ledger_202301)
9. 后续升级方向
-
移动端适配:
- 使用Capacitor打包为Android/iOS应用
- 增加拍照入库功能
-
供应商对接:
- 通过邮件自动发送补货清单
- 集成电商平台API比价采购
-
耗材寿命预测:
- 基于历史数据预测更换周期
- 如"每月平均消耗3个墨盒"
在现有架构下,这些功能都可以通过插件形式逐步添加,而无需重构核心代码。比如供应商对接模块可以单独打包为supplier-plugin.js,按需加载。```
