Files
bj_power/bj_power_mes/internal/logic/seed.go
T
SunYF b6799c9de4 feat: 完成产线与仓储系统多模块迭代升级
本次迭代覆盖MES与WMS核心业务:
1. 新增接驳台托盘传感器读取与AGV对接能力
2. 完善工单排产、备料流程与权限体系拆分
3. 优化看板接口与前端路由、样式
4. 新增操作日志、库存盘点与角色保护逻辑
5. 修复代理地址、BOM保存等已知问题
2026-09-04 14:18:53 +08:00

233 lines
9.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logic
import (
"context"
"strconv"
"bj_power_mes/ent"
"bj_power_mes/ent/permission"
"bj_power_mes/ent/processflow"
"bj_power_mes/ent/processstep"
"bj_power_mes/ent/role"
"bj_power_mes/ent/station"
"bj_power_mes/ent/user"
"golang.org/x/crypto/bcrypt"
)
// Seed 初始化:超级管理员、默认角色、默认菜单权限、12 道工序与工位派工
func (s *Service) Seed(ctx context.Context) error {
// 1. 默认角色(已存在则合并权限码,保证新按钮权限能落到已有角色上)
roles := []struct{ name, code string }{
{"超级管理员", "SUPER_ADMIN"},
{"生产操作员", "OPERATOR"},
{"质检员", "INSPECTOR"},
}
for _, r := range roles {
codes := []string{"*"}
if r.code == "OPERATOR" {
codes = []string{
"produce.workorder", "produce.dailyplan", "produce.bom", "produce.material", "produce.scan",
"produce.trace", "produce.torque", "produce.plc", "produce.product",
"produce.processflow", "produce.station", "produce.performance",
// 按钮级权限(块2
"produce.workorder:add", "produce.workorder:edit", "produce.workorder:delete",
"produce.workorder:dailyplan", "produce.bom:edit", "produce.material:generate",
"produce.plc:send", "produce.product:add", "produce.product:edit", "produce.product:delete",
"produce.processflow:add", "produce.processflow:edit", "produce.processflow:delete",
"produce.processflow:upload", "produce.station:edit",
}
} else if r.code == "INSPECTOR" {
codes = []string{"produce.trace", "produce.torque", "produce.performance", "sys.eventlog",
"sys.inspect", "sys.inspect:checkin", "sys.inspect:point", "sys.inspect:process",
"sys.inspect:done", "sys.inspect:alarm", "sys.inspect:view"}
}
exist, err := s.ctx.EntClient.Role.Query().Where(role.Code(r.code)).First(ctx)
if err != nil {
_ = s.ctx.EntClient.Role.Create().SetName(r.name).SetCode(r.code).SetPermissionCodes(codes).Exec(ctx)
} else {
_ = s.ctx.EntClient.Role.UpdateOneID(exist.ID).SetPermissionCodes(mergeCodes(exist.PermissionCodes, codes)).Exec(ctx)
}
}
// 2. 超级管理员账号 admin / 123456(对已存在的旧行做对齐,避免残留禁用状态)
hash, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
adminRole, _ := s.ctx.EntClient.Role.Query().Where(role.Code("SUPER_ADMIN")).First(ctx)
roleId := 0
if adminRole != nil {
roleId = adminRole.ID
}
if s.ctx.EntClient.User.Query().Where(user.Username("admin")).ExistX(ctx) {
_ = s.ctx.EntClient.User.Update().
Where(user.Username("admin")).
SetPassword(string(hash)).SetStatus("ENABLED").SetRoleId(roleId).Exec(ctx)
} else {
_ = s.ctx.EntClient.User.Create().
SetUsername("admin").SetPassword(string(hash)).SetName("系统管理员").
SetRoleId(roleId).SetStatus("ENABLED").Exec(ctx)
}
// 3. 默认菜单权限
menus := []struct{ code, name, typ, path string }{
{"produce.workorder", "工单管理", "MENU", "/work-order"},
{"produce.dailyplan", "日排产", "MENU", "/daily-plan"},
{"produce.bom", "物料清单", "MENU", "/bom"},
{"produce.material", "备料单", "MENU", "/material-request"},
{"produce.plc", "工位组合下发", "MENU", "/plc-send"},
{"produce.torque", "拧紧查询", "MENU", "/torque"},
{"produce.processflow", "工艺流程", "MENU", "/process-flow"},
{"produce.station", "关联工位", "MENU", "/station"},
{"produce.performance", "绩效报表", "MENU", "/performance"},
{"produce.scan", "手动报工", "MENU", "/scan"},
{"produce.trace", "工件追溯", "MENU", "/trace"},
{"produce.product", "产品类型", "MENU", "/product-type"},
{"sys.inspect", "巡检终端", "MENU", "/inspect"},
{"sys.eventlog", "操作日志", "MENU", "/event-log"},
// sys.rbac(角色权限管理) 已拆分:账号管理 + 角色管理(对齐 WMS 系统管理菜单)
{"sys.account", "账号管理", "MENU", "/account"},
{"sys.role", "角色管理", "MENU", "/role"},
}
for _, m := range menus {
if s.ctx.EntClient.Permission.Query().Where(permission.Code(m.code)).ExistX(ctx) {
continue
}
_ = s.ctx.EntClient.Permission.Create().
SetCode(m.code).SetName(m.name).SetType(m.typ).SetPath(m.path).Exec(ctx)
}
// 3.1 按钮级权限(块2):前端按钮 + 后端接口 双重校验
buttons := []struct{ code, name, typ, path string }{
{"produce.workorder:add", "工单-新增", "BUTTON", ""},
{"produce.workorder:edit", "工单-编辑", "BUTTON", ""},
{"produce.workorder:delete", "工单-删除", "BUTTON", ""},
{"produce.workorder:dailyplan", "工单-日排产", "BUTTON", ""},
{"produce.bom:edit", "物料清单-维护", "BUTTON", ""},
{"produce.material:generate", "备料单-生成", "BUTTON", ""},
{"produce.plc:send", "工位组合-下发", "BUTTON", ""},
{"produce.product:add", "产品类型-新增", "BUTTON", ""},
{"produce.product:edit", "产品类型-编辑", "BUTTON", ""},
{"produce.product:delete", "产品类型-删除", "BUTTON", ""},
{"produce.processflow:add", "工艺流程-新增", "BUTTON", ""},
{"produce.processflow:edit", "工艺流程-编辑", "BUTTON", ""},
{"produce.processflow:delete", "工艺流程-删除", "BUTTON", ""},
{"produce.processflow:upload", "工艺流程-上传图纸", "BUTTON", ""},
{"produce.station:edit", "工位-绑定", "BUTTON", ""},
{"sys.account:add", "账号-新增", "BUTTON", ""},
{"sys.account:edit", "账号-编辑", "BUTTON", ""},
{"sys.account:delete", "账号-删除", "BUTTON", ""},
{"sys.role:add", "角色-新增", "BUTTON", ""},
{"sys.role:edit", "角色-编辑", "BUTTON", ""},
{"sys.role:delete", "角色-删除", "BUTTON", ""},
{"sys.role:perm", "角色-权限定义", "BUTTON", ""},
{"sys.inspect:checkin", "巡检-开工签到", "BUTTON", ""},
{"sys.inspect:point", "巡检-工位点检", "BUTTON", ""},
{"sys.inspect:process", "巡检-过程巡检", "BUTTON", ""},
{"sys.inspect:done", "巡检-完工确认", "BUTTON", ""},
{"sys.inspect:alarm", "巡检-异常上报", "BUTTON", ""},
{"sys.inspect:view", "巡检-记录查看", "BUTTON", ""},
}
for _, b := range buttons {
if s.ctx.EntClient.Permission.Query().Where(permission.Code(b.code)).ExistX(ctx) {
continue
}
_ = s.ctx.EntClient.Permission.Create().
SetCode(b.code).SetName(b.name).SetType(b.typ).SetPath(b.path).Exec(ctx)
}
// 3.2 旧版权限码迁移(sys.rbac 家族 → sys.account / sys.role,幂等)
migrateLegacySysRbac(ctx, s)
// 4. 12 个工位默认工艺流程 + 工位绑定(流程挂 process_code,工位绑流程)
seedFlowsAndStations(ctx, s)
return nil
}
func seedFlowsAndStations(ctx context.Context, s *Service) {
// 每个工位(1~12)若未配置工艺流程,则创建默认流程并绑定;已有流程则跳过
for i := 1; i <= 12; i++ {
flow, err := s.ctx.EntClient.ProcessFlow.Query().
Where(processflow.ProcessCode(i)).
Order(ent.Asc(processflow.FieldID)).First(ctx)
if err != nil {
flow, _ = s.ctx.EntClient.ProcessFlow.Create().
SetName("工位" + strconv.Itoa(i) + "_默认").
SetProcessCode(i).SetStatus("ACTIVE").SetRemark("默认工艺流程").Save(ctx)
}
if flow == nil {
continue
}
cnt, _ := s.ctx.EntClient.ProcessStep.Query().Where(processstep.FlowId(flow.ID)).Count(ctx)
if cnt == 0 {
stepID := 0
if step, err := s.ctx.EntClient.ProcessStep.Create().
SetFlowId(flow.ID).SetProcessCode(i).SetSeq(1).SetName("装配完成").
SetCollectType("NONE").Save(ctx); err == nil {
stepID = step.ID
}
if i == 3 && stepID > 0 {
_, _ = s.ctx.EntClient.ProcessStep.Create().
SetFlowId(flow.ID).SetProcessCode(i).SetSeq(2).SetName("拧紧扭矩").
SetCollectType("AUTO").SetIsTorque(true).Save(ctx)
}
}
// 工位 N 绑定工位 N 的默认流程
st, err := s.ctx.EntClient.Station.Query().Where(station.StationNo(i)).First(ctx)
if err != nil {
_, _ = s.ctx.EntClient.Station.Create().
SetStationNo(i).SetName("装配工位" + strconv.Itoa(i)).
SetFlowId(flow.ID).SetStatus("ENABLED").Save(ctx)
} else if st.FlowId == 0 {
_, _ = s.ctx.EntClient.Station.UpdateOneID(st.ID).SetFlowId(flow.ID).Save(ctx)
}
}
}
// mergeCodes 合并两份权限码列表(去重、保序)
func mergeCodes(a, b []string) []string {
seen := map[string]bool{}
out := make([]string, 0, len(a)+len(b))
for _, c := range append(append([]string{}, a...), b...) {
if c == "" || seen[c] {
continue
}
seen[c] = true
out = append(out, c)
}
return out
}
// migrateLegacySysRbac 迁移旧 sys.rbac 家族权限码(幂等,可重复执行):
// sys.rbac(角色权限管理) 已拆分为 sys.account(账号管理)+sys.role(角色管理)。
// 对存量角色 permissionCodes 做码替换,并删除已废弃的权限定义行。
func migrateLegacySysRbac(ctx context.Context, s *Service) {
legacyMap := map[string][]string{
"sys.rbac": {"sys.account", "sys.role"},
"sys.rbac:user": {"sys.account:add", "sys.account:edit", "sys.account:delete"},
"sys.rbac:role": {"sys.role:add", "sys.role:edit", "sys.role:delete"},
"sys.rbac:perm": {"sys.role:perm"},
}
// 1) 角色 permissionCodes 替换
roleList, _ := s.ctx.EntClient.Role.Query().All(ctx)
for _, rl := range roleList {
changed := false
out := make([]string, 0, len(rl.PermissionCodes))
for _, c := range rl.PermissionCodes {
if repl, ok := legacyMap[c]; ok {
out = append(out, repl...)
changed = true
continue
}
out = append(out, c)
}
if changed {
_ = s.ctx.EntClient.Role.UpdateOneID(rl.ID).
SetPermissionCodes(mergeCodes(out, nil)).Exec(ctx)
}
}
// 2) 删除旧权限定义行
for oldCode := range legacyMap {
_, _ = s.ctx.EntClient.Permission.Delete().
Where(permission.Code(oldCode)).Exec(ctx)
}
}