zzw
11 小时以前 ce841ddf85c48bae32f9e3068403fdfe98ac8711
emergency-repair-server/src/main/java/com/emergencyrepair/bootstrap/DataInitializer.java
@@ -34,6 +34,7 @@
import com.emergencyrepair.system.mapper.SysTenantMenuMapper;
import com.emergencyrepair.system.service.ButtonPermissionCatalog;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@@ -50,6 +51,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
@Order(2)
@@ -73,6 +75,9 @@
    private final JdbcTemplate jdbcTemplate;
    private final ButtonPermissionCatalog buttonPermissionCatalog;
    @Value("${app.seed-demo-data:false}")
    private boolean seedDemoData;
    private final Map<String, Long> menuIds = new HashMap<>();
    private final Map<String, Long> productDeviceIds = new HashMap<>();
    private final List<Long> contractorIds = new ArrayList<>();
@@ -83,11 +88,13 @@
    public void run(String... args) {
        seedMenusAndRoles();
        ensureSystemMenus();
        ensureCompletionMenus();
        normalizeSensitiveTerms();
        normalizeEquipmentTerms();
        seedButtonMenus();
        ensureAdminRoleAssignment();
        ensureMajorConfigMenus();
        ensureRoleMenuAncestors();
        seedMajors();
        seedContractors();
        seedTrees();
@@ -97,7 +104,9 @@
        backfillFaultEquipmentIds();
        upgradeDemoFaultEquipment();
        upgradeDemoMultiEquipmentFault();
        seedBusinessData();
        if (seedDemoData) {
            seedBusinessData();
        }
        backfillCompletionConsumableCounts();
        normalizeParentSystemSeparators();
    }
@@ -114,6 +123,7 @@
            createMenu("dispatch", fault, "rk_XCB助理派单", "/fault/dispatch", null, 1, 60);
            createMenu("completion-list", fault, "完工情况处理", "/fault/completion", null, 1, 70);
            createMenu("completion-report", fault, "完工信息上报", "/completion/report", null, 1, 80);
            createMenu("completion-query", fault, "完工信息查阅", "/completion/query", null, 1, 90);
            Long acceptance = createMenu("acceptance", null, "完工验收", null, "el-icon-circle-check", 0, 30);
            createMenu("accept-application", acceptance, "验收申请", "/acceptance/application", null, 1, 10);
@@ -130,16 +140,24 @@
            createMenu("report-trend", reports, "故障数/备品备件消耗年度趋势", "/reports/trend", null, 1, 50);
            Long system = createMenu("system", null, "系统管理", null, "el-icon-setting", 0, 50);
            createMenu("organization", system, "组织机构", "/system/organization", null, 1, 5);
            createMenu("contractors", system, "承修单位管理", "/system/contractors", null, 1, 10);
            createMenu("product-tree", system, "产品结构树管理", "/system/product-tree", null, 1, 20);
            createMenu("base-equipment", system, "设备基础库管理", "/system/base-equipment", null, 1, 30);
            createMenu("engineering-majors", system, "工程专业配置", "/system/engineering-majors", null, 1, 35);
            createMenu("team-majors", system, "rk_T队专业配置", "/system/team-majors", null, 1, 36);
            createMenu("roles", system, "角色管理", "/system/roles", null, 1, 40);
            createMenu("menus", system, "菜单管理", "/system/menus", null, 1, 50);
            createMenu("menu-permissions", system, "菜单权限管理", "/system/menu-permissions", null, 1, 60);
            createMenu("three-member", system, "三员控制", "/system/three-member", null, 1, 70);
            Long systemConfig = createMenu("system-config", system, "系统配置", null, "el-icon-s-tools", 0, 10);
            createMenu("organization", systemConfig, "组织机构", "/system/organization", null, 1, 10);
            createMenu("contractors", systemConfig, "承修单位管理", "/system/contractors", null, 1, 20);
            createMenu("product-tree", systemConfig, "产品结构树", "/system/product-tree", null, 1, 30);
            createMenu("base-equipment", systemConfig, "设备基础库管理", "/system/base-equipment", null, 1, 40);
            createMenu("engineering-majors", systemConfig, "工程专业配置", "/system/engineering-majors", null, 1, 50);
            createMenu("team-majors", systemConfig, "rk_T队专业配置", "/system/team-majors", null, 1, 60);
            createMenu("three-member", systemConfig, "三员控制", "/system/three-member", null, 1, 70);
            Long permissionConfig = createMenu("permission-config", system, "权限配置", null, "el-icon-lock", 0, 20);
            createMenu("users", permissionConfig, "用户管理", "/system/users", null, 1, 10);
            createMenu("roles", permissionConfig, "角色管理", "/system/roles", null, 1, 20);
            createMenu("menus", permissionConfig, "菜单管理", "/system/menus", null, 1, 30);
            Long logConfig = createMenu("log-config", system, "日志管理", null, "el-icon-document", 0, 30);
            createMenu("login-logs", logConfig, "登录日志", "/system/login-logs", null, 1, 10);
            createMenu("operation-logs", logConfig, "操作日志", "/system/operation-logs", null, 1, 20);
            createMenu("error-logs", logConfig, "错误日志", "/system/error-logs", null, 1, 30);
        } else {
            for (SysMenu menu : menuMapper.selectList(null)) {
                menuIds.put(menu.getUrl() == null ? "id-" + menu.getId() : menu.getUrl(), menu.getId());
@@ -178,36 +196,121 @@
        SysMenu system = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getName, "系统管理")
                .last("LIMIT 1"));
        Long pid = system == null ? 0L : system.getId();
        ensureMenu(pid, "工程专业配置", "/system/engineering-majors", 35);
        ensureMenu(pid, "rk_T队专业配置", "/system/team-majors", 36);
        SysMenu config = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getName, "系统配置")
                .eq(SysMenu::getMenuType, 0)
                .last("LIMIT 1"));
        Long pid = config == null ? (system == null ? 0L : system.getId()) : config.getId();
        ensureMenu(pid, "工程专业配置", "/system/engineering-majors", 50);
        ensureMenu(pid, "rk_T队专业配置", "/system/team-majors", 60);
    }
    private void ensureMenu(Long pid, String name, String url, int sort) {
        if (menuMapper.selectCount(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getUrl, url)) > 0) {
            return;
    private Long ensureGroupMenu(Long pid, String name, String icon, int sort) {
        SysMenu menu = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getPid, pid)
                .eq(SysMenu::getName, name)
                .eq(SysMenu::getMenuType, 0)
                .last("LIMIT 1"));
        LocalDateTime now = LocalDateTime.now();
        if (menu == null) {
            menu = new SysMenu();
            menu.setPid(pid);
            menu.setName(name);
            menu.setIcon(icon);
            menu.setMenuType(0);
            menu.setSortNo(sort);
            menu.setVisible(1);
            menu.setCreateTime(now);
            menu.setUpdateTime(now);
            menuMapper.insert(menu);
            return menu.getId();
        }
        SysMenu menu = new SysMenu();
        menu.setPid(pid);
        menu.setName(name);
        menu.setUrl(url);
        menu.setMenuType(1);
        menu.setSortNo(sort);
        menu.setVisible(1);
        menu.setCreateTime(LocalDateTime.now());
        menu.setUpdateTime(LocalDateTime.now());
        menuMapper.insert(menu);
        boolean changed = !java.util.Objects.equals(menu.getIcon(), icon)
                || !java.util.Objects.equals(menu.getSortNo(), sort)
                || !java.util.Objects.equals(menu.getVisible(), 1);
        if (changed) {
            menu.setIcon(icon);
            menu.setSortNo(sort);
            menu.setVisible(1);
            menu.setUpdateTime(now);
            menuMapper.updateById(menu);
        }
        return menu.getId();
    }
    private Long ensureMenu(Long pid, String name, String url, int sort) {
        SysMenu menu = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getUrl, url).last("LIMIT 1"));
        LocalDateTime now = LocalDateTime.now();
        if (menu == null) {
            menu = new SysMenu();
            menu.setPid(pid);
            menu.setName(name);
            menu.setUrl(url);
            menu.setMenuType(1);
            menu.setSortNo(sort);
            menu.setVisible(1);
            menu.setCreateTime(now);
            menu.setUpdateTime(now);
            menuMapper.insert(menu);
            return menu.getId();
        }
        // Existing menu names are user-managed; startup only repairs structural fields.
        boolean changed = !java.util.Objects.equals(menu.getPid(), pid)
                || !java.util.Objects.equals(menu.getSortNo(), sort)
                || !java.util.Objects.equals(menu.getMenuType(), 1)
                || !java.util.Objects.equals(menu.getVisible(), 1);
        if (changed) {
            menu.setPid(pid);
            menu.setMenuType(1);
            menu.setSortNo(sort);
            menu.setVisible(1);
            menu.setUpdateTime(now);
            menuMapper.updateById(menu);
        }
        return menu.getId();
    }
    private void ensureCompletionMenus() {
        SysMenu fault = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getName, "故障管理")
                .eq(SysMenu::getMenuType, 0)
                .last("LIMIT 1"));
        Long pid = fault == null ? 0L : fault.getId();
        ensureMenu(pid, "完工信息查阅", "/completion/query", 90);
        grantAdminMenus("/completion/query");
    }
    private void ensureSystemMenus() {
        SysMenu system = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getName, "\u7cfb\u7edf\u7ba1\u7406").last("LIMIT 1"));
        Long pid = system == null ? 0L : system.getId();
        ensureMenu(pid, "组织机构", "/system/organization", 5);
        ensureMenu(pid, "\u7528\u6237\u7ba1\u7406", "/system/users", 37);
        ensureMenu(pid, "\u767b\u5f55\u65e5\u5fd7", "/system/login-logs", 65);
        ensureMenu(pid, "\u64cd\u4f5c\u65e5\u5fd7", "/system/operation-logs", 66);
        grantAdminMenus("/system/organization", "/system/users", "/system/login-logs", "/system/operation-logs");
        Long systemConfig = ensureGroupMenu(pid, "系统配置", "el-icon-s-tools", 10);
        Long permissionConfig = ensureGroupMenu(pid, "权限配置", "el-icon-lock", 20);
        Long logConfig = ensureGroupMenu(pid, "日志管理", "el-icon-document", 30);
        ensureMenu(systemConfig, "组织机构", "/system/organization", 10);
        ensureMenu(systemConfig, "承修单位管理", "/system/contractors", 20);
        ensureMenu(systemConfig, "产品结构树", "/system/product-tree", 30);
        ensureMenu(systemConfig, "设备基础库管理", "/system/base-equipment", 40);
        ensureMenu(systemConfig, "工程专业配置", "/system/engineering-majors", 50);
        ensureMenu(systemConfig, "rk_T队专业配置", "/system/team-majors", 60);
        ensureMenu(systemConfig, "三员控制", "/system/three-member", 70);
        ensureMenu(permissionConfig, "用户管理", "/system/users", 10);
        ensureMenu(permissionConfig, "角色管理", "/system/roles", 20);
        ensureMenu(permissionConfig, "菜单管理", "/system/menus", 30);
        ensureMenu(logConfig, "登录日志", "/system/login-logs", 10);
        ensureMenu(logConfig, "操作日志", "/system/operation-logs", 20);
        ensureMenu(logConfig, "错误日志", "/system/error-logs", 30);
        removeMenuByUrl("/system/menu-permissions");
        grantAdminMenuIds(systemConfig, permissionConfig, logConfig);
        grantAdminMenus("/system/organization", "/system/contractors", "/system/product-tree",
                "/system/base-equipment", "/system/engineering-majors", "/system/team-majors",
                "/system/three-member", "/system/users", "/system/roles", "/system/menus",
                "/system/login-logs", "/system/operation-logs", "/system/error-logs");
    }
    private void grantAdminMenus(String... urls) {
@@ -226,6 +329,61 @@
        }
    }
    private void grantAdminMenuIds(Long... menuIds) {
        SysRole adminRole = roleMapper.selectOne(Wrappers.<SysRole>lambdaQuery()
                .eq(SysRole::getCode, "SYS_ADMIN").last("LIMIT 1"));
        if (adminRole == null) {
            return;
        }
        for (Long menuId : menuIds) {
            ensureRoleMenu(adminRole.getId(), menuId);
            ensureTenantMenu(1L, menuId);
        }
    }
    private void removeMenuByUrl(String url) {
        SysMenu menu = menuMapper.selectOne(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getUrl, url).last("LIMIT 1"));
        if (menu == null) {
            return;
        }
        List<SysMenu> children = menuMapper.selectList(Wrappers.<SysMenu>lambdaQuery()
                .eq(SysMenu::getPid, menu.getId()));
        for (SysMenu child : children) {
            removeMenuRelations(child.getId());
            menuMapper.deleteById(child.getId());
        }
        removeMenuRelations(menu.getId());
        menuMapper.deleteById(menu.getId());
    }
    private void removeMenuRelations(Long menuId) {
        roleMenuMapper.delete(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getMenuId, menuId));
        tenantMenuMapper.delete(Wrappers.<SysTenantMenu>lambdaQuery().eq(SysTenantMenu::getMenuId, menuId));
    }
    private void ensureRoleMenuAncestors() {
        Map<Long, SysMenu> menuById = menuMapper.selectList(null).stream()
                .collect(java.util.stream.Collectors.toMap(SysMenu::getId, item -> item));
        List<SysRoleMenu> relations = new ArrayList<>(roleMenuMapper.selectList(null));
        Set<String> existing = relations.stream()
                .map(item -> item.getRoleId() + "-" + item.getMenuId())
                .collect(java.util.stream.Collectors.toSet());
        for (SysRoleMenu relation : relations) {
            SysMenu menu = menuById.get(relation.getMenuId());
            Long cursor = menu == null ? null : menu.getPid();
            int guard = 0;
            while (cursor != null && cursor != 0L && guard++ < 32) {
                String key = relation.getRoleId() + "-" + cursor;
                if (existing.add(key)) {
                    ensureRoleMenu(relation.getRoleId(), cursor);
                }
                SysMenu parent = menuById.get(cursor);
                cursor = parent == null ? null : parent.getPid();
            }
        }
    }
    /**
     * Materializes the declarative button catalog as MENU_TYPE=2 rows.
     * Existing rows are left untouched so manual menu edits are preserved.