feat(task): 新增定时任务控制系统与分享码配置

- 增加设备持久化、阻抗数据持久化、分享码持久化定时任务
- 通过环境变量 ENABLE_PERSIST_TASK 和 ENABLE_IMPEDANCE_PERSIST_TASK 控制任务启用
- 分享码配置新增最大数量和TTL时间支持多种时间单位(m/h/d)
- 实现任务批量处理、锁机制及失败重试保障数据一致性
- 定时任务启动集成至服务主流程,增强系统可配置性和运维便利性

feat(ota): 新增根据设备型号和版本号查询版本名称接口

- 实现 GET /audio/getVerName 接口返回唯一 OTA 版本名称 verName
- 添加请求参数校验及错误处理逻辑
- 在仓库层新增按型号和版本号查询版本名称的方法
- 完善接口文档及Swagger定义,支持前端调用查询版本名称功能
This commit is contained in:
eafonyang
2026-09-02 11:13:14 +08:00
parent ceea657ccf
commit dd92845bc2
8 changed files with 273 additions and 21 deletions
+45
View File
@@ -20,6 +20,51 @@ func NewOTAHandler(repo *repository.OTARepository, log *zap.Logger) *OTAHandler
return &OTAHandler{repo: repo, log: log}
}
// GetVerName 查询版本名称
//
// @Summary 查询版本名称
// @Description 根据设备型号和版本号(verCode)定位唯一 OTA 记录,返回版本名称 verName
// @Tags OTA
// @Produce json
// @Param model query string true "设备型号"
// @Param version query int true "版本号 (verCode)"
// @Success 200 {object} object "成功返回 verName"
// @Failure 400 {object} object
// @Failure 500 {object} object
// @Router /audio/getVerName [get]
func (h *OTAHandler) GetVerName(c *gin.Context) {
modelVal := strings.TrimSpace(c.Query("model"))
versionStr := strings.TrimSpace(c.Query("version"))
// 参数校验
if modelVal == "" || versionStr == "" {
response.BadRequest(c, "model和version参数不能为空")
return
}
version, err := strconv.Atoi(versionStr)
if err != nil {
response.BadRequest(c, "version参数格式错误")
return
}
ctx := c.Request.Context()
verName, found, err := h.repo.GetVerNameByVersion(ctx, modelVal, version)
if err != nil {
h.log.Error("query ota verName failed", zap.Error(err))
response.InternalError(c, "查询版本名称失败")
return
}
if !found {
response.Fail(c, http.StatusOK, 40004, "无OTA版本信息")
return
}
response.OK(c, gin.H{"verName": verName})
}
// GetOTA 获取 OTA 升级信息
//
// @Summary 获取 OTA 升级信息
+15
View File
@@ -131,6 +131,21 @@ func (r *OTARepository) GetLatestOTANotTarget(ctx context.Context, modelVal stri
return &o, nil
}
// GetVerNameByVersion 按 model+verCode 查询版本名称
func (r *OTARepository) GetVerNameByVersion(ctx context.Context, modelVal string, version int) (string, bool, error) {
const query = `SELECT verName FROM ota WHERE model = ? AND verCode = ? LIMIT 1`
var verName string
err := r.db.QueryRowContext(ctx, query, modelVal, version).Scan(&verName)
if err == sql.ErrNoRows {
return "", false, nil
}
if err != nil {
return "", false, fmt.Errorf("query ota verName: %w", err)
}
return verName, true, nil
}
// IsInBlackList 检查 mac 是否在指定 ota_id 的黑名单中
func (r *OTARepository) IsInBlackList(ctx context.Context, otaID int, mac string) (bool, error) {
const query = `SELECT COUNT(*) FROM black_list WHERE ota_id = ? AND mac = ?`
+1
View File
@@ -69,6 +69,7 @@ func New(log *zap.Logger, db *sql.DB, searchClient *search.Client, rdb *redis.Cl
audio.GET("/reportDevInfo", device.ReportDevInfo)
audio.GET("/reportImpedance", impedance.ReportImpedance)
audio.GET("/ota", ota.GetOTA)
audio.GET("/getVerName", ota.GetVerName)
audio.GET("/getCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.GetCurve)
audio.GET("/modelCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.ModelCurve)
audio.GET("/getModelCSV", modelCSV.GetModelCSV)