fix(consumable): 修复最大库存字段逻辑并改进耗材管理
将 maxStock 字段从允许 null 改为默认 0 表示无限制 添加耗材创建时的数据验证和错误处理 优化前端耗材管理页面的表单初始化和显示逻辑 添加数据库迁移脚本处理现有数据
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
const { sequelize } = require('./db');
|
||||
|
||||
async function fixMaxStock() {
|
||||
try {
|
||||
console.log('开始修复 maxStock 字段...');
|
||||
|
||||
// 检查当前表结构
|
||||
const [results] = await sequelize.query(
|
||||
"PRAGMA table_info(consumables);"
|
||||
);
|
||||
|
||||
console.log('当前表结构:');
|
||||
results.forEach(col => {
|
||||
console.log(` ${col.name}: ${col.type} ${col.notnull ? 'NOT NULL' : 'NULL'} default=${col.dflt_value}`);
|
||||
});
|
||||
|
||||
const maxStockCol = results.find(c => c.name === 'maxStock');
|
||||
if (maxStockCol) {
|
||||
console.log('\n当前 maxStock 字段:', maxStockCol);
|
||||
|
||||
// SQLite 不支持直接修改列,需要创建新表
|
||||
console.log('\n需要重建表结构...');
|
||||
|
||||
// 1. 创建新表
|
||||
await sequelize.query(`
|
||||
CREATE TABLE consumables_new (
|
||||
consumableId VARCHAR(255) PRIMARY KEY NOT NULL UNIQUE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
category VARCHAR(255) NOT NULL,
|
||||
unit VARCHAR(255) NOT NULL DEFAULT '个',
|
||||
currentStock INTEGER NOT NULL DEFAULT 0,
|
||||
minStock INTEGER NOT NULL DEFAULT 10,
|
||||
maxStock INTEGER NOT NULL DEFAULT 0,
|
||||
unitPrice DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||||
supplier VARCHAR(255),
|
||||
location VARCHAR(255),
|
||||
description TEXT,
|
||||
status VARCHAR(255) DEFAULT 'active',
|
||||
version INTEGER NOT NULL DEFAULT 0,
|
||||
createdAt DATETIME,
|
||||
updatedAt DATETIME
|
||||
)
|
||||
`);
|
||||
|
||||
// 2. 复制数据(将 null 转换为 0)
|
||||
await sequelize.query(`
|
||||
INSERT INTO consumables_new
|
||||
SELECT
|
||||
consumableId,
|
||||
name,
|
||||
category,
|
||||
unit,
|
||||
currentStock,
|
||||
minStock,
|
||||
COALESCE(maxStock, 0) as maxStock,
|
||||
unitPrice,
|
||||
supplier,
|
||||
location,
|
||||
description,
|
||||
status,
|
||||
version,
|
||||
createdAt,
|
||||
updatedAt
|
||||
FROM consumables
|
||||
`);
|
||||
|
||||
// 3. 删除旧表
|
||||
await sequelize.query('DROP TABLE consumables');
|
||||
|
||||
// 4. 重命名新表
|
||||
await sequelize.query('ALTER TABLE consumables_new RENAME TO consumables');
|
||||
|
||||
// 5. 创建索引
|
||||
await sequelize.query('CREATE INDEX consumables_category ON consumables(category)');
|
||||
await sequelize.query('CREATE INDEX consumables_status ON consumables(status)');
|
||||
await sequelize.query('CREATE INDEX consumables_category_status ON consumables(category, status)');
|
||||
await sequelize.query('CREATE INDEX consumables_updatedAt ON consumables(updatedAt)');
|
||||
|
||||
console.log('\n表结构修复完成!');
|
||||
|
||||
// 验证新表结构
|
||||
const [newResults] = await sequelize.query(
|
||||
"PRAGMA table_info(consumables);"
|
||||
);
|
||||
console.log('\n新表结构:');
|
||||
newResults.forEach(col => {
|
||||
console.log(` ${col.name}: ${col.type} ${col.notnull ? 'NOT NULL' : 'NULL'} default=${col.dflt_value}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n修复完成!');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('修复失败:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fixMaxStock();
|
||||
@@ -33,9 +33,9 @@ const Consumable = sequelize.define('Consumable', {
|
||||
},
|
||||
maxStock: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
comment: '最大库存,null表示无限制'
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '最大库存,0表示无限制'
|
||||
},
|
||||
unitPrice: {
|
||||
type: DataTypes.DECIMAL(10, 2),
|
||||
|
||||
@@ -53,7 +53,13 @@ router.get('/', async (req, res) => {
|
||||
router.post('/', async (req, res) => {
|
||||
const transaction = await sequelize.transaction();
|
||||
try {
|
||||
const consumable = await Consumable.create(req.body, { transaction });
|
||||
console.log('接收到的数据:', JSON.stringify(req.body, null, 2));
|
||||
const consumableData = {
|
||||
...req.body,
|
||||
consumableId: req.body.consumableId || `CON${Date.now()}`
|
||||
};
|
||||
console.log('处理后的数据:', JSON.stringify(consumableData, null, 2));
|
||||
const consumable = await Consumable.create(consumableData, { transaction });
|
||||
|
||||
await ConsumableLog.create({
|
||||
consumableId: consumable.consumableId,
|
||||
@@ -71,7 +77,13 @@ router.post('/', async (req, res) => {
|
||||
res.status(201).json(consumable);
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
res.status(400).json({ error: error.message });
|
||||
console.error('创建耗材错误:', error);
|
||||
if (error.name === 'SequelizeValidationError') {
|
||||
const messages = error.errors.map(e => `${e.path}: ${e.message}`).join(', ');
|
||||
res.status(400).json({ error: `Validation error: ${messages}` });
|
||||
} else {
|
||||
res.status(400).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user