You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

170 lines
5.3 KiB

package api
import (
"strings"
"time"
"yunyan/comm"
"yunyan/lego/sys/log"
"yunyan/pb"
"yunyan/utils/license"
"yunyan/utils/mac"
)
// CreateAuthCodes 创建授权码/设备码(一次生产 = 一个批次)。
//
// 序号采用「产品级全局游标」:每次生产原子地从 product.serialcursor 上分配一段连续区间
// [start, end],不再随批次重置,也不再依赖厂家维度的 probatch 计数器。
// 每次生产落一条 production_batch 台账(记录序号区间/MAC区间/数量),
// 再把该批次的全部授权码写入 license_<productid十六进制> 分表。
func (this *apiComp) CreateAuthCodes(session comm.IUserSession, req *pb.ApiCreateAuthCodesReq) (resp *pb.ApiCreateAuthCodesResp, errdata *pb.ErrorData) {
var (
err error
product *pb.DBProduct
now = time.Now().Unix()
pid = req.Productid
)
// 校验品牌商存在
if _, err = this.module.model.factory(req.Brandid); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_DBError, Message: err.Error()}
return
}
if product, err = this.module.model.product(pid); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_DBError, Message: err.Error()}
return
}
// 每副产品需要生产的设备码份数(0或1视为单份)
codeCount := product.Devicecodecount
if codeCount == 0 {
codeCount = 1
}
isClassicBT := product.Devicetype == pb.DeviceType_Classic_bluetooth_Headset
// 计算本次生产的授权码总数
var (
total int64
macaddresses []string
)
switch req.Createtype {
case 1: // 生产模式:数量 * 每副份数
total = int64(req.Number) * int64(codeCount)
case 2: // 导入模式:按逗号拆分的 MAC 份数
macaddresses = strings.Split(req.Macaddresses, ",")
total = int64(len(macaddresses))
default:
errdata = &pb.ErrorData{Code: pb.ErrorCode_ReqParameterError, Message: "createtype 仅支持 1(生产) 或 2(导入)"}
return
}
if total <= 0 {
errdata = &pb.ErrorData{Code: pb.ErrorCode_ReqParameterError, Message: "生成数量必须大于0"}
return
}
// 原子分配产品级序号区间 [start, end]
end, err := this.module.model.allocSerialRange(pid, total)
if err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_DBError, Message: err.Error()}
this.module.Error("allocSerialRange Fail!", log.Field{Key: "err", Value: err.Error()})
return
}
start := end - total + 1
models := make([]*pb.DBAuthCode, 0, total)
if req.Createtype == 1 {
for i := int64(0); i < total; i++ {
serial := start + i
var code string
if code, err = license.GenerateV2(uint16(pid), uint32(serial)); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_SystemError, Message: err.Error()}
return
}
device := &pb.DBAuthCode{
Code: code,
Codetype: pb.Codetype_AUTHCODE,
Brandid: req.Brandid,
Productid: pid,
Number: serial,
Createtime: now,
}
if isClassicBT { // 经典蓝牙耳机:生成设备码 + MAC
device.Codetype = pb.Codetype_DEVICECODE
device.Devicemac = mac.Generate(uint16(pid), uint32(serial))
}
models = append(models, device)
}
} else { // 导入模式
for i := int64(0); i < total; i++ {
serial := start + i
var code string
if code, err = license.GenerateV2(uint16(pid), uint32(serial)); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_SystemError, Message: err.Error()}
return
}
models = append(models, &pb.DBAuthCode{
Code: code,
Codetype: pb.Codetype_DEVICECODE,
Brandid: req.Brandid,
Productid: pid,
Number: serial,
Createtime: now,
Devicemac: strings.TrimSpace(macaddresses[i]),
})
}
}
// 经典蓝牙时批次记录 MAC 区间,否则留空
var startmac, endmac string
if isClassicBT {
startmac = mac.Generate(uint16(pid), uint32(start))
endmac = mac.Generate(uint16(pid), uint32(end))
}
// 先落批次台账。批次号 = 6 位可读短码(batchno 唯一索引兜底防碰撞),授权码用它关联批次。
// 优先用预览确认流程回传的 req.Batchno(保证二次确认展示的号 = 实际生产的号),未传则现生成。
batchno := strings.TrimSpace(req.Batchno)
if batchno == "" {
batchno, _ = comm.GeneratePublicCode()
}
batch := &pb.DBProductionBatch{
Ts: now,
Brandid: req.Brandid,
Productid: pid,
Serialstart: start,
Serialend: end,
Startmac: startmac,
Endmac: endmac,
Devicenum: uint32(total),
Batchno: batchno,
Remark: req.Remark,
}
if err = this.module.model.addproductionbatch(batch); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_DBError, Message: err.Error()}
this.module.Error("addproductionbatch Fail!", log.Field{Key: "err", Value: err.Error()})
return
}
// 回填批次号后批量写入分表
for _, row := range models {
row.Batchno = batchno
}
if err = this.module.model.addfactoryDevics(pid, models); err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_DBError, Message: err.Error()}
this.module.Error("addauthcodes Fail!", log.Field{Key: "err", Value: err.Error()})
return
}
resp = &pb.ApiCreateAuthCodesResp{
Brandid: req.Brandid,
Productid: pid,
Batchno: batchno,
Startmac: startmac,
Endmac: endmac,
Serialstart: start,
Serialend: end,
Number: uint32(total),
Devices: models,
}
return
}