ota 拓展功能-黑名单&灰色定向上线
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
const Ota = require('./Ota');
|
||||
|
||||
const BlackList = sequelize.define('BlackList', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
comment: 'ID',
|
||||
},
|
||||
ota_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'ota_id',
|
||||
comment: '关联 OTA 版本 ID',
|
||||
},
|
||||
mac: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: 'MAC 地址',
|
||||
},
|
||||
create_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间',
|
||||
},
|
||||
}, {
|
||||
tableName: 'black_list',
|
||||
comment: 'OTA 黑名单',
|
||||
});
|
||||
|
||||
BlackList.belongsTo(Ota, { foreignKey: 'ota_id', as: 'ota' });
|
||||
|
||||
module.exports = BlackList;
|
||||
@@ -0,0 +1,37 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
const Ota = require('./Ota');
|
||||
|
||||
const OtaTargetDevice = sequelize.define('OtaTargetDevice', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
comment: 'ID',
|
||||
},
|
||||
ota_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
field: 'ota_id',
|
||||
comment: '关联 OTA 版本 ID',
|
||||
},
|
||||
mac_addr: {
|
||||
type: DataTypes.STRING(17),
|
||||
allowNull: false,
|
||||
field: 'mac_addr',
|
||||
comment: 'MAC 地址',
|
||||
},
|
||||
create_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间',
|
||||
},
|
||||
}, {
|
||||
tableName: 'ota_target_device',
|
||||
comment: '定向升级设备',
|
||||
});
|
||||
|
||||
OtaTargetDevice.belongsTo(Ota, { foreignKey: 'ota_id', as: 'ota' });
|
||||
|
||||
module.exports = OtaTargetDevice;
|
||||
@@ -1,7 +1,9 @@
|
||||
const Brand = require('./Brand');
|
||||
const Model = require('./Model');
|
||||
const Ota = require('./Ota');
|
||||
const BlackList = require('./BlackList');
|
||||
const OtaTargetDevice = require('./OtaTargetDevice');
|
||||
const ShareCodeLog = require('./ShareCodeLog');
|
||||
const DashboardUser = require('./DashboardUser');
|
||||
|
||||
module.exports = { Brand, Model, Ota, ShareCodeLog, DashboardUser };
|
||||
module.exports = { Brand, Model, Ota, BlackList, OtaTargetDevice, ShareCodeLog, DashboardUser };
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* 黑名单路由
|
||||
*/
|
||||
const router = require('express').Router();
|
||||
const { Op } = require('sequelize');
|
||||
const BlackList = require('../models/BlackList');
|
||||
const Ota = require('../models/Ota');
|
||||
const logger = require('../config/logger');
|
||||
const { ApiResponse } = require('../utils/response');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
const { BlackListCreateSchema, BlackListUpdateSchema } = require('../validators/blacklist');
|
||||
|
||||
// 所有接口需登录
|
||||
router.use('/api/blacklist', authMiddleware);
|
||||
|
||||
// GET /api/blacklist/
|
||||
router.get('/api/blacklist/', async (req, res) => {
|
||||
try {
|
||||
const skip = parseInt(req.query.skip || '0', 10);
|
||||
const limit = Math.min(parseInt(req.query.limit || '100', 10), 1000);
|
||||
const otaId = req.query.ota_id !== undefined ? parseInt(req.query.ota_id, 10) : null;
|
||||
const model = req.query.model;
|
||||
const mac = req.query.mac;
|
||||
|
||||
const where = {};
|
||||
if (otaId !== null && !isNaN(otaId)) where.ota_id = otaId;
|
||||
if (mac) where.mac = { [Op.like]: `%${mac}%` };
|
||||
|
||||
// 如果按 model 筛选,需先查出对应 model 的 ota_id 列表
|
||||
if (model) {
|
||||
const otaIds = await Ota.findAll({
|
||||
where: { model: { [Op.like]: `%${model}%` } },
|
||||
attributes: ['id'],
|
||||
});
|
||||
const ids = otaIds.map((o) => o.id);
|
||||
if (ids.length === 0) {
|
||||
return res.json(ApiResponse.success({ items: [], total: 0, skip, limit }));
|
||||
}
|
||||
if (where.ota_id !== undefined) {
|
||||
where.ota_id = { [Op.and]: [where.ota_id, { [Op.in]: ids }] };
|
||||
} else {
|
||||
where.ota_id = { [Op.in]: ids };
|
||||
}
|
||||
}
|
||||
|
||||
const total = await BlackList.count({ where });
|
||||
const rows = await BlackList.findAll({
|
||||
where,
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
offset: skip,
|
||||
limit,
|
||||
order: [['id', 'DESC']],
|
||||
});
|
||||
|
||||
logger.info(`Found ${rows.length} BlackList records, total=${total}`);
|
||||
|
||||
if (!rows.length) {
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
const items = rows.map(blacklistToDict);
|
||||
return res.json(ApiResponse.success({ items, total, skip, limit }));
|
||||
} catch (e) {
|
||||
logger.error(`Error getting BlackList: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/blacklist/:id
|
||||
router.get('/api/blacklist/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
logger.info(`Getting BlackList: id=${id}`);
|
||||
const item = await BlackList.findByPk(id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
if (!item) {
|
||||
logger.warn(`BlackList not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
return res.json(ApiResponse.success(blacklistToDict(item)));
|
||||
} catch (e) {
|
||||
logger.error(`Error getting BlackList ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/blacklist/
|
||||
router.post('/api/blacklist/', async (req, res) => {
|
||||
try {
|
||||
const parsed = BlackListCreateSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
const errors = parsed.error.errors.map((e) => e.message).join('; ');
|
||||
return res.json(ApiResponse.error(errors));
|
||||
}
|
||||
|
||||
const data = parsed.data;
|
||||
logger.info(`Creating BlackList: ota_id=${data.ota_id}, mac=${data.mac}`);
|
||||
|
||||
// 校验 OTA 是否存在
|
||||
const ota = await Ota.findByPk(data.ota_id);
|
||||
if (!ota) {
|
||||
return res.json(ApiResponse.error('OTA 版本不存在'));
|
||||
}
|
||||
|
||||
const item = await BlackList.create(data);
|
||||
logger.info(`BlackList created: id=${item.id}`);
|
||||
|
||||
// 重新加载关联数据
|
||||
const created = await BlackList.findByPk(item.id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
|
||||
return res.json(ApiResponse.success(blacklistToDict(created)));
|
||||
} catch (e) {
|
||||
logger.error(`Error creating BlackList: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/blacklist/:id
|
||||
router.put('/api/blacklist/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
|
||||
const parsed = BlackListUpdateSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
const errors = parsed.error.errors.map((e) => e.message).join('; ');
|
||||
return res.json(ApiResponse.error(errors));
|
||||
}
|
||||
|
||||
const data = parsed.data;
|
||||
logger.info(`Updating BlackList: id=${id}`);
|
||||
|
||||
const item = await BlackList.findByPk(id);
|
||||
if (!item) {
|
||||
logger.warn(`BlackList not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
// 如果更新 ota_id,校验 OTA 是否存在
|
||||
if (data.ota_id !== undefined && data.ota_id !== null && data.ota_id !== item.ota_id) {
|
||||
const ota = await Ota.findByPk(data.ota_id);
|
||||
if (!ota) {
|
||||
return res.json(ApiResponse.error('OTA 版本不存在'));
|
||||
}
|
||||
}
|
||||
|
||||
const updateFields = Object.entries(data).filter(([_, v]) => v !== undefined && v !== null);
|
||||
for (const [field, value] of updateFields) {
|
||||
item[field] = value;
|
||||
}
|
||||
|
||||
await item.save();
|
||||
logger.info(`BlackList updated: id=${id}`);
|
||||
|
||||
// 重新加载关联数据
|
||||
const updated = await BlackList.findByPk(id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
|
||||
return res.json(ApiResponse.success(blacklistToDict(updated)));
|
||||
} catch (e) {
|
||||
logger.error(`Error updating BlackList ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/blacklist/:id
|
||||
router.delete('/api/blacklist/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
logger.info(`Deleting BlackList: id=${id}`);
|
||||
|
||||
const item = await BlackList.findByPk(id);
|
||||
if (!item) {
|
||||
logger.warn(`BlackList not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
await item.destroy();
|
||||
logger.info(`BlackList deleted: id=${id}`);
|
||||
return res.json(ApiResponse.success(null, 'success'));
|
||||
} catch (e) {
|
||||
logger.error(`Error deleting BlackList ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// BlackList 对象转字典
|
||||
function blacklistToDict(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
ota_id: item.ota_id,
|
||||
mac: item.mac,
|
||||
create_at: item.create_at ? item.create_at.toISOString() : null,
|
||||
ota: item.ota ? {
|
||||
id: item.ota.id,
|
||||
verCode: item.ota.verCode,
|
||||
verName: item.ota.verName,
|
||||
model: item.ota.model,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
@@ -5,8 +5,10 @@ const authRouter = require('./auth');
|
||||
const brandsRouter = require('./brands');
|
||||
const modelsRouter = require('./models');
|
||||
const otaRouter = require('./ota');
|
||||
const blacklistRouter = require('./blacklist');
|
||||
const otaTargetDeviceRouter = require('./otaTargetDevice');
|
||||
const shareCodeLogsRouter = require('./shareCodeLogs');
|
||||
const usersRouter = require('./users');
|
||||
const dashboardRouter = require('./dashboard');
|
||||
|
||||
module.exports = [authRouter, brandsRouter, modelsRouter, otaRouter, shareCodeLogsRouter, usersRouter, dashboardRouter];
|
||||
module.exports = [authRouter, brandsRouter, modelsRouter, otaRouter, blacklistRouter, otaTargetDeviceRouter, shareCodeLogsRouter, usersRouter, dashboardRouter];
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* 定向升级路由
|
||||
*/
|
||||
const router = require('express').Router();
|
||||
const { Op } = require('sequelize');
|
||||
const OtaTargetDevice = require('../models/OtaTargetDevice');
|
||||
const Ota = require('../models/Ota');
|
||||
const logger = require('../config/logger');
|
||||
const { ApiResponse } = require('../utils/response');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
const { OtaTargetDeviceCreateSchema, OtaTargetDeviceUpdateSchema } = require('../validators/otaTargetDevice');
|
||||
|
||||
// 所有接口需登录
|
||||
router.use('/api/ota-target-device', authMiddleware);
|
||||
|
||||
// GET /api/ota-target-device/
|
||||
router.get('/api/ota-target-device/', async (req, res) => {
|
||||
try {
|
||||
const skip = parseInt(req.query.skip || '0', 10);
|
||||
const limit = Math.min(parseInt(req.query.limit || '100', 10), 1000);
|
||||
const otaId = req.query.ota_id !== undefined ? parseInt(req.query.ota_id, 10) : null;
|
||||
const model = req.query.model;
|
||||
const macAddr = req.query.mac_addr;
|
||||
|
||||
const where = {};
|
||||
if (otaId !== null && !isNaN(otaId)) where.ota_id = otaId;
|
||||
if (macAddr) where.mac_addr = { [Op.like]: `%${macAddr}%` };
|
||||
|
||||
// 如果按 model 筛选,需先查出对应 model 的 ota_id 列表
|
||||
if (model) {
|
||||
const otaIds = await Ota.findAll({
|
||||
where: { model: { [Op.like]: `%${model}%` } },
|
||||
attributes: ['id'],
|
||||
});
|
||||
const ids = otaIds.map((o) => o.id);
|
||||
if (ids.length === 0) {
|
||||
return res.json(ApiResponse.success({ items: [], total: 0, skip, limit }));
|
||||
}
|
||||
if (where.ota_id !== undefined) {
|
||||
where.ota_id = { [Op.and]: [where.ota_id, { [Op.in]: ids }] };
|
||||
} else {
|
||||
where.ota_id = { [Op.in]: ids };
|
||||
}
|
||||
}
|
||||
|
||||
const total = await OtaTargetDevice.count({ where });
|
||||
const rows = await OtaTargetDevice.findAll({
|
||||
where,
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
offset: skip,
|
||||
limit,
|
||||
order: [['id', 'DESC']],
|
||||
});
|
||||
|
||||
logger.info(`Found ${rows.length} OtaTargetDevice records, total=${total}`);
|
||||
|
||||
if (!rows.length) {
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
const items = rows.map(toDict);
|
||||
return res.json(ApiResponse.success({ items, total, skip, limit }));
|
||||
} catch (e) {
|
||||
logger.error(`Error getting OtaTargetDevice: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/ota-target-device/:id
|
||||
router.get('/api/ota-target-device/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
logger.info(`Getting OtaTargetDevice: id=${id}`);
|
||||
const item = await OtaTargetDevice.findByPk(id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
if (!item) {
|
||||
logger.warn(`OtaTargetDevice not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
return res.json(ApiResponse.success(toDict(item)));
|
||||
} catch (e) {
|
||||
logger.error(`Error getting OtaTargetDevice ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/ota-target-device/
|
||||
router.post('/api/ota-target-device/', async (req, res) => {
|
||||
try {
|
||||
const parsed = OtaTargetDeviceCreateSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
const errors = parsed.error.errors.map((e) => e.message).join('; ');
|
||||
return res.json(ApiResponse.error(errors));
|
||||
}
|
||||
|
||||
const data = parsed.data;
|
||||
logger.info(`Creating OtaTargetDevice: ota_id=${data.ota_id}, mac_addr=${data.mac_addr}`);
|
||||
|
||||
// 校验 OTA 是否存在
|
||||
const ota = await Ota.findByPk(data.ota_id);
|
||||
if (!ota) {
|
||||
return res.json(ApiResponse.error('OTA 版本不存在'));
|
||||
}
|
||||
|
||||
// 唯一性校验:同一 ota_id 下 mac_addr 不能重复
|
||||
const existing = await OtaTargetDevice.findOne({
|
||||
where: { ota_id: data.ota_id, mac_addr: data.mac_addr },
|
||||
});
|
||||
if (existing) {
|
||||
return res.json(ApiResponse.error('该 MAC 地址已在此 OTA 版本中'));
|
||||
}
|
||||
|
||||
const item = await OtaTargetDevice.create(data);
|
||||
logger.info(`OtaTargetDevice created: id=${item.id}`);
|
||||
|
||||
// 重新加载关联数据
|
||||
const created = await OtaTargetDevice.findByPk(item.id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
|
||||
return res.json(ApiResponse.success(toDict(created)));
|
||||
} catch (e) {
|
||||
logger.error(`Error creating OtaTargetDevice: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/ota-target-device/:id
|
||||
router.put('/api/ota-target-device/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
|
||||
const parsed = OtaTargetDeviceUpdateSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
const errors = parsed.error.errors.map((e) => e.message).join('; ');
|
||||
return res.json(ApiResponse.error(errors));
|
||||
}
|
||||
|
||||
const data = parsed.data;
|
||||
logger.info(`Updating OtaTargetDevice: id=${id}`);
|
||||
|
||||
const item = await OtaTargetDevice.findByPk(id);
|
||||
if (!item) {
|
||||
logger.warn(`OtaTargetDevice not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
// 如果更新 ota_id,校验 OTA 是否存在
|
||||
if (data.ota_id !== undefined && data.ota_id !== null && data.ota_id !== item.ota_id) {
|
||||
const ota = await Ota.findByPk(data.ota_id);
|
||||
if (!ota) {
|
||||
return res.json(ApiResponse.error('OTA 版本不存在'));
|
||||
}
|
||||
}
|
||||
|
||||
// 唯一性校验:如果 ota_id 或 mac_addr 有变更
|
||||
const newOtaId = data.ota_id !== undefined && data.ota_id !== null ? data.ota_id : item.ota_id;
|
||||
const newMacAddr = data.mac_addr !== undefined && data.mac_addr !== null ? data.mac_addr : item.mac_addr;
|
||||
|
||||
if (newOtaId !== item.ota_id || newMacAddr !== item.mac_addr) {
|
||||
const existing = await OtaTargetDevice.findOne({
|
||||
where: {
|
||||
ota_id: newOtaId,
|
||||
mac_addr: newMacAddr,
|
||||
id: { [Op.ne]: id },
|
||||
},
|
||||
});
|
||||
if (existing) {
|
||||
return res.json(ApiResponse.error('该 MAC 地址已在此 OTA 版本中'));
|
||||
}
|
||||
}
|
||||
|
||||
const updateFields = Object.entries(data).filter(([_, v]) => v !== undefined && v !== null);
|
||||
for (const [field, value] of updateFields) {
|
||||
item[field] = value;
|
||||
}
|
||||
|
||||
await item.save();
|
||||
logger.info(`OtaTargetDevice updated: id=${id}`);
|
||||
|
||||
// 重新加载关联数据
|
||||
const updated = await OtaTargetDevice.findByPk(id, {
|
||||
include: [{
|
||||
model: Ota,
|
||||
as: 'ota',
|
||||
attributes: ['id', 'verCode', 'verName', 'model'],
|
||||
}],
|
||||
});
|
||||
|
||||
return res.json(ApiResponse.success(toDict(updated)));
|
||||
} catch (e) {
|
||||
logger.error(`Error updating OtaTargetDevice ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/ota-target-device/:id
|
||||
router.delete('/api/ota-target-device/:id', async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
logger.info(`Deleting OtaTargetDevice: id=${id}`);
|
||||
|
||||
const item = await OtaTargetDevice.findByPk(id);
|
||||
if (!item) {
|
||||
logger.warn(`OtaTargetDevice not found: id=${id}`);
|
||||
return res.json(ApiResponse.noData('empty'));
|
||||
}
|
||||
|
||||
await item.destroy();
|
||||
logger.info(`OtaTargetDevice deleted: id=${id}`);
|
||||
return res.json(ApiResponse.success(null, 'success'));
|
||||
} catch (e) {
|
||||
logger.error(`Error deleting OtaTargetDevice ${req.params.id}: ${e.message}`);
|
||||
return res.json(ApiResponse.error('error'));
|
||||
}
|
||||
});
|
||||
|
||||
// OtaTargetDevice 对象转字典
|
||||
function toDict(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
ota_id: item.ota_id,
|
||||
mac_addr: item.mac_addr,
|
||||
create_at: item.create_at ? item.create_at.toISOString() : null,
|
||||
ota: item.ota ? {
|
||||
id: item.ota.id,
|
||||
verCode: item.ota.verCode,
|
||||
verName: item.ota.verName,
|
||||
model: item.ota.model,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,13 @@
|
||||
const { z } = require('zod');
|
||||
|
||||
const BlackListCreateSchema = z.object({
|
||||
ota_id: z.number().int({ message: 'ota_id 须为整数' }),
|
||||
mac: z.string().min(1, 'MAC 地址不能为空').max(100, 'MAC 地址最多100字符'),
|
||||
});
|
||||
|
||||
const BlackListUpdateSchema = z.object({
|
||||
ota_id: z.number().int({ message: 'ota_id 须为整数' }).optional().nullable(),
|
||||
mac: z.string().min(1).max(100).optional().nullable(),
|
||||
});
|
||||
|
||||
module.exports = { BlackListCreateSchema, BlackListUpdateSchema };
|
||||
@@ -0,0 +1,13 @@
|
||||
const { z } = require('zod');
|
||||
|
||||
const OtaTargetDeviceCreateSchema = z.object({
|
||||
ota_id: z.number().int({ message: 'ota_id 须为整数' }),
|
||||
mac_addr: z.string().min(1, 'MAC 地址不能为空').max(17, 'MAC 地址最多17字符'),
|
||||
});
|
||||
|
||||
const OtaTargetDeviceUpdateSchema = z.object({
|
||||
ota_id: z.number().int({ message: 'ota_id 须为整数' }).optional().nullable(),
|
||||
mac_addr: z.string().min(1).max(17).optional().nullable(),
|
||||
});
|
||||
|
||||
module.exports = { OtaTargetDeviceCreateSchema, OtaTargetDeviceUpdateSchema };
|
||||
Reference in New Issue
Block a user