持续优化

This commit is contained in:
eafonyang
2026-06-30 10:41:03 +08:00
parent d5bb46e738
commit cac5bef5a7
11 changed files with 841 additions and 203 deletions
+6 -28
View File
@@ -64,34 +64,6 @@ const Ota = sequelize.define('Ota', {
defaultValue: 0,
comment: '是否灰度,1-是,0-否',
},
pawVerCode: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
field: 'pawVerCode',
comment: '配对版本号',
},
pawVerName: {
type: DataTypes.STRING(20),
allowNull: false,
defaultValue: '',
field: 'pawVerName',
comment: '配对版本名称',
},
pawUrl: {
type: DataTypes.STRING(255),
allowNull: false,
defaultValue: '',
field: 'pawUrl',
comment: '配对版本 URL',
},
pawMd5: {
type: DataTypes.STRING(32),
allowNull: false,
defaultValue: '',
field: 'pawMd5',
comment: '配对版本 MD5',
},
startTime: {
type: DataTypes.DATE,
allowNull: true,
@@ -110,6 +82,12 @@ const Ota = sequelize.define('Ota', {
defaultValue: 1,
comment: '是否可用',
},
create_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间',
},
}, {
tableName: 'ota',
comment: 'OTA 升级版本',
+65
View File
@@ -0,0 +1,65 @@
/**
* Dashboard 路由 — 首页统计数据
*/
const router = require('express').Router();
const { Op } = require('sequelize');
const Model = require('../models/Model');
const Ota = require('../models/Ota');
const logger = require('../config/logger');
const { ApiResponse } = require('../utils/response');
const { authMiddleware } = require('../middleware/auth');
// 所有 dashboard 接口需登录
router.use(authMiddleware);
/**
* GET /api/dashboard/today
* 返回今日新增的耳机型号和 OTA 数据
*/
router.get('/api/dashboard/today', async (req, res) => {
try {
// 今日 00:00:00 (UTC+8)
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
// 今日新增型号
const newModels = await Model.findAll({
where: {
create_at: { [Op.gte]: todayStart },
},
order: [['id', 'DESC']],
attributes: ['id', 'brand_name', 'name', 'create_at'],
});
// 今日新增 OTA
const newOtas = await Ota.findAll({
where: {
create_at: { [Op.gte]: todayStart },
},
order: [['id', 'DESC']],
attributes: ['id', 'verName', 'model', 'create_at'],
});
return res.json(
ApiResponse.success({
models: newModels.map((m) => ({
id: m.id,
brand_name: m.brand_name,
name: m.name,
create_at: m.create_at ? m.create_at.toISOString() : null,
})),
otas: newOtas.map((o) => ({
id: o.id,
verName: o.verName,
model: o.model,
create_at: o.create_at ? o.create_at.toISOString() : null,
})),
})
);
} catch (e) {
logger.error(`Error getting dashboard today stats: ${e.message}`);
return res.json(ApiResponse.error(`获取统计数据失败:${e.message}`));
}
});
module.exports = router;
+2 -1
View File
@@ -7,5 +7,6 @@ const modelsRouter = require('./models');
const otaRouter = require('./ota');
const shareCodeLogsRouter = require('./shareCodeLogs');
const usersRouter = require('./users');
const dashboardRouter = require('./dashboard');
module.exports = [authRouter, brandsRouter, modelsRouter, otaRouter, shareCodeLogsRouter, usersRouter];
module.exports = [authRouter, brandsRouter, modelsRouter, otaRouter, shareCodeLogsRouter, usersRouter, dashboardRouter];
+1 -4
View File
@@ -281,13 +281,10 @@ function otaToDict(ota) {
hw: ota.hw,
target: ota.target,
beta: ota.beta,
pawVerCode: ota.pawVerCode,
pawVerName: ota.pawVerName,
pawUrl: ota.pawUrl,
pawMd5: ota.pawMd5,
startTime: ota.startTime ? ota.startTime.toISOString() : null,
endTime: ota.endTime ? ota.endTime.toISOString() : null,
status: ota.status,
create_at: ota.create_at ? ota.create_at.toISOString() : null,
};
}
-8
View File
@@ -11,10 +11,6 @@ const OtaCreateSchema = z.object({
hw: z.number().int().optional().default(0),
target: z.number().int().min(0).max(1).optional().default(0),
beta: z.number().int().min(0).max(1).optional().default(0),
pawVerCode: z.number().int().optional().default(0),
pawVerName: z.string().max(20).optional().default(''),
pawUrl: z.string().max(255).optional().default(''),
pawMd5: z.string().length(32).optional().default(''),
startTime: z.string().optional().nullable(),
endTime: z.string().optional().nullable(),
status: z.number().int().min(0).max(1).optional().default(1),
@@ -31,10 +27,6 @@ const OtaUpdateSchema = z.object({
hw: z.number().int().optional().nullable(),
target: z.number().int().min(0).max(1).optional().nullable(),
beta: z.number().int().min(0).max(1).optional().nullable(),
pawVerCode: z.number().int().optional().nullable(),
pawVerName: z.string().max(20).optional().nullable(),
pawUrl: z.string().max(255).optional().nullable(),
pawMd5: z.string().length(32).optional().nullable(),
startTime: z.string().optional().nullable(),
endTime: z.string().optional().nullable(),
status: z.number().int().min(0).max(1).optional().nullable(),