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.
 
 
 
 
 
 

140 lines
5.9 KiB

package console
import (
"yunyan/comm"
"yunyan/lego/sys/postgres"
)
// 芯片厂商档案(chip_vendor)——原来是 apps/proto/db.proto 里硬编码的 SolutionVendor 枚举,
// 加一个厂商要同步改三处代码再重新发版,运营自己加不了,故转成表。
//
// **Id 就是 CID**(芯片方案标识,十六进制看,如 恒玄=0xABF4),与方案商的 BID、产品的 PID 同一套路:
// 手工指定的有含义编码、不自增、后台可改。`solution_provider.vendor` 存的就是它。
//
// ⚠️ 尚未确定 CID 的厂商先用历史占位 id(杰里=1 / 蓝汛=2 / 博通=4,即原枚举值),
// 等真实 CID 定下来在后台改号即可(改号会级联更新方案商的 vendor 引用,见 renameChipVendorId)。
// 主键不能为空,所以「先空着」只能表现为占位值、不能是 0。
//
// 用本地 gorm struct 而不是 pb:这张表只服务后台,客户端协议不涉及,
// 走 pb 就得重新生成 22 个 .pb.go(见 CLAUDE.md 关于 protoc-gen-go 版本的告警),没必要。
type ChipVendor struct {
// Id 即 CID:手工指定、不自增。改它会级联改方案商的 vendor,必须走 renameChipVendorId。
Id uint32 `gorm:"primaryKey;column:id" json:"id"`
Name string `gorm:"column:name;size:64;index" json:"name"` // 厂商名,如 杰里/蓝汛/恒玄/博通
Enabled bool `gorm:"column:enabled" json:"enabled"` // 停用后不在方案商的「芯片」下拉里出现,但存量方案商仍显示其名字
Sort int32 `gorm:"column:sort" json:"sort"` // 列表排序,小的在前;相同则按 id
Createtime int64 `gorm:"column:createtime" json:"createtime"`
Updatetime int64 `gorm:"column:updatetime" json:"updatetime"`
}
func (ChipVendor) TableName() string { return comm.TableChipVendor }
// chipVendorSeeds 原 SolutionVendor 枚举的 4 个取值。
// 恒玄的 CID 已知(0xABF4)故直接用作 id;其余三家 CID 未定,沿用原枚举值作占位 id,
// 后台确定后改号即可。不替它们猜值——CID 要烧进固件,猜错比留占位难查得多。
var chipVendorSeeds = []ChipVendor{
{Id: 1, Name: "杰里"},
{Id: 2, Name: "蓝汛"},
{Id: 0xABF4, Name: "恒玄"},
{Id: 4, Name: "博通"},
}
// migrateChipVendorCidToId 一次性迁移:把独立的 cid 列并进主键 id。
//
// 上一版把 CID 做成了独立字段(id 自增、cid 另存),本版改成「id 即 CID」。已部署过上一版的库里
// 存着 id=3 / cid=44020 的恒玄,必须把它搬到 id=44020 并同步改掉方案商的 vendor 引用,
// 否则方案商会指向一个不存在的芯片厂商。
//
// 幂等:迁移完就把 cid 列删掉,之后本函数直接跳过。
func migrateChipVendorCidToId() error {
// 探测 cid 列是否还在(不在 = 已迁移过,或本来就是新库)
var n int64
if err := postgres.Raw(
"SELECT COUNT(*) FROM information_schema.columns WHERE table_name=? AND column_name='cid'",
comm.TableChipVendor).Scan(&n).Error; err != nil {
return err
}
if n == 0 {
return nil
}
type cidRow struct {
Id uint32 `gorm:"column:id"`
Cid uint32 `gorm:"column:cid"`
}
var rows []cidRow
if err := postgres.Raw(
"SELECT id, cid FROM " + comm.TableChipVendor + " WHERE cid <> 0 AND cid <> id").Scan(&rows).Error; err != nil {
return err
}
for _, r := range rows {
// 目标 id 已被别人占用就跳过,留给人工处理——静默合并两条厂商记录比不迁移危险得多。
var taken int64
if err := postgres.Table(comm.TableChipVendor).Where("id=?", r.Cid).Count(&taken).Error; err != nil {
return err
}
if taken > 0 {
continue
}
if err := renameChipVendorId(r.Id, r.Cid); err != nil {
return err
}
}
if res := postgres.Exec("ALTER TABLE " + comm.TableChipVendor + " DROP COLUMN IF EXISTS cid"); res.Error != nil {
return res.Error
}
return nil
}
// ensureChipVendorSeed 幂等补种 4 条已知厂商。
//
// 按【名称】判存在而不是按 id:id 就是 CID、后台可改,按 id 判会在厂商改过号之后
// 把旧 id 那条重新种回来,变成同名两条。同时也避开 id 被别的厂商占用的情况。
func ensureChipVendorSeed() error {
for _, v := range chipVendorSeeds {
if res := postgres.Exec(
"INSERT INTO "+comm.TableChipVendor+" (id, name, enabled, sort, createtime, updatetime) "+
"SELECT ?, ?, true, 0, 0, 0 "+
"WHERE NOT EXISTS (SELECT 1 FROM "+comm.TableChipVendor+" WHERE name=?) "+
" AND NOT EXISTS (SELECT 1 FROM "+comm.TableChipVendor+" WHERE id=?)",
v.Id, v.Name, v.Name, v.Id); res.Error != nil {
return res.Error
}
}
return nil
}
// ---- 芯片厂商 CRUD(console 主库,与方案商/品牌商同库)----
func dvChipVendors(sys *appConn) (models []*ChipVendor, err error) {
models = make([]*ChipVendor, 0)
err = sys.AdminDB().Find(comm.TableChipVendor, &models, "")
return
}
func dvChipVendor(sys *appConn, id uint32) (model *ChipVendor, err error) {
model = &ChipVendor{}
// 用 FindOne:不存在时返回 ErrRecordNotFound,存在性校验才有效(Find 对空结果不报错)。
err = sys.AdminDB().FindOne(comm.TableChipVendor, model, "id=?", id)
return
}
func dvAddChipVendor(sys *appConn, model *ChipVendor) (err error) {
err = sys.AdminDB().Insert(comm.TableChipVendor, model)
return
}
func dvSaveChipVendor(sys *appConn, model *ChipVendor) (err error) {
err = sys.AdminDB().Save(comm.TableChipVendor, model)
return
}
func dvDelChipVendor(sys *appConn, id uint32) (err error) {
err = sys.AdminDB().Delete(comm.TableChipVendor, "id=?", id)
return
}
// dvCountProvidersByVendor 统计挂在某芯片厂商下的方案商数量,删除/改号前用它做引用检查。
func dvCountProvidersByVendor(sys *appConn, vendorId uint32) (n int64, err error) {
err = sys.AdminDB().Table(comm.TableSolutionProvider).Where("vendor=?", vendorId).Count(&n).Error
return
}