Files
bj_power/bj_power_mes/internal/logic/seed.go
T
SunYF 4ec6784629 feat: 完成MES工位终端系统全量功能迭代
本次提交包含以下核心变更:
1. 新增按钮级权限控制框架与前端权限校验
2. 新增工位管理、工艺流程、巡检终端等核心业务模块
3. 完善用户体系,支持工位终端专属登录权限
4. 新增文件上传下载、报表查询等配套功能
5. 修复多系统兼容性与交互体验问题
6. 完成所有文档与配置项的规范化更新
2026-08-31 08:06:55 +08:00

194 lines
8.2 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/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/stationprocess"
"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.step",
"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", "PLC工序下发", "MENU", "/plc-send"},
{"produce.torque", "拧紧查询", "MENU", "/torque"},
{"produce.step", "工艺参数", "MENU", "/process-step"},
{"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", "角色权限管理", "MENU", "/rbac"},
}
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", "PLC工序-下发", "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.rbac:user", "权限-用户", "BUTTON", ""},
{"sys.rbac:role", "权限-角色", "BUTTON", ""},
{"sys.rbac: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)
}
// 4. 12 道工序默认工艺流程 + 工位绑定(流程挂 process_code,工位绑流程)
seedFlowsAndStations(ctx, s)
// 5. 12 工位 ↔ 工序 派工(工位N 默认做工序N)
for i := 1; i <= 12; i++ {
if s.ctx.EntClient.StationProcess.Query().Where(stationprocess.StationNo(i), stationprocess.ProcessCode(i)).ExistX(ctx) {
continue
}
_ = s.ctx.EntClient.StationProcess.Create().
SetStationNo(i).SetProcessCode(i).SetEffectDate("").Exec(ctx)
}
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), processflow.Name("工序"+strconv.Itoa(i)+"_默认")).First(ctx)
if err != nil {
flow, _ = s.ctx.EntClient.ProcessFlow.Create().
SetName("工序" + strconv.Itoa(i) + "_默认").
SetProcessCode(i).SetStatus("ACTIVE").SetRemark("默认工艺流程").Save(ctx)
}
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
}