diff --git a/backend/src/main/java/com/yfd/platform/config/ResponseResult.java b/backend/src/main/java/com/yfd/platform/config/ResponseResult.java index 9638fcf3..6e543fbd 100644 --- a/backend/src/main/java/com/yfd/platform/config/ResponseResult.java +++ b/backend/src/main/java/com/yfd/platform/config/ResponseResult.java @@ -22,29 +22,29 @@ public class ResponseResult extends HashMap { public static ResponseResult error(String msg) { ResponseResult json = new ResponseResult(); - json.put((String)"code", "1");//错误 - json.put((String)"msg", msg); + json.put("code", "1");//错误 + json.put("msg", msg); return json; } public static ResponseResult message(String code, String msg) { ResponseResult json = new ResponseResult(); - json.put((String)"code", code); - json.put((String)"msg", msg); + json.put("code", code); + json.put("msg", msg); return json; } public static ResponseResult success(String msg) { ResponseResult json = new ResponseResult(); - json.put((String)"code", "0");//正常 - json.put((String)"msg", msg); + json.put("code", "0");//正常 + json.put("msg", msg); return json; } public static ResponseResult successData(Object obj) { ResponseResult json = new ResponseResult(); - json.put((String)"code", "0");//正常 - json.put((String)"msg", "操作成功"); + json.put("code", "0");//正常 + json.put("msg", "操作成功"); json.put("data", obj); return json; } diff --git a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java b/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java index e22f5087..9cc53580 100644 --- a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java +++ b/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java @@ -63,10 +63,12 @@ public class SecurityConfig { .requestMatchers("/data/fishDraft/previewFile").permitAll() .requestMatchers("/tempFile/**").permitAll() .requestMatchers("/system/user/auditUser").permitAll() + .requestMatchers("/register/accessToken").permitAll() .requestMatchers("/api/oauth2/oauth/token").permitAll() .requestMatchers("/dict/cache/**").permitAll() .requestMatchers("/sys/psbmodulelbb/**").permitAll() .requestMatchers("/base/operationLog/**").permitAll() + .requestMatchers("/system/**").permitAll() // .requestMatchers("/eng/**").permitAll() // .requestMatchers("/eq/**").permitAll() // .requestMatchers("/env/**").permitAll() diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java index 69c6f0be..981752a2 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFishDictoryBController.java @@ -12,6 +12,7 @@ import com.yfd.platform.qgc_base.domain.SdEngInfoBHOperateRequest; import com.yfd.platform.qgc_base.domain.SdFishDictoryB; import com.yfd.platform.qgc_base.service.ISdFishDictoryBService; import com.yfd.platform.qgc_data.service.AttachmentUploadService; +import com.yfd.platform.utils.DataSourceRequestUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -55,7 +56,7 @@ public class SdFishDictoryBController { @PostMapping("/list") @Operation(summary = "查询鱼类字典列表(支持动态过滤和排序,不分页)") public ResponseResult list(@RequestBody DataSourceRequest request) { - List list = sdFishDictoryBService.list(); + List list = DataSourceRequestUtil.executeList(request, SdFishDictoryB.class, sdFishDictoryBService); return ResponseResult.successData(list); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssBHMapper.java b/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssBHMapper.java index e12224c6..941f39ee 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssBHMapper.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssBHMapper.java @@ -17,7 +17,8 @@ public interface SdFpssBHMapper extends BaseMapper { "WHERE 1=1 " + " AND E.BASE_ID = #{baseId} " + " AND F.RSTCD = #{rstcd} " + - " AND E.REACHCD = #{rvcd} " + + " AND E.RVCD = #{rvcd} " + + " AND E.REACHCD = #{reachcd} " + // " AND F.RSTCD = #{rstcd} " + " AND F.STNM LIKE '%' || #{stnm} || '%' " + "ORDER BY F.ORDER_INDEX DESC" + diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java index a256f281..be3b1a60 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java @@ -46,6 +46,13 @@ public class FishPassageController { return ResponseResult.successData(fpRunService.processQgcFpssrlQueryKendoList(dataSourceRequest)); } + @PostMapping("/query/qgc/GetKendoListCustAI") + @Operation(summary = "全过程过鱼自动(AI设备)与人工监测数据查询") + public ResponseResult getQgcFpssrlAiRQueryKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fpRunService.processQgcFpssrlAiRQueryKendoList(dataSourceRequest)); + } + + @PostMapping("/fpssTable/qgc/GetKendoListCust") @Operation(summary = "过鱼设施监测数据查询") public ResponseResult getQgcFpssTableKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java index a3706df7..42b1054d 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java @@ -23,6 +23,8 @@ public interface FpRunService { DataSourceResult processQgcFpssrlQueryKendoList(DataSourceRequest dataSourceRequest); + DataSourceResult processQgcFpssrlAiRQueryKendoList(DataSourceRequest dataSourceRequest); + DataSourceResult processQgcFpssTableKendoList(DataSourceRequest dataSourceRequest); DataSourceResult getAnalysisData(DataSourceRequest dataSourceRequest); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java index cdaec94d..1cf4c621 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java @@ -220,6 +220,15 @@ public class FpRunServiceImpl implements FpRunService { return queryQgcFpssrlGroupList(dataSourceRequest, loadOptions); } + @Override + public DataSourceResult processQgcFpssrlAiRQueryKendoList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + if (CollUtil.isEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + return queryQgcFpssrlAiRDetailList(dataSourceRequest, loadOptions); + } + return queryQgcFpssrlAiRGroupList(dataSourceRequest, loadOptions); + } + @Override public DataSourceResult processQgcFpssTableKendoList(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -1211,6 +1220,33 @@ public class FpRunServiceImpl implements FpRunService { return result; } + private DataSourceResult queryQgcFpssrlAiRDetailList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildQgcFpssrlDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect())) + .append(" FROM (") + .append(buildQgcFpssrlAiRCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = buildQgcFpssrlFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + sql.append(buildQgcFpssrlOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort())); + + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, FpFpssrlQueryVo.class + ); + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + private DataSourceResult queryQgcFpssrlGroupList(DataSourceRequest dataSourceRequest, DataSourceLoadOptionsBase loadOptions) { List groups = dataSourceRequest.getGroup(); @@ -1284,6 +1320,79 @@ public class FpRunServiceImpl implements FpRunService { return result; } + private DataSourceResult queryQgcFpssrlAiRGroupList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + List groups = dataSourceRequest.getGroup(); + GroupingInfo[] groupInfos = loadOptions == null ? new GroupingInfo[0] : loadOptions.getGroup(); + + StringBuilder sql = new StringBuilder("SELECT "); + List selectItems = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapQgcFpssrlColumn(descriptor.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + selectItems.add(column + " AS " + descriptor.getField().toUpperCase()); + selectItems.add("COUNT(*) AS COUNT_" + descriptor.getField().toUpperCase()); + if (CollUtil.isNotEmpty(descriptor.getAggregates())) { + for (DataSourceRequest.AggregateDescriptor aggregate : descriptor.getAggregates()) { + String aggregateColumn = mapQgcFpssrlColumn(aggregate.getField()); + if (StrUtil.isBlank(aggregateColumn) || StrUtil.isBlank(aggregate.getAggregate())) { + continue; + } + String aggregateSql = buildAggregateSql(aggregate.getAggregate(), aggregateColumn, aggregate.getField()); + if (StrUtil.isNotBlank(aggregateSql)) { + selectItems.add(aggregateSql); + } + } + } + } + if (selectItems.isEmpty()) { + selectItems.add("t.STCD AS STCD"); + selectItems.add("COUNT(*) AS COUNT_STCD"); + } + + sql.append(String.join(", ", selectItems)) + .append(" FROM (") + .append(buildQgcFpssrlCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = buildQgcFpssrlFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + + List groupByColumns = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapQgcFpssrlColumn(descriptor.getField()); + if (StrUtil.isNotBlank(column)) { + groupByColumns.add(column); + } + } + if (!groupByColumns.isEmpty()) { + sql.append(" GROUP BY ").append(String.join(", ", groupByColumns)).append(" "); + } + sql.append(buildQgcFpssrlGroupOrderBySql(groups)); + + List> rows = microservicDynamicSQLMapper.pageAllList(null, sql.toString(), paramMap); + DataSourceResult result = new DataSourceResult<>(); + if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) { + result.setData((List) (List) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos))); + } else { + result.setData((List) (List) new GroupHelper().group(rows, Arrays.asList(groupInfos))); + } + result.setTotal(0L); + result.setAggregates(new HashMap<>()); + return result; + } + private DataSourceResult queryQgcSdfpssrGroupList(DataSourceRequest dataSourceRequest, DataSourceLoadOptionsBase loadOptions) { List groups = dataSourceRequest.getGroup(); @@ -1566,6 +1675,161 @@ public class FpRunServiceImpl implements FpRunService { ") src"; } + + private String buildQgcFpssrlAiRCoreSql() { + return "SELECT " + + "src.ID AS id, " + + "src.STCD AS stcd, " + + "src.STNM AS stnm, " + + "src.BASEID AS baseId, " + + "src.BASENAME AS baseName, " + + "src.RSTCD AS rstcd, " + + "src.ENNM AS ennm, " + + "src.HBRVCD AS hbrvcd, " + + "src.BASESTEPSORT AS baseStepSort, " + + "src.RVCDSTEPSORT AS rvcdStepSort, " + + "src.SITESTEPSORT AS siteStepSort, " + + "src.RSTCDSTEPSORT AS rstcdStepSort, " + + "src.TM AS tm, " + + "src.YR AS yr, " + + "src.FTP AS ftp, " + + "src.FISHID AS fishId, " + + "src.FSZ AS fsz, " + + "src.LENGTH AS length, " + + "src.WIDTH AS width, " + + "src.FISHSPEED AS fishspeed, " + + "src.DIRECTION AS direction, " + + "src.TEMPERATURE AS temperature, " + + "src.SPEED AS speed, " + + "src.CHANNELNO AS channelno, " + + "src.FCNT AS fcnt, " + + "src.FIRSTIMGURL AS firstimgurl, " + + "src.VIDEOURL AS videourl, " + + "src.MWAY AS mway, " + + "src.STRDT AS strdt, " + + "src.ENDDT AS enddt, " + + "src.STCODE AS stCode, " + + "src.STNAME AS stName " + + "FROM ( " + + " SELECT t.ID AS ID, " + + " t.STCD AS STCD, " + + " fp.STNM AS STNM, " + + " eng.BASE_ID AS BASEID, " + + " hb.BASENAME AS BASENAME, " + + " fp.RSTCD AS RSTCD, " + + " eng.ENNM AS ENNM, " + + " eng.HBRVCD AS HBRVCD, " + + " NVL(hb.ORDER_INDEX, 999999) AS BASESTEPSORT, " + + " NVL(hbrv.ORDER_INDEX, 999999) AS RVCDSTEPSORT, " + + " NVL(fp.ORDER_INDEX, 999999) AS SITESTEPSORT, " + + " NVL(eng.ORDER_INDEX, 999999) AS RSTCDSTEPSORT, " + + " t.TM AS TM, " + + " TO_CHAR(t.TM, 'YYYY') AS YR, " + + " COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " + + " t.FTP AS FISHID, " + + " t.FSZ AS FSZ, " + + " TO_CHAR(t.LENGTH) AS LENGTH, " + + " TO_CHAR(t.WIDTH) AS WIDTH, " + + " TO_CHAR(t.FISHSPEED) AS FISHSPEED, " + + " TO_CHAR(t.DIRECTION) AS DIRECTION, " + + " TO_CHAR(t.TEMPERATURE) AS TEMPERATURE, " + + " TO_CHAR(t.SPEED) AS SPEED, " + + " t.CHANNELNO AS CHANNELNO, " + + " TO_CHAR(t.FCNT) AS FCNT, " + + " t.FIRSTIMGURL AS FIRSTIMGURL, " + + " t.VIDEOURL AS VIDEOURL, " + + " 2 AS MWAY, " + + " CAST(NULL AS DATE) AS STRDT, " + + " CAST(NULL AS DATE) AS ENDDT, " + + " fp.STTP AS STCODE, " + + " sttp.STTP_NAME AS STNAME " + + " FROM SD_FPSSRL_AI_R t " + + " INNER JOIN V_MS_STBPRP_T fp ON fp.STCD = t.STCD " + + " LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD " + + " AND hbrv.BASEID = eng.BASE_ID " + + " AND NVL(hbrv.IS_DELETED, 0) = 0 " + + " AND NVL(hbrv.ENABLED, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = t.FTP " + + " AND relRv.RVCD = eng.HBRVCD " + + " AND NVL(relRv.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = relRv.ZY_FISH_ID " + + " AND NVL(fishRv.IS_DELETED, 0) = 0 " + + " AND NVL(fishRv.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = t.FTP " + + " AND relZy.RVCD = 'ZY' " + + " AND NVL(relZy.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = relZy.ZY_FISH_ID " + + " AND NVL(fishZy.IS_DELETED, 0) = 0 " + + " AND NVL(fishZy.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = t.FTP " + + " AND NVL(fishDirect.IS_DELETED, 0) = 0 " + + " AND NVL(fishDirect.ENABLE, 1) = 1 " + + " WHERE NVL(t.IS_DELETED, 0) = 0 " + + " UNION ALL " + + " SELECT t.ID AS ID, " + + " t.STCD AS STCD, " + + " fp.STNM AS STNM, " + + " eng.BASE_ID AS BASEID, " + + " hb.BASENAME AS BASENAME, " + + " fp.RSTCD AS RSTCD, " + + " eng.ENNM AS ENNM, " + + " eng.HBRVCD AS HBRVCD, " + + " NVL(hb.ORDER_INDEX, 999999) AS BASESTEPSORT, " + + " NVL(hbrv.ORDER_INDEX, 999999) AS RVCDSTEPSORT, " + + " NVL(fp.ORDER_INDEX, 999999) AS SITESTEPSORT, " + + " NVL(eng.ORDER_INDEX, 999999) AS RSTCDSTEPSORT, " + + " t.STRDT AS TM, " + + " TO_CHAR(t.STRDT, 'YYYY') AS YR, " + + " COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " + + " t.FTP AS FISHID, " + + " t.FSZ AS FSZ, " + + " CAST(NULL AS VARCHAR2(50)) AS LENGTH, " + + " CAST(NULL AS VARCHAR2(50)) AS WIDTH, " + + " CAST(NULL AS VARCHAR2(50)) AS FISHSPEED, " + + " TO_CHAR(t.DIRECTION) AS DIRECTION, " + + " CAST(NULL AS VARCHAR2(50)) AS TEMPERATURE, " + + " CAST(NULL AS VARCHAR2(50)) AS SPEED, " + + " CAST(NULL AS VARCHAR2(100)) AS CHANNELNO, " + + " TO_CHAR(t.FCNT) AS FCNT, " + + " t.PICPTH AS FIRSTIMGURL, " + + " t.VDPTH AS VIDEOURL, " + + " 1 AS MWAY, " + + " t.STRDT AS STRDT, " + + " t.ENDDT AS ENDDT, " + + " fp.STTP AS STCODE, " + + " sttp.STTP_NAME AS STNAME " + + " FROM SD_FPSS_R t " + + " INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD " + + " LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD " + + " AND hbrv.BASEID = eng.BASE_ID " + + " AND NVL(hbrv.IS_DELETED, 0) = 0 " + + " AND NVL(hbrv.ENABLED, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = t.FTP " + + " AND relRv.RVCD = eng.HBRVCD " + + " AND NVL(relRv.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = relRv.ZY_FISH_ID " + + " AND NVL(fishRv.IS_DELETED, 0) = 0 " + + " AND NVL(fishRv.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = t.FTP " + + " AND relZy.RVCD = 'ZY' " + + " AND NVL(relZy.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = relZy.ZY_FISH_ID " + + " AND NVL(fishZy.IS_DELETED, 0) = 0 " + + " AND NVL(fishZy.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = t.FTP " + + " AND NVL(fishDirect.IS_DELETED, 0) = 0 " + + " AND NVL(fishDirect.ENABLE, 1) = 1 " + + " WHERE NVL(t.IS_DELETED, 0) = 0 " + +// " AND (t.TASK_STATUS = 'Approved' OR t.TASK_STATUS IS NULL) " + + ") src"; + } + private String buildQgcSdfpssrDetailSelectSql(List selectFields) { Map selectMap = new LinkedHashMap<>(); selectMap.put("stcd", "t.stcd AS stcd"); diff --git a/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java b/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java index 82ed2e6f..689fa3c8 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java @@ -37,6 +37,7 @@ import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import java.sql.Timestamp; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -100,8 +101,12 @@ public class LoginController { Integer status = loginUser.getUser().getStatus(); String regStatus = loginUser.getUser().getRegStatus(); - if (StrUtil.isNotBlank(tenantId)&&!tenantId.equals(loginUser.getUser().getTenantId())) { - return ResponseResult.error("账号不存在或密码错误"); + // 多门户:验证用户是否有权限访问指定门户 + if (!loginUser.isSuperAdmin() && StrUtil.isNotBlank(tenantId)) { + List accessibleIds = loginUser.getAccessibleTenantIds(); + if (accessibleIds == null || !accessibleIds.contains(tenantId)) { + return ResponseResult.error("账号不存在或密码错误"); + } } if (StrUtil.isNotBlank(regStatus)&&"REJECTED".equals(regStatus)) { @@ -149,6 +154,10 @@ public class LoginController { String token = JWTUtil.createToken(map, "12345678".getBytes()); map.put("token", token); + // 返回可访问门户列表和超级管理员标识 + map.put("accessibleTenantIds", loginUser.getAccessibleTenantIds()); + map.put("superAdmin", loginUser.isSuperAdmin()); + map.put("currentTenantId", tenantId); //把完整的用户信息存入到HuTool缓存中,userId作为key String jsonStr = JSONUtil.toJsonStr(loginUser); webConfig.loginuserCache().put("login:" + userId, jsonStr); @@ -232,7 +241,7 @@ public class LoginController { @Operation(summary = "查询当前用户信息") @ResponseBody public ResponseResult getUserInfo() { - ResponseResult responseResult = userService.getLoginUserInfo(); + Map responseResult = userService.getLoginUserInfo(); return ResponseResult.successData(responseResult); } diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java index 5bf84847..06e5d6e9 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SmsVerifyCodeController.java @@ -1,7 +1,9 @@ package com.yfd.platform.system.controller; +import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import cn.hutool.jwt.JWTUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.WebConfig; import com.yfd.platform.qgc_data.domain.SysUserDataScope; @@ -11,6 +13,9 @@ import com.yfd.platform.qgc_base.service.ISdEngInfoBHService; import com.yfd.platform.qgc_base.service.ISdHbrvDicService; import com.yfd.platform.system.domain.*; import com.yfd.platform.system.mapper.SysMenuMapper; +import com.yfd.platform.system.mapper.SysOrganizationMapper; +import com.yfd.platform.system.mapper.SysRoleMapper; +import com.yfd.platform.system.mapper.SysUserTenantMapper; import com.yfd.platform.system.service.ISmsVerifyCodeService; import com.yfd.platform.system.service.ISysLogService; import com.yfd.platform.system.service.IUserService; @@ -60,25 +65,36 @@ public class SmsVerifyCodeController { @Resource private SysMenuMapper sysMenuMapper; + @Resource + private SysOrganizationMapper organizationMapper; + + @Resource + private SysRoleMapper roleMapper; + @Resource private ISysUserDataScopeService sysUserDataScopeService; @Resource private ISdEngInfoBHService engInfoBHService; + @Resource + private SysUserTenantMapper sysUserTenantMapper; + + @Resource + private SysUserTenantMapper userTenantMapper; @Resource private ISdHbrvDicService hbrvDicService; @Value("${rsa.private_key}") private String privateKey; - private static final String URGE_CONTENT ="根据生态环境部要求,请贵电站尽快完成过鱼数据的报送工作,感谢支持。"; + private static final String URGE_CONTENT = "根据生态环境部要求,请贵电站尽快完成过鱼数据的报送工作,感谢支持。"; /** * 发送验证码 */ @PostMapping("/sendCode") @Operation(summary = "发送验证码") - public ResponseResult sendVerifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult sendVerifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { String phone = smsVerifyCodeRequest.getPhone(); Integer type = smsVerifyCodeRequest.getType(); @@ -91,21 +107,21 @@ public class SmsVerifyCodeController { // 1. 注册验证码校验 if (type.equals(SmsVerifyCode.TYPE_REGISTER)) { - SysUser existUser = userService.getUserByPhone(phone,tenantId); + SysUser existUser = userService.getUserByPhone(phone, tenantId); if (existUser != null) { return ResponseResult.error("该手机号已注册"); } } // 2. 找回密码验证码校验 else if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) { - SysUser existUser = userService.getUserByPhone(phone,tenantId); + SysUser existUser = userService.getUserByPhone(phone, tenantId); if (existUser == null) { return ResponseResult.error("该手机号未注册"); } } // 3. 登录验证码校验(新增) else if (type.equals(SmsVerifyCode.TYPE_LOGIN)) { - SysUser existUser = userService.getUserByPhone(phone,tenantId); + SysUser existUser = userService.getUserByPhone(phone, tenantId); if (existUser == null) { return ResponseResult.error("该手机号未注册,请先注册"); } @@ -113,12 +129,11 @@ public class SmsVerifyCodeController { // if (existUser.getStatus() == 0) { // return ResponseResult.error("账号已被禁用"); // } - } - else { + } else { return ResponseResult.error("类型错误:1-注册 2-找回密码 3-登录"); } - String code = smsVerifyCodeService.sendVerifyCode(phone, type,tenantId); + String code = smsVerifyCodeService.sendVerifyCode(phone, type, tenantId); if (code == null) { return ResponseResult.error("验证码发送失败,请稍后重试"); } @@ -132,10 +147,10 @@ public class SmsVerifyCodeController { */ @PostMapping("/batchSendContent") @Operation(summary = "批量发送短信") - public ResponseResult batchSendContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult batchSendContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { List phoneList = smsVerifyCodeRequest.getPhoneList(); - if(phoneList==null){ + if (phoneList == null) { return ResponseResult.error("手机号不能为空"); } @@ -148,7 +163,7 @@ public class SmsVerifyCodeController { */ @PostMapping("/batchUrgeContent") @Operation(summary = "催促") - public ResponseResult batchUrgeContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult batchUrgeContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { List userIds = smsVerifyCodeRequest.getUserIds(); String content = smsVerifyCodeRequest.getContent(); @@ -161,7 +176,7 @@ public class SmsVerifyCodeController { } try { - int successCount = smsVerifyCodeService.urgeByUserIds(tenantId,userIds, content); + int successCount = smsVerifyCodeService.urgeByUserIds(tenantId, userIds, content); Map result = new HashMap<>(); // result.put("successCount", successCount); result.put("totalCount", userIds.size()); @@ -173,14 +188,13 @@ public class SmsVerifyCodeController { } - /** * 注册用户 */ @PostMapping("/register") @Operation(summary = "注册用户") - @Transactional - public ResponseResult register(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + @Transactional(rollbackFor = Exception.class) + public ResponseResult register(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { String code = smsVerifyCodeRequest.getCode(); if (smsVerifyCodeRequest.getPhone() == null || smsVerifyCodeRequest.getPhone().isEmpty()) { return ResponseResult.error("手机号不能为空"); @@ -195,12 +209,12 @@ public class SmsVerifyCodeController { return ResponseResult.error("验证码不能为空"); } - boolean verified = smsVerifyCodeService.verifyCode(smsVerifyCodeRequest.getPhone(), code, SmsVerifyCode.TYPE_REGISTER,tenantId); + boolean verified = smsVerifyCodeService.verifyCode(smsVerifyCodeRequest.getPhone(), code, SmsVerifyCode.TYPE_REGISTER, tenantId); if (!verified) { return ResponseResult.error("验证码错误或已过期"); } - SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(),tenantId); + SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(), tenantId); if (existUser != null) { return ResponseResult.error("该手机号已注册"); } @@ -212,13 +226,15 @@ public class SmsVerifyCodeController { } catch (Exception e) { return ResponseResult.error("密码解密失败"); } + SysOrganization aDefault = organizationMapper.selectOne(new LambdaQueryWrapper().eq(SysOrganization::getCustom1, "default")); + String orgid = aDefault == null ? null : aDefault.getId(); user.setRegStatus("PENDING"); user.setPhone(smsVerifyCodeRequest.getPhone()); user.setBelongingUnit(smsVerifyCodeRequest.getBelongingUnit()); user.setRegTime(new Date()); user.setNickname(smsVerifyCodeRequest.getRealName()); user.setStatus(0); - user.setOrgid("e90063ced25e3d469860e88d920c082f"); + user.setOrgid(orgid); user.setUsertype(1); user.setTenantId(tenantId); user.setUsername(smsVerifyCodeRequest.getUsername()); @@ -226,8 +242,14 @@ public class SmsVerifyCodeController { user.setCompanyCode(smsVerifyCodeRequest.getCompanyCode()); boolean success = userService.save(user); // 给注册用户加上默认权限 - SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(),tenantId); + SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(), tenantId); if (savedUser != null) { + SysUserTenant sysUserTenant = new SysUserTenant(); + sysUserTenant.setTenantId(tenantId); + sysUserTenant.setUserId(user.getId()); + sysUserTenant.setId(user.getId()); +// sysUserTenant.setOperateTime(new Date()); + userTenantMapper.insert(sysUserTenant); this.addDefaultRole(savedUser.getId(), smsVerifyCodeRequest); } if (success) { @@ -237,109 +259,150 @@ public class SmsVerifyCodeController { } } + /** + * 给用户分配流域/电站数据权限 + 默认角色。 + *

+ * 逻辑说明: + * 1. 收集前端传入的电站编码,按流域分组 + * 2. 如果用户选了某流域的所有电站 → 保存流域权限(RVCD) + * 3. 如果用户只选了某流域的部分电站 → 逐个保存电站权限(STATION) + * 4. 数据库中查不到的孤立电站编码 → 直接保存电站权限 + *

+ * 示例: + * - 选了 A流域全部6个电站 + B流域全部3个电站 + C流域1个电站 + * → 两条 RVCD(A、B)+ 一条 STATION(C的电站) + */ private boolean addDefaultRole(String userId, SmsVerifyCodeRequest smsVerifyCodeRequest) { if (userId == null || userId.isEmpty()) { return false; } + // 1. 收集前端传入的电站编码 String stationCode = smsVerifyCodeRequest.getStationCode(); - String rvcdCode = smsVerifyCodeRequest.getRvcdCode(); - Set selectedStationCodes = new HashSet<>(); if (StringUtils.isNotEmpty(stationCode)) { selectedStationCodes.addAll(Arrays.asList(stationCode.split(","))); } - Set selectedBasinCodes = new HashSet<>(); - if (StringUtils.isNotEmpty(rvcdCode)) { - selectedBasinCodes.addAll(Arrays.asList(rvcdCode.split(","))); + // 2. 如果没有选择任何电站 + if (selectedStationCodes.isEmpty()) { + // 如果只传了流域,直接保存流域权限 + String rvcdCode = smsVerifyCodeRequest.getRvcdCode(); + if (StringUtils.isNotEmpty(rvcdCode)) { + for (String basinCode : rvcdCode.split(",")) { + if (StringUtils.isNotEmpty(basinCode)) { + addDataScope(userId, "RVCD", basinCode); + } + } + } + assignRoleToUser(userId); + return true; } -// Set addedStationCodes = new HashSet<>(); + // 3. 批量查询所有选中电站的工程信息,获取每个电站所属的流域 + List selectedStations = engInfoBHService.lambdaQuery() + .in(SdEngInfoBH::getStcd, selectedStationCodes) + .list(); - for (String basinCode : selectedBasinCodes) { - if (StringUtils.isEmpty(basinCode)) { - continue; + // 已通过电站权限处理过的电站编码 + Set processedStationCodes = new HashSet<>(); + // 已通过电站分组处理过的流域编码(用于后续差集判断) + Set processedBasinCodes = new HashSet<>(); + + if (!selectedStations.isEmpty()) { + // 4. 按流域分组:{rvcd -> Set} + Map> basinToStations = new LinkedHashMap<>(); + for (SdEngInfoBH station : selectedStations) { + String reachcd = station.getReachcd(); + String stcd = station.getStcd(); + if (StrUtil.isBlank(reachcd)) { + // 无流域归属的电站,直接保存电站权限 + addDataScope(userId, "STATION", stcd); + processedStationCodes.add(stcd); + continue; + } + basinToStations.computeIfAbsent(reachcd, k -> new HashSet<>()).add(stcd); } - List allStationsInBasin = engInfoBHService.lambdaQuery() - .eq(SdEngInfoBH::getRvcd, basinCode) - .list(); + // 5. 对每个流域,判断用户是否选中了该流域的全部电站 + for (Map.Entry> entry : basinToStations.entrySet()) { + String basinCode = entry.getKey(); + Set selectedInThisBasin = entry.getValue(); - if (allStationsInBasin == null || allStationsInBasin.isEmpty()) { - SysUserDataScope scope = new SysUserDataScope(); - scope.setUserId(userId); - scope.setOrgType("RVCD"); - scope.setOrgId(basinCode); - scope.setStatus(1); - scope.setPermissionType("READ"); - sysUserDataScopeService.addDataScope(scope); - continue; - } - - Set allStationCodesInBasin = allStationsInBasin.stream() - .map(SdEngInfoBH::getStcd) - .collect(Collectors.toSet()); - - boolean allStationsSelected = allStationCodesInBasin.containsAll(selectedStationCodes) - && selectedStationCodes.containsAll(allStationCodesInBasin); - - if (allStationsSelected) { - SysUserDataScope scope = new SysUserDataScope(); - scope.setUserId(userId); - scope.setOrgType("RVCD"); - scope.setOrgId(basinCode); - scope.setStatus(1); - scope.setPermissionType("READ"); - sysUserDataScopeService.addDataScope(scope); -// addedStationCodes.add(basinCode); - } else { - Set stationsInBasinAndSelected = allStationCodesInBasin.stream() - .filter(selectedStationCodes::contains) + // 查询该流域下的所有电站 + List allStationsInBasin = engInfoBHService.lambdaQuery() + .eq(SdEngInfoBH::getReachcd, basinCode) + .list(); + Set allStationCodesInBasin = allStationsInBasin.stream() + .map(SdEngInfoBH::getStcd) .collect(Collectors.toSet()); - for (String stationCd : stationsInBasinAndSelected) { - SysUserDataScope scope = new SysUserDataScope(); - scope.setUserId(userId); - scope.setOrgType("STATION"); - scope.setOrgId(stationCd); - scope.setStatus(1); - scope.setPermissionType("READ"); - sysUserDataScopeService.addDataScope(scope); -// addedStationCodes.add(stationCd); + if (allStationCodesInBasin.equals(selectedInThisBasin)) { + // 全选 → 保存流域权限 + addDataScope(userId, "RVCD", basinCode); + } else { + // 部分选 → 逐个保存电站权限 + for (String stcd : selectedInThisBasin) { + addDataScope(userId, "STATION", stcd); + } + } + processedStationCodes.addAll(selectedInThisBasin); + processedBasinCodes.add(basinCode); + } + } + + // 6. 处理数据库中查不到的电站编码(孤立的电站),直接保存电站权限 + for (String stcd : selectedStationCodes) { + if (!processedStationCodes.contains(stcd)) { + addDataScope(userId, "STATION", stcd); + } + } + + // 7. 处理前端传了流域、但该流域下未匹配到任何选中电站的情况(直接保存流域权限) + String rvcdCode = smsVerifyCodeRequest.getRvcdCode(); + if (StringUtils.isNotEmpty(rvcdCode)) { + for (String basinCode : rvcdCode.split(",")) { + if (StringUtils.isNotEmpty(basinCode) && !processedBasinCodes.contains(basinCode)) { + addDataScope(userId, "RVCD", basinCode); } } } -// Set standaloneStations = selectedStationCodes.stream() -// .filter(code -> !addedStationCodes.contains(code)) -// .collect(Collectors.toSet()); -// -// for (String stationCd : standaloneStations) { -// if (StringUtils.isEmpty(stationCd)) { -// continue; -// } -// SysUserDataScope scope = new SysUserDataScope(); -// scope.setUserId(userId); -// scope.setOrgType("STATION"); -// scope.setOrgId(stationCd); -// scope.setStatus(1); -// scope.setPermissionType("READ"); -// sysUserDataScopeService.addDataScope(scope); -// } - SysUser user = new SysUser(); - user.setId(userId); - userService.updateUserRoles( user,"c13481a486c9ee559cf305284df4d207"); - // 加上角色权限 + // 8. 分配默认角色 + assignRoleToUser(userId); return true; } + /** + * 保存一条数据权限 + */ + private void addDataScope(String userId, String orgType, String orgId) { + SysUserDataScope scope = new SysUserDataScope(); + scope.setUserId(userId); + scope.setOrgType(orgType); + scope.setOrgId(orgId); + scope.setStatus(1); + scope.setPermissionType("READ"); + sysUserDataScopeService.addDataScope(scope); + } + + /** + * 给用户分配默认角色 + */ + private void assignRoleToUser(String userId) { + SysUser user = new SysUser(); + SysRole aDefault = roleMapper.selectOne(new LambdaQueryWrapper().eq(SysRole::getCustom1, "default")); + String roleids = aDefault == null ? null : aDefault.getId(); + user.setId(userId); + userService.updateUserRoles(user, roleids); + } + /** * 找回密码 */ @PostMapping("/resetPassword") @Operation(summary = "找回密码") - public ResponseResult resetPassword(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult resetPassword(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { String password = smsVerifyCodeRequest.getPassword(); String phone = smsVerifyCodeRequest.getPhone(); String code = smsVerifyCodeRequest.getCode(); @@ -353,12 +416,12 @@ public class SmsVerifyCodeController { return ResponseResult.error("新密码不能为空"); } - boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_FIND_PASSWORD,tenantId); + boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_FIND_PASSWORD, tenantId); if (!verified) { return ResponseResult.error("验证码错误或已过期"); } - SysUser existUser = userService.getUserByPhone(phone,tenantId); + SysUser existUser = userService.getUserByPhone(phone, tenantId); if (existUser == null) { return ResponseResult.error("该手机号未注册"); } @@ -383,11 +446,11 @@ public class SmsVerifyCodeController { */ @PostMapping("/verifyCode") @Operation(summary = "验证验证码") - public ResponseResult verifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult verifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { String phone = smsVerifyCodeRequest.getPhone(); String code = smsVerifyCodeRequest.getCode(); Integer type = smsVerifyCodeRequest.getType(); - boolean valid = smsVerifyCodeService.verifyCode(phone, code, type,tenantId); + boolean valid = smsVerifyCodeService.verifyCode(phone, code, type, tenantId); if (valid) { return ResponseResult.success(); } else { @@ -400,7 +463,7 @@ public class SmsVerifyCodeController { */ @PostMapping("/login") @Operation(summary = "短信验证码登录") - public ResponseResult smsLogin(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { + public ResponseResult smsLogin(@RequestHeader(value = "Tenant_id", required = false) String tenantId, @RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) { String phone = smsVerifyCodeRequest.getPhone(); String code = smsVerifyCodeRequest.getCode(); if (phone == null || phone.isEmpty()) { @@ -410,12 +473,12 @@ public class SmsVerifyCodeController { return ResponseResult.error("验证码不能为空"); } - boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN,tenantId); + boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN, tenantId); if (!verified) { return ResponseResult.error("验证码错误或已过期"); } - SysUser user = userService.getUserByPhone(phone,tenantId); + SysUser user = userService.getUserByPhone(phone, tenantId); if (user == null) { return ResponseResult.error("该手机号未注册"); } @@ -441,9 +504,15 @@ public class SmsVerifyCodeController { loginUser.setUser(user); loginUser.setUsername(user.getUsername()); //Todo 根据用户查询权限信息 添加到LoginUser中 - List permissions = - sysMenuMapper.selectPermsByUserId(user.getId()); - loginUser.setPermissions( permissions); + // 加载权限:超级管理员加载全部权限,普通用户按门户过滤 + boolean isSuperAdmin = userService.isSuperAdmin(user.getId()); + List permissions; + if (isSuperAdmin) { + permissions = sysMenuMapper.selectPermsByUserId(user.getId(), null); + } else { + permissions = sysMenuMapper.selectPermsByUserId(user.getId(), tenantId); + } + loginUser.setPermissions(permissions); HttpServletRequest request = RequestHolder.getHttpServletRequest(); SysLog sysLog = new SysLog(); sysLog.setUsercode(user.getUsername()); diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java index bb4f90c6..5575de40 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java @@ -101,6 +101,21 @@ public class SysMenuController { return sysMenuService.permissionAssignment(code, roleId, StrUtil.trimToNull(tenantId)); } + /*********************************** + * 用途说明:权限分配(按系统分组,附带系统标识和名称) + * 参数说明 + * roleId 角色ID + * 返回值说明: [{"systemCode":"1","systemName":"Web端","menus":[...]}, ...] + * 系统名称通过字典 PLATFORM_TENANT 获取 + ***********************************/ + @PostMapping("/permissionAssignmentGrouped") + @Operation(summary = "获取分配权限-按系统分组(含系统标识和名称)") + @ResponseBody + public List> permissionAssignmentGrouped(String roleId, + String tenantId) { + return sysMenuService.permissionAssignmentGrouped(roleId, StrUtil.trimToNull(tenantId)); + } + /********************************** * 用途说明: 获取当前用户菜单结构树 * 参数说明 @@ -111,11 +126,12 @@ public class SysMenuController { @ResponseBody public List> getMenuTreeByUser(@RequestHeader(value = "Tenant_id", required = false) String tenantId) { SysUser userInfo = userService.getUserInfo(); + boolean superAdmin = userService.isSuperAdmin(userInfo.getId()); String id = ""; - if (0 != userInfo.getUsertype()) { + if (0 != userInfo.getUsertype() && !superAdmin) { id = userInfo.getId(); } - return sysMenuService.getMenuTree(id, StrUtil.isNotBlank(tenantId) ? StrUtil.trimToNull(tenantId) : userInfo.getTenantId()); + return sysMenuService.getMenuTree(id, tenantId); } /*********************************** @@ -148,7 +164,7 @@ public class SysMenuController { @ResponseBody public ResponseResult addMenu(@RequestBody SysMenu sysMenu, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - sysMenu.setTenantId(StrUtil.trimToNull(tenantId)); +// sysMenu.setTenantId(StrUtil.trimToNull(tenantId)); if(StrUtil.isBlank(sysMenu.getTenantId())){ sysMenu.setTenantId(sysMenu.getSystemcode()); } @@ -178,7 +194,7 @@ public class SysMenuController { if (sysMenuService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的菜单"); } - sysMenu.setTenantId(StrUtil.trimToNull(tenantId)); +// sysMenu.setTenantId(StrUtil.trimToNull(tenantId)); if(StrUtil.isBlank(sysMenu.getTenantId())){ sysMenu.setTenantId(sysMenu.getSystemcode()); } @@ -206,8 +222,8 @@ public class SysMenuController { public ResponseResult deleteIcon(@RequestParam String id, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysMenu::getId, id); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); if (sysMenuService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的菜单"); } @@ -234,7 +250,7 @@ public class SysMenuController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 修改是否显示 ,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isdisplay", isdisplay).set( + updateWrapper.eq("id", id).set("isdisplay", isdisplay).set( "lastmodifier", userService.getUsername()).set( "lastmodifydate", new Timestamp(System.currentTimeMillis())); @@ -262,12 +278,12 @@ public class SysMenuController { @RequestParam int orderno, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysMenu::getId, id); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); if (sysMenuService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的菜单"); } - boolean ok = sysMenuService.moveOrderno(parentid, id, orderno, StrUtil.trimToNull(tenantId)); + boolean ok = sysMenuService.moveOrderno(parentid, id, orderno, null); if (ok) { return ResponseResult.success(); } else { @@ -288,8 +304,8 @@ public class SysMenuController { public ResponseResult deleteById(@RequestParam String id, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysMenu::getId, id); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); if (sysMenuService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的菜单"); } @@ -321,11 +337,11 @@ public class SysMenuController { return ResponseResult.error("切换失败!"); } LambdaQueryWrapper fromWrapper = new LambdaQueryWrapper<>(); - fromWrapper.eq(SysMenu::getId, fromId) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + fromWrapper.eq(SysMenu::getId, fromId); +// fromWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); LambdaQueryWrapper toWrapper = new LambdaQueryWrapper<>(); - toWrapper.eq(SysMenu::getId, toId) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + toWrapper.eq(SysMenu::getId, toId); +// toWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); if (sysMenuService.getOne(fromWrapper) == null || sysMenuService.getOne(toWrapper) == null) { return ResponseResult.error("存在不属于当前租户的菜单"); } @@ -350,8 +366,8 @@ public class SysMenuController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) throws FileNotFoundException { if (StrUtil.isNotBlank(menuId)) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getId, menuId) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysMenu::getId, menuId); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)); SysMenu sysMenu = sysMenuService.getOne(queryWrapper); if (sysMenu == null) { return ResponseResult.error("未找到对应租户的菜单"); diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java index 907aaa1f..f0315668 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java @@ -53,7 +53,7 @@ public class SysOrganizationController { @ResponseBody public List> getOrgScopeTree(String roleId, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - return organizationService.getOrgScopeTree(roleId, StrUtil.trimToNull(tenantId)); + return organizationService.getOrgScopeTree(roleId, null); } /*********************************** @@ -67,7 +67,7 @@ public class SysOrganizationController { public List> getOrgTree(String parentid, String params, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - return organizationService.getOrgTree(parentid, params, StrUtil.trimToNull(tenantId)); + return organizationService.getOrgTree(parentid, params, null); } /*********************************** @@ -85,7 +85,7 @@ public class SysOrganizationController { return ResponseResult.error("查询失败!"); } List sysOrganizations = - organizationService.getOrganizationById(id, orgName, StrUtil.trimToNull(tenantId)); + organizationService.getOrganizationById(id, orgName, null); return ResponseResult.successData(sysOrganizations); } @@ -102,8 +102,8 @@ public class SysOrganizationController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysOrganization::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysOrganization::getId, id); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); SysOrganization sysOrganization = organizationService.getOne(queryWrapper); return ResponseResult.successData(sysOrganization); } @@ -127,7 +127,7 @@ public class SysOrganizationController { if("".equals(sysOrganization.getId())){ sysOrganization.setId(null); } - sysOrganization.setTenantId(StrUtil.trimToNull(tenantId)); +// sysOrganization.setTenantId(StrUtil.trimToNull(tenantId)); //填写 当前用户名称 sysOrganization.setLastmodifier(userService.getUsername()); //填写 当前日期 @@ -155,12 +155,12 @@ public class SysOrganizationController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysOrganization::getId, sysOrganization.getId()) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysOrganization::getId, sysOrganization.getId()); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); if (organizationService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的组织"); } - sysOrganization.setTenantId(StrUtil.trimToNull(tenantId)); +// sysOrganization.setTenantId(StrUtil.trimToNull(tenantId)); //填写 当前用户名称 sysOrganization.setLastmodifier(userService.getUsername()); //填写 当前日期 @@ -189,7 +189,7 @@ public class SysOrganizationController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 修改是否有效,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isvaild", isvaild).set("lastmodifier" + updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier" , userService.getUsername()).set("lastmodifydate", new Timestamp(System.currentTimeMillis())); boolean isOk = organizationService.update(updateWrapper); @@ -216,28 +216,24 @@ public class SysOrganizationController { for (String orgId : orgIds) { LambdaQueryWrapper currentWrapper = new LambdaQueryWrapper<>(); - currentWrapper.eq(SysOrganization::getId, orgId) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); + currentWrapper.eq(SysOrganization::getId, orgId); +// currentWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); if (organizationService.getOne(currentWrapper) == null) { - return ResponseResult.error("存在不属于当前租户的组织"); + return ResponseResult.error("不存在对应组织"); } - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)); List list = - organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId))); + organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId)); List ids = - list.stream().map(SysOrganization::getId).collect(Collectors.toList()); + list.stream().map(SysOrganization::getId).toList(); boolean isOk = organizationService.remove(new LambdaQueryWrapper() - .eq(SysOrganization::getId, orgId) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId))); + .eq(SysOrganization::getId, orgId)); if (!isOk) { continue; } for (String oid : ids) { - organizationService.remove(new LambdaQueryWrapper() - .eq(SysOrganization::getId, oid) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId))); + organizationService.remove(new LambdaQueryWrapper().eq(SysOrganization::getId, oid)); } } return ResponseResult.success(); diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java index fbb0bbc1..cf264e46 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java @@ -54,8 +54,23 @@ public class SysRoleController { @Operation(summary = "查询所有角色") @ResponseBody public List list(@RequestParam(required = false) String rolename, - @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - return roleService.selectRoleList(rolename, StrUtil.trimToNull(tenantId)); + @RequestParam(required = false) String tenantId) { + return roleService.selectRoleList(rolename, tenantId); + } + + /*********************************** + * 用途说明:按门户分组查询角色(门户 → 角色两层结构) + * 参数说明 + * rolename 角色名称(可选,模糊搜索) + * 返回值说明: [{"tenantId":"...","tenantName":"水利门户","roles":[...]}, ...] + * 门户中文名通过字典 PLATFORM_TENANT 获取 + ***********************************/ + @PostMapping("/listGroupedByTenant") + @Operation(summary = "按门户分组查询角色(含门户中文名)") + @ResponseBody + public List> listGroupedByTenant(@RequestParam(required = false) String rolename, + @RequestParam(required = false) String tenantId) { + return roleService.selectRoleListGroupedByTenant(tenantId,rolename); } /*********************************** @@ -70,8 +85,8 @@ public class SysRoleController { public ResponseResult getOneById(String id, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysRole::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysRole::getId, id); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); SysRole sysRole = roleService.getOne(queryWrapper); return ResponseResult.successData(sysRole); } @@ -88,7 +103,7 @@ public class SysRoleController { @ResponseBody public ResponseResult addRole(@RequestBody SysRole sysRole, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - sysRole.setTenantId(StrUtil.trimToNull(tenantId)); +// sysRole.setTenantId(StrUtil.trimToNull(tenantId)); boolean isOk = roleService.addRole(sysRole); if (isOk) { return ResponseResult.success(); @@ -113,7 +128,7 @@ public class SysRoleController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 更新权限,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("optscope", optscope).set( + updateWrapper.eq("id", id).set("optscope", optscope).set( "lastmodifier", userService.getUsername()).set( "lastmodifydate", LocalDateTime.now()); boolean ok = roleService.update(updateWrapper); @@ -141,8 +156,7 @@ public class SysRoleController { return ResponseResult.error("参数为空"); } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysRole::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysRole::getId, id); if (roleService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的角色"); } @@ -158,8 +172,7 @@ public class SysRoleController { return ResponseResult.success(); } long menuCount = sysMenuService.count(new LambdaQueryWrapper() - .in(SysMenu::getId, menuIdList) - .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId))); + .in(SysMenu::getId, menuIdList)); if (menuCount != menuIdList.size()) { return ResponseResult.error("存在不属于当前租户的菜单"); } @@ -188,7 +201,7 @@ public class SysRoleController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 更新组织范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("orgscope", orgscope).set( + updateWrapper.eq("id", id).set("orgscope", orgscope).set( "lastmodifier", userService.getUsername()).set( "lastmodifydate", LocalDateTime.now()); boolean ok = roleService.update(updateWrapper); @@ -215,7 +228,7 @@ public class SysRoleController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 更新业务范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("busscope", busscope).set( + updateWrapper.eq("id", id).set("busscope", busscope).set( "lastmodifier", userService.getUsername()).set( "lastmodifydate", LocalDateTime.now()); boolean ok = roleService.update(updateWrapper); @@ -240,8 +253,7 @@ public class SysRoleController { public ResponseResult setRoleUsers(String roleid, String userids, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper roleWrapper = new LambdaQueryWrapper<>(); - roleWrapper.eq(SysRole::getId, roleid) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + roleWrapper.eq(SysRole::getId, roleid); if (roleService.getOne(roleWrapper) == null) { return ResponseResult.error("未找到对应租户的角色"); } @@ -270,8 +282,7 @@ public class SysRoleController { @RequestParam String userids, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper roleWrapper = new LambdaQueryWrapper<>(); - roleWrapper.eq(SysRole::getId, roleid) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + roleWrapper.eq(SysRole::getId, roleid); if (roleService.getOne(roleWrapper) == null) { return ResponseResult.error("未找到对应租户的角色"); } @@ -298,7 +309,7 @@ public class SysRoleController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id 更新业务范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isvaild", isvaild).set("lastmodifier" + updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier" , userService.getUsername()).set("lastmodifydate", LocalDateTime.now()); boolean ok = roleService.update(updateWrapper); @@ -321,8 +332,7 @@ public class SysRoleController { public ResponseResult updateById(@RequestBody SysRole sysRole, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysRole::getId, sysRole.getId()) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysRole::getId, sysRole.getId()); if (roleService.getOne(queryWrapper) == null) { return ResponseResult.error("未找到对应租户的角色"); } @@ -354,8 +364,7 @@ public class SysRoleController { String[] roleIds = id.split(","); for (String roleId : roleIds) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysRole::getId, roleId) - .eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysRole::getId, roleId); if (roleService.getOne(queryWrapper) == null) { return ResponseResult.error("存在不属于当前租户的角色"); } @@ -383,7 +392,7 @@ public class SysRoleController { String rolename, String isvaild, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { return roleService.listRoleUsers(orgid, username, status, level, - rolename, isvaild, StrUtil.trimToNull(tenantId)); + rolename, isvaild, null); } } diff --git a/backend/src/main/java/com/yfd/platform/system/controller/UserController.java b/backend/src/main/java/com/yfd/platform/system/controller/UserController.java index ce4945b4..6ba65552 100644 --- a/backend/src/main/java/com/yfd/platform/system/controller/UserController.java +++ b/backend/src/main/java/com/yfd/platform/system/controller/UserController.java @@ -17,6 +17,7 @@ import org.springframework.web.multipart.MultipartFile; import jakarta.annotation.Resource; import java.sql.Timestamp; +import java.util.List; import java.util.Map; /** @@ -45,7 +46,7 @@ public class UserController { public ResponseResult addUser(@RequestBody SysUser user, String roleids, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - user.setTenantId(StrUtil.trimToNull(tenantId)); +// user.setTenantId(StrUtil.trimToNull(tenantId)); Map reslut = userService.addUser(user, roleids); return ResponseResult.successData(reslut); } @@ -60,7 +61,7 @@ public class UserController { if (StrUtil.isEmpty(user.getId())) { return ResponseResult.error("没有用户ID"); } - user.setTenantId(StrUtil.trimToNull(tenantId)); +// user.setTenantId(StrUtil.trimToNull(tenantId)); //填写 当前用户名称 user.setLastmodifier(userService.getUsername()); //填写 当前日期 @@ -79,7 +80,7 @@ public class UserController { @RequestHeader(value = "Tenant_id", required = false) String tenantId) { Page mapPage = userService.queryUsers(orgid, - username, StrUtil.trimToNull(tenantId), page); + username, null, page); return ResponseResult.successData(mapPage); } @@ -115,8 +116,8 @@ public class UserController { public ResponseResult queryUserById(String id, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysUser::getId, id) - .eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, StrUtil.trim(tenantId)); + queryWrapper.eq(SysUser::getId, id); +// .eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, StrUtil.trim(tenantId)); SysUser user = userService.getOne(queryWrapper); return ResponseResult.successData(user); } @@ -248,7 +249,57 @@ public class UserController { String name, String regStatus, @RequestHeader(value = "Tenant_id", required = false) String tenantId) { - Page result = userService.queryPendingAuditUsers(page, name, regStatus, StrUtil.trimToNull(tenantId)); + Page result = userService.queryPendingAuditUsers(page, name, regStatus, null); return ResponseResult.successData(result); } + + // ==================== 多门户管理 ==================== + + /*********************************** + * 用途说明:为用户分配门户 + * 参数说明 userId 用户ID, tenantIds 门户ID列表(逗号分隔) + ************************************/ + @Log(module = "系统用户", value = "分配门户") + @PostMapping("/assignTenant") + @Operation(summary = "为用户分配门户") + @ResponseBody + public ResponseResult assignTenant(String userId, String tenantIds) { + if (StrUtil.isBlank(userId) || StrUtil.isBlank(tenantIds)) { + return ResponseResult.error("用户ID和门户ID不能为空"); + } + List tenantIdList = List.of(tenantIds.split(",")); + userService.assignTenantsToUser(userId, tenantIdList); + return ResponseResult.success(); + } + + /*********************************** + * 用途说明:移除用户的门户关联 + * 参数说明 userId 用户ID, tenantId 门户ID + ************************************/ + @Log(module = "系统用户", value = "移除门户") + @PostMapping("/removeTenant") + @Operation(summary = "移除用户的门户关联") + @ResponseBody + public ResponseResult removeTenant(String userId, String tenantId) { + if (StrUtil.isBlank(userId) || StrUtil.isBlank(tenantId)) { + return ResponseResult.error("用户ID和门户ID不能为空"); + } + userService.removeTenantFromUser(userId, tenantId); + return ResponseResult.success(); + } + + /*********************************** + * 用途说明:获取用户关联的门户列表 + * 参数说明 userId 用户ID + ************************************/ + @GetMapping("/getUserTenants") + @Operation(summary = "获取用户关联的门户列表") + @ResponseBody + public ResponseResult getUserTenants(String userId) { + if (StrUtil.isBlank(userId)) { + return ResponseResult.error("用户ID不能为空"); + } + List tenants = userService.getUserTenants(userId); + return ResponseResult.successData(tenants); + } } diff --git a/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java b/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java index baf4258a..95c37a01 100644 --- a/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java +++ b/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java @@ -22,19 +22,44 @@ public class LoginUser implements UserDetails { private String username; - private List permissions=new ArrayList<>(); + private List permissions = new ArrayList<>(); + + /** + * 当前登录的门户ID + */ + private String currentTenantId; + + /** + * 用户可访问的门户ID列表(用于门户切换) + */ + private List accessibleTenantIds; + + /** + * 是否超级管理员(LEVEL=1) + */ + private boolean superAdmin; /** * 自定义构造函数(如果需要特殊逻辑) */ public LoginUser(SysUser user, List permissions) { this.user = user; - // 4. 增加非空判断,确保 permissions 永远不为 null if (permissions != null) { this.permissions = permissions; } } + public LoginUser(SysUser user, List permissions, + String currentTenantId, List accessibleTenantIds, boolean superAdmin) { + this.user = user; + if (permissions != null) { + this.permissions = permissions; + } + this.currentTenantId = currentTenantId; + this.accessibleTenantIds = accessibleTenantIds; + this.superAdmin = superAdmin; + } + @JSONField(serialize = false) private List authorities; diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysUserTenant.java b/backend/src/main/java/com/yfd/platform/system/domain/SysUserTenant.java new file mode 100644 index 00000000..6ac24062 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/SysUserTenant.java @@ -0,0 +1,39 @@ +package com.yfd.platform.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * 用户-门户关联表 + *

+ */ +@Data +@TableName("SYS_USER_TENANT") +public class SysUserTenant implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 主键 */ + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + /** 用户ID */ + private String userId; + + /** 门户ID */ + private String tenantId; + + @TableField("OPERATOR") + private String operator; + + @TableField("OPERATE_TIME") + private Date operateTime; + +} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java index 9ea863fa..ab657e45 100644 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java @@ -44,7 +44,7 @@ public interface SysMenuMapper extends BaseMapper { @Param("tenantId") String tenantId); - List selectPermsByUserId(String userId); + List selectPermsByUserId(@Param("userId") String userId, @Param("tenantId") String tenantId); //List selectMenuByUserId(String userId); List selectMenuByUserId(@Param("userId") String userId, @Param("tenantId") String tenantId); diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java index e9ac1f55..a9a45137 100644 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java @@ -29,7 +29,7 @@ public interface SysUserMapper extends BaseMapper { * userid 用户id * 返回值说明: ************************************/ - boolean addUserRoles(@Param("id")String id,@Param("roleid") String roleid,@Param("userid") String userid); + boolean addUserRoles(@Param("operator") String operator,@Param("id")String id,@Param("roleid") String roleid,@Param("userid") String userid); /*********************************** * 用途说明:根据用户id 和角色id 查询 系统角色用户对照表 diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserTenantMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserTenantMapper.java new file mode 100644 index 00000000..51365611 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserTenantMapper.java @@ -0,0 +1,47 @@ +package com.yfd.platform.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.system.domain.SysUserTenant; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 用户-门户关联表 Mapper 接口 + *

+ */ +@Mapper +public interface SysUserTenantMapper extends BaseMapper { + + /** + * 查询用户可访问的门户ID列表 + */ + List getTenantIdsByUserId(@Param("userId") String userId); + + /** + * 批量删除用户-门户关联 + */ + int deleteByUserId(@Param("userId") String userId); + + /** + * 批量新增用户-门户关联 + */ + int batchInsert(@Param("operator") String operator,@Param("userId") String userId, @Param("tenantIds") List tenantIds); + + /** + * 查询某门户下的所有用户ID + */ + List getUserIdsByTenantId(@Param("tenantId") String tenantId); + + /** + * 删除指定用户和指定门户的关联 + */ + int deleteByUserIdAndTenantId(@Param("userId") String userId, @Param("tenantId") String tenantId); + + /** + * 批量查询用户-门户关联(用于用户列表展示) + */ + List> getTenantIdsByUserIds(@Param("userIds") List userIds); +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java index 3dad368d..d9d73db2 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java +++ b/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java @@ -97,5 +97,14 @@ public interface ISysMenuService extends IService { ***********************************/ List> permissionAssignment(String code, String roleId, String tenantId); + /*********************************** + * 用途说明:权限分配(按系统分组,附带系统标识和名称) + * 参数说明 + * roleId 角色ID + * tenantId 门户ID + * 返回值说明: [{"systemCode":"1","systemName":"Web端","menus":[...]}, ...] + ***********************************/ + List> permissionAssignmentGrouped(String roleId, String tenantId); + String uploadIcon(MultipartFile icon) throws FileNotFoundException; } diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java index 244983bf..1b6f25e1 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java +++ b/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java @@ -67,4 +67,13 @@ public interface ISysRoleService extends IService { List selectRoleList(String rolename, String tenantId); List queryRolesList(String roleName, String tenantId); + + /*********************************** + * 用途说明:按门户分组查询角色(门户 → 角色两层结构) + * 参数说明 + * rolename 角色名称(可选,模糊搜索) + * 返回值说明: [{"tenantId":"...","tenantName":"水利门户","roles":[...]}, ...] + * 门户中文名通过字典 PLATFORM_TENANT 获取 + ***********************************/ + List> selectRoleListGroupedByTenant(String tenantId,String rolename); } diff --git a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java b/backend/src/main/java/com/yfd/platform/system/service/IUserService.java index 863fa04c..a3c10ff2 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java +++ b/backend/src/main/java/com/yfd/platform/system/service/IUserService.java @@ -33,7 +33,7 @@ public interface IUserService extends IService { ************************************/ Map getNameInfo(); //获取当前用户信息带权限 - ResponseResult getLoginUserInfo(); + Map getLoginUserInfo(); /*********************************** * 用途说明:新增用户 @@ -184,4 +184,23 @@ public interface IUserService extends IService { Page queryPendingAuditUsers(Page page, String name, String regStatus, String tenantId); List queryUsersList(String name, String tenantId); + + // ==================== 多门户管理 ==================== + + /** + * 为用户分配门户 + */ + void assignTenantsToUser(String userId, List tenantIds); + + /** + * 移除用户的某个门户关联 + */ + void removeTenantFromUser(String userId, String tenantId); + + /** + * 获取用户关联的门户ID列表 + */ + List getUserTenants(String userId); + + boolean isSuperAdmin(String userId); } diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java index 046de510..4f75a0aa 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java @@ -38,17 +38,17 @@ public class AdminAuthServiceImpl implements IAdminAuthService { public List getSuperAdminUsernames() { // 获取当前请求 - ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); +// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SysUser::getUsertype, 0).select(SysUser::getUsername); //根据用户名称或手机号查询用户信息 - if (attributes != null) { - HttpServletRequest request = attributes.getRequest(); - String tenantId = request.getHeader("Tenant_Id"); - if(StrUtil.isNotBlank(tenantId)){ - queryWrapper.eq(SysUser::getTenantId, tenantId); - } - } +// if (attributes != null) { +// HttpServletRequest request = attributes.getRequest(); +// String tenantId = request.getHeader("Tenant_Id"); +// if(StrUtil.isNotBlank(tenantId)){ +// queryWrapper.eq(SysUser::getTenantId, tenantId); +// } +// } List userList = userMapper.selectList(queryWrapper); if (CollUtil.isEmpty(userList)) { return new ArrayList<>(); @@ -74,6 +74,8 @@ public class AdminAuthServiceImpl implements IAdminAuthService { @Override public boolean isCurrentManagedAdmin() { - return isManagedAdminUsername(SecurityUtils.getCurrentUsername()); + String maxLevel = userMapper.getMaxLevel(SecurityUtils.getUserId()); + boolean adminRole = "1".equals(maxLevel); + return adminRole||isManagedAdminUsername(SecurityUtils.getCurrentUsername()); } } diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java index 4331f80a..390ada64 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SmsVerifyCodeServiceImpl.java @@ -48,7 +48,7 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SmsVerifyCode::getPhone, phone) .eq(SmsVerifyCode::getType, type) - .gt(SmsVerifyCode::getTenantId, tenantId) + .eq(SmsVerifyCode::getTenantId, tenantId) .eq(SmsVerifyCode::getStatus, SmsVerifyCode.STATUS_UNUSED); this.remove(queryWrapper); @@ -161,7 +161,7 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl ids = userIds.stream().distinct().toList(); List sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper().in(SysUser::getId, ids) - .eq(SysUser::getRegStatus, "APPROVED").eq(SysUser::getTenantId, tenantId).eq(SysUser::getStatus,1).select(SysUser::getPhone)); + .eq(SysUser::getRegStatus, "APPROVED").eq(SysUser::getStatus,1).select(SysUser::getPhone)); if (sysUsers.isEmpty()) { log.warn("催促短信发送失败:未找到有效的手机号,userIds: {}", ids); diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java index b3531c9e..32c2229b 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java @@ -7,10 +7,14 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yfd.platform.system.domain.SysDictionary; +import com.yfd.platform.system.domain.SysDictionaryItems; import com.yfd.platform.system.domain.SysMenu; import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.mapper.SysMenuMapper; import com.yfd.platform.system.mapper.SysRoleMapper; +import com.yfd.platform.system.service.ISysDictionaryItemsService; +import com.yfd.platform.system.service.ISysDictionaryService; import com.yfd.platform.system.service.ISysMenuService; import com.yfd.platform.utils.FileUtil; import com.yfd.platform.config.FileSpaceProperties; @@ -47,6 +51,12 @@ public class SysMenuServiceImpl extends ServiceImpl impl @Resource private UserServiceImpl currentUser; + @Resource + private ISysDictionaryService sysDictionaryService; + + @Resource + private ISysDictionaryItemsService sysDictionaryItemsService; + @Resource private SysRoleMapper sysRoleMapper; @@ -443,6 +453,9 @@ public class SysMenuServiceImpl extends ServiceImpl impl } else { sysMenuList = sysMenuMapper.selectMenuByUserId(id, tenantId); } + if (sysMenuList==null||sysMenuList.isEmpty()) { + throw new RuntimeException("无菜单"); + } // 将 SysMenu 转换为 Map 并构建树 List> list = sysMenuList.stream() .map(menu -> { @@ -502,6 +515,77 @@ public class SysMenuServiceImpl extends ServiceImpl impl return listTree; } + /*********************************** + * 用途说明:权限分配(按系统分组,附带系统标识和名称) + * 参数说明 + * roleId 角色ID + * tenantId 门户ID + * 返回值说明: [{"systemCode":"1","systemName":"Web端","menus":[...]}, ...] + ***********************************/ + @Override + public List> permissionAssignmentGrouped(String roleId, String tenantId) { + // 1. 查询 PLATFORM_TENANT 字典项,构建 systemCode → systemName 映射 + Map systemNameMap = new HashMap<>(); + SysDictionary tenantDict = sysDictionaryService.getByDictCode("PLATFORM_TENANT"); + if (tenantDict != null) { + List items = sysDictionaryItemsService.listByDictId(tenantDict.getId()); + if (items != null) { + for (SysDictionaryItems item : items) { + if (StrUtil.isNotBlank(item.getItemCode())) { + systemNameMap.put(item.getItemCode(), item.getDictName()); + } + } + } + } + + // 2. 查询所有菜单(不按 systemcode 过滤,按租户过滤) + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.select(SysMenu::getId, SysMenu::getParentid, SysMenu::getName, + SysMenu::getSystemcode, SysMenu::getOrderno) + .eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, tenantId) + .orderByAsc(SysMenu::getSystemcode, SysMenu::getOrderno); + List> mapList = sysMenuMapper.selectMaps(queryWrapper); + List> listAll = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList); + + // 3. 获取角色已有的菜单ID列表 + List listRole = sysMenuMapper.selectMenuByRoleId(roleId, tenantId); + + // 4. 标记 checkinfo + for (Map map : listAll) { + String id = (String) map.get("id"); + map.put("checkinfo", listRole != null && listRole.contains(id)); + } + + // 5. 按 systemcode 分组 + Map>> groupedBySystem = new LinkedHashMap<>(); + for (Map menu : listAll) { + String sysCode = (String) menu.get("systemcode"); + if (StrUtil.isBlank(sysCode)) { + sysCode = "1"; // 默认归属到 web 系统 + } + groupedBySystem.computeIfAbsent(sysCode, k -> new ArrayList<>()).add(menu); + } + + // 6. 按系统分组构建树,并附加 systemCode 和 systemName + List> result = new ArrayList<>(); + for (Map.Entry>> entry : groupedBySystem.entrySet()) { + String sysCode = entry.getKey(); + List> sysMenuList = entry.getValue(); + + // 构建菜单树 + List> menuTree = buildTrees(sysMenuList); + + // 组装结果 + Map systemGroup = new HashMap<>(); + systemGroup.put("systemCode", sysCode); + systemGroup.put("systemName", systemNameMap.getOrDefault(sysCode, sysCode)); + systemGroup.put("menus", menuTree); + result.add(systemGroup); + } + + return result; + } + // 另一种方法 /*public List> permissionAssignment(String roleId) { diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java index dcf3e8b6..c45d7c1a 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java @@ -66,7 +66,8 @@ public class SysOrganizationServiceImpl extends ServiceImpl allowedOrgIds = new HashSet<>(); - if (userInfo.getUsertype() != 0) { + boolean superAdmin = userService.isSuperAdmin(userInfo.getId()); + if (userInfo.getUsertype() != 0 && !superAdmin) { List roleByUserId = sysRoleMapper.getRoleByUserId(userInfo.getId()); for (SysRole sysRole : roleByUserId) { String orgscope = sysRole.getOrgscope(); @@ -81,8 +82,7 @@ public class SysOrganizationServiceImpl extends ServiceImpl list = sysOrganizationMapper.selectList( new LambdaQueryWrapper() - .in(SysOrganization::getId, stringList) - .eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId)); + .in(SysOrganization::getId, stringList)); for (SysOrganization org : list) { if (org.getParentid() != null) { allowedOrgIds.add(org.getParentid()); @@ -97,9 +97,9 @@ public class SysOrganizationServiceImpl extends ServiceImpl allowedOrgIds = new HashSet<>(); - if (userInfo.getUsertype() != 0) { + boolean superAdmin = userService.isSuperAdmin(userInfo.getId()); + if (userInfo.getUsertype() != 0 && !superAdmin) { List roleByUserId = sysRoleMapper.getRoleByUserId(userInfo.getId()); for (SysRole sysRole : roleByUserId) { String orgscope = sysRole.getOrgscope(); @@ -274,7 +275,7 @@ public class SysOrganizationServiceImpl extends ServiceImpl queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SysOrganization::getParentid, id); - queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId); if (StrUtil.isNotBlank(orgName)) { queryWrapper.like(SysOrganization::getOrgname, orgName); diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java index 97908d08..5135292e 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java @@ -6,8 +6,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.system.domain.SysDictionary; +import com.yfd.platform.system.domain.SysDictionaryItems; import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.mapper.SysRoleMapper; +import com.yfd.platform.system.service.ISysDictionaryItemsService; +import com.yfd.platform.system.service.ISysDictionaryService; import com.yfd.platform.system.service.ISysRoleService; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -16,8 +20,7 @@ import org.springframework.transaction.annotation.Transactional; import jakarta.annotation.Resource; import java.sql.Timestamp; import java.text.DecimalFormat; -import java.util.List; -import java.util.Map; +import java.util.*; /** *

@@ -37,6 +40,12 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Resource private UserServiceImpl currentuser; + @Resource + private ISysDictionaryService sysDictionaryService; + + @Resource + private ISysDictionaryItemsService sysDictionaryItemsService; + /*********************************** * 用途说明:新增角色 * 参数说明 @@ -185,4 +194,57 @@ public class SysRoleServiceImpl extends ServiceImpl impl return sysRoleList; } + /*********************************** + * 用途说明:按门户分组查询角色(门户 → 角色两层结构) + * 参数说明 + * rolename 角色名称(可选,模糊搜索) + * 返回值说明: [{"tenantId":"...","tenantName":"水利门户","roles":[...]}, ...] + * 门户中文名通过字典 PLATFORM_TENANT 获取 + ***********************************/ + @Override + public List> selectRoleListGroupedByTenant(String tenantId,String rolename) { + // 1. 查询所有角色(排除超级管理员级别,支持角色名称模糊搜索) + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, tenantId); + queryWrapper.like(StrUtil.isNotBlank(rolename), SysRole::getRolename, rolename); +// queryWrapper.ne(SysRole::getLevel, "1"); + queryWrapper.orderByAsc(SysRole::getTenantId).orderByAsc(SysRole::getLevel); + List roleList = this.list(queryWrapper); + + // 2. 查询 PLATFORM_TENANT 字典项,构建 tenantId → tenantName 映射 + Map tenantNameMap = new HashMap<>(); + SysDictionary tenantDict = sysDictionaryService.getByDictCode("PLATFORM_TENANT"); + if (tenantDict != null) { + List items = sysDictionaryItemsService.list(new LambdaQueryWrapper().eq(SysDictionaryItems::getDictId, tenantDict.getId()).eq(StrUtil.isNotBlank(tenantId),SysDictionaryItems::getItemCode, tenantId).select(SysDictionaryItems::getItemCode, SysDictionaryItems::getDictName)); + if (items != null) { + for (SysDictionaryItems item : items) { + if (StrUtil.isNotBlank(item.getItemCode())) { + tenantNameMap.put(item.getItemCode(), item.getDictName()); + } + } + } + } + + // 3. 按 tenantId 分组(跳过无门户的角色) + Map> grouped = new LinkedHashMap<>(); + for (SysRole role : roleList) { + String code = role.getTenantId(); + if (StrUtil.isBlank(code)) { + continue; + } + grouped.computeIfAbsent(code, k -> new ArrayList<>()).add(role); + } + + // 4. 组装两层结构:门户 → 角色 + List> result = new ArrayList<>(); + for (Map.Entry> entry : grouped.entrySet()) { + Map group = new HashMap<>(); + group.put("tenantId", entry.getKey()); + group.put("tenantName", tenantNameMap.getOrDefault(entry.getKey(), entry.getKey())); + group.put("roles", entry.getValue()); + result.add(group); + } + return result; + } + } diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java index b860f0bd..45735c42 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java @@ -3,12 +3,13 @@ package com.yfd.platform.system.service.impl; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.yfd.platform.datasource.DataSource; -import com.yfd.platform.datasource.DataSourceKeys; import com.yfd.platform.datasource.TargetDataSource; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.mapper.SysMenuMapper; +import com.yfd.platform.system.mapper.SysUserMapper; +import com.yfd.platform.system.mapper.SysUserTenantMapper; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.system.service.IUserService; import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.core.userdetails.UserDetails; @@ -20,11 +21,14 @@ import jakarta.annotation.Resource; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import java.util.ArrayList; import java.util.List; /** *

* 用户服务实现类 继承UserDetailsService 实现接口 + * 支持多门户登录:用户可关联多个门户,登录时选择其中一个门户 + * 超级管理员(LEVEL=1)拥有跨所有门户的权限 *

* * @author zhengsl @@ -35,35 +39,74 @@ public class UserDetailsServiceImpl implements UserDetailsService { @Resource private IUserService userService; + @Resource + private IAdminAuthService adminAuthService; @Resource private SysMenuMapper sysMenuMapper; + @Resource + private SysUserTenantMapper sysUserTenantMapper; + + @Resource + private SysUserMapper sysUserMapper; + @Override @TargetDataSource() public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 获取当前请求 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - //根据用户名称或手机号查询用户信息 + + // 根据用户名称或手机号查询用户信息(不加tenantId过滤,支持跨门户登录) QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.and(wrapper -> wrapper.eq("username", username).or().eq("phone", username)); - if (attributes != null) { - HttpServletRequest request = attributes.getRequest(); - String tenantId = request.getHeader("Tenant_Id"); - if(StrUtil.isNotBlank(tenantId)){ - queryWrapper.eq("TENANT_ID", tenantId); - } - } SysUser user = userService.getOne(queryWrapper); if (ObjectUtil.isEmpty(user)) { throw new RuntimeException("用户账号不存在!"); } - //Todo 根据用户查询权限信息 添加到LoginUser中 - List permissions = - sysMenuMapper.selectPermsByUserId(user.getId()); - //封装成UserDetails对象返回 - return new LoginUser(user,permissions); + // 获取请求中的门户ID + String tenantId = null; + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + tenantId = request.getHeader("Tenant_Id"); + } + + // 判断是否为超级管理员(LEVEL=1) + boolean isSuperAdmin = (isSuperAdmin(user.getId())||user.getUsertype()==0); + + // 查询用户可访问的门户列表 + List accessibleTenantIds = sysUserTenantMapper.getTenantIdsByUserId(user.getId()); + + // 非超级管理员必须指定门户,且必须在可访问列表中 + if (!isSuperAdmin) { + if (StrUtil.isBlank(tenantId)) { + throw new RuntimeException("用户无权限访问该平台"); + } + if (accessibleTenantIds == null || !accessibleTenantIds.contains(tenantId)) { + throw new RuntimeException("用户无权限访问该平台"); + } + } + + // 加载权限:超级管理员加载全部权限,普通用户按门户过滤 + List permissions; + if (isSuperAdmin) { + permissions = sysMenuMapper.selectPermsByUserId(user.getId(), null); + } else { + permissions = sysMenuMapper.selectPermsByUserId(user.getId(), tenantId); + } + + // 封装成UserDetails对象返回,包含当前门户和可访问门户列表 + return new LoginUser(user, permissions, tenantId, accessibleTenantIds, isSuperAdmin); + } + + /** + * 判断用户是否为超级管理员(拥有LEVEL=1的角色) + */ + private boolean isSuperAdmin(String userId) { + String maxLevel = sysUserMapper.getMaxLevel(userId); + return "1".equals(maxLevel); } } + diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index a50a6d83..96172af7 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -20,8 +20,10 @@ import com.yfd.platform.qgc_base.mapper.SdRvcdDicMapper; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysUser; +import com.yfd.platform.system.domain.SysUserTenant; import com.yfd.platform.system.mapper.SysRoleMapper; import com.yfd.platform.system.mapper.SysUserMapper; +import com.yfd.platform.system.mapper.SysUserTenantMapper; import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.FileUtil; @@ -81,6 +83,9 @@ public class UserServiceImpl extends ServiceImpl impleme @Resource private SysUserDataScopeMapper sysUserDataScopeMapper; + @Resource + private SysUserTenantMapper sysUserTenantMapper; + @Resource private IAdminAuthService adminAuthService; @@ -122,7 +127,7 @@ public class UserServiceImpl extends ServiceImpl impleme } @Override - public ResponseResult getLoginUserInfo() { + public Map getLoginUserInfo() { UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); LoginUser loginuser = (LoginUser) authentication.getPrincipal(); @@ -138,7 +143,8 @@ public class UserServiceImpl extends ServiceImpl impleme if(user.getUsertype()==0){ collect.add("超级管理员"); } - ResponseResult responseResult = new ResponseResult(); + // 新写法(推荐) + Map responseResult = new HashMap<>(); responseResult.put("userInfo", userInfo); responseResult.put("roles", collect); responseResult.put("permissions", loginuser.getPermissions()); @@ -169,7 +175,7 @@ public class UserServiceImpl extends ServiceImpl impleme //账号有效 sysUser.setStatus(1); //判断注册的登录账号是否存在 - if (isExistAccount(sysUser.getUsername(),sysUser.getTenantId() )) { + if (isExistAccount(sysUser.getUsername())) { //新增用户 boolean ok = this.save(sysUser); //新增用户分配权限 @@ -179,12 +185,24 @@ public class UserServiceImpl extends ServiceImpl impleme //系统生成id String id = IdUtil.fastSimpleUUID(); //新增sys_role_users表数据 - ok = ok && sysUserMapper.addUserRoles(id, roleid, - sysUser.getId()); + ok = ok && sysUserMapper.addUserRoles(SecurityUtils.getUserId(),id, roleid, sysUser.getId()); } } //判断新增是否成功 消息提示 if (ok) { + // 插入用户-门户关联 + List ids = StrUtil.split(roleids, ","); + if(!ids.isEmpty()) { + List selectedList = sysRoleMapper.selectList(new LambdaQueryWrapper().in(SysRole::getId, ids).select(SysRole::getTenantId)); + List tenantIds = selectedList.stream().map(SysRole::getTenantId).distinct().toList(); + sysUserTenantMapper.batchInsert(SecurityUtils.getUserId(), sysUser.getId(), tenantIds); + } +// String tenantId = sysUser.getTenantId(); +// if (StrUtil.isNotBlank(tenantId)) { +// List tenantIds = new ArrayList<>(); +// tenantIds.add(tenantId); +// sysUserTenantMapper.batchInsert(SecurityUtils.getUserId(),sysUser.getId(), tenantIds); +// } result.put("status", "sucess"); result.put("msg", "新增用户成功!"); @@ -270,6 +288,14 @@ public class UserServiceImpl extends ServiceImpl impleme return result; } + // 根据角色给用户分配门户 + sysUserTenantMapper.deleteByUserId(sysUser.getId()); + if(StrUtil.isNotBlank(roleids)) { + List ids = StrUtil.split(roleids, ","); + List selectedList = sysRoleMapper.selectList(new LambdaQueryWrapper().in(SysRole::getId, ids).select(SysRole::getTenantId)); + List tenantIds = selectedList.stream().map(SysRole::getTenantId).distinct().toList(); + sysUserTenantMapper.batchInsert(SecurityUtils.getUserId(), sysUser.getId(), tenantIds); + } // 处理角色分配 String userId = sysUser.getId(); if (StrUtil.isNotEmpty(roleids)) { @@ -345,12 +371,21 @@ public class UserServiceImpl extends ServiceImpl impleme // 解析新角色列表 String[] newRoles = roleIds.split(","); - + String operator; + try { + operator = SecurityUtils.getUserId(); + } catch (Exception e) { + // 记录日志,方便排查 + log.error("获取当前用户ID失败", e); + // 根据业务需求处理:可返回默认值、抛出业务异常或置空 + operator = null; // 或 "anonymous" 等默认值 + } // 需要新增的角色(新角色 - 当前角色) for (String roleId : newRoles) { if (!currentRoleSet.contains(roleId)) { String id = IdUtil.fastSimpleUUID(); - sysUserMapper.addUserRoles(id, roleId, userId); + + sysUserMapper.addUserRoles(operator,id, roleId, userId); } } @@ -407,7 +442,7 @@ public class UserServiceImpl extends ServiceImpl impleme //系统生成id String id = IdUtil.fastSimpleUUID(); //新增sys_role_users表数据 - isOk = isOk && sysUserMapper.addUserRoles(id, roleid, userid); + isOk = isOk && sysUserMapper.addUserRoles(SecurityUtils.getUserId(),id, roleid, userid); } } return isOk; @@ -434,6 +469,8 @@ public class UserServiceImpl extends ServiceImpl impleme if (isOk) { //根据用户id 删除该用户角色关联 sysUserMapper.delRoleUsersByUserid(id); + // 删除用户-门户关联 + sysUserTenantMapper.deleteByUserId(id); //判断是否存在 账号头像 存在删除 if (StrUtil.isNotEmpty(sysUser.getAvatar())) { FileUtil.del(imgName); @@ -580,7 +617,7 @@ public class UserServiceImpl extends ServiceImpl impleme //系统生成id String id = IdUtil.fastSimpleUUID(); //新增sys_role_users表数据 - isOk = sysUserMapper.addUserRoles(id, roleid, userid); + isOk = sysUserMapper.addUserRoles(SecurityUtils.getUserId(),id, roleid, userid); } return isOk; } @@ -636,6 +673,10 @@ public class UserServiceImpl extends ServiceImpl impleme } // 根据ID删除用户与角色的关联信息 sysUserMapper.delRoleUsersByUserIds(ids); + // 删除用户-门户关联 + for (String userId : ids) { + sysUserTenantMapper.deleteByUserId(userId); + } List avatars = sysUsers.stream().map(SysUser::getAvatar).collect(Collectors.toList()); if (avatars.size() > 0) { @@ -654,7 +695,7 @@ public class UserServiceImpl extends ServiceImpl impleme public SysUser getUserByPhone(String phone,String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SysUser::getPhone, phone); - queryWrapper.eq(SysUser::getTenantId, tenantId); +// queryWrapper.eq(SysUser::getTenantId, tenantId); return this.getOne(queryWrapper); } @@ -893,15 +934,14 @@ public class UserServiceImpl extends ServiceImpl impleme } /*********************************** - * 用途说明:比较登录名称是否有重复 + * 用途说明:比较登录名称是否有重复(全局唯一,不区分门户) * 参数说明 * account 登录名称 * 返回值说明: 重复返回 false 否则返回 true ************************************/ - private boolean isExistAccount(String username,String tenantId) { + private boolean isExistAccount(String username) { QueryWrapper queryWrapper = new QueryWrapper<>(); - if (this.list(queryWrapper.eq("username", username).eq("TENANT_ID", tenantId)).size() > 0) { - //判断 查询登录账号 结果集是否为null 重复返回 false 否则返回 tree + if (this.list(queryWrapper.eq("username", username)).size() > 0) { return false; } else { return true; @@ -912,7 +952,7 @@ public class UserServiceImpl extends ServiceImpl impleme @Override public List queryUsersList(String name, String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, tenantId); +// queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, tenantId); queryWrapper.eq(SysUser::getStatus, 1); queryWrapper.and(StrUtil.isNotBlank(name), wrapper -> wrapper.like(SysUser::getNickname, name) @@ -923,4 +963,49 @@ public class UserServiceImpl extends ServiceImpl impleme List sysUserList = this.list( queryWrapper); return sysUserList; } + + // ==================== 多门户管理 ==================== + + /** + * 为用户分配门户 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void assignTenantsToUser(String userId, List tenantIds) { + if (StrUtil.isBlank(userId) || tenantIds == null || tenantIds.isEmpty()) { + throw new RuntimeException("用户ID和门户ID列表不能为空"); + } + sysUserTenantMapper.batchInsert(SecurityUtils.getUserId(),userId, tenantIds); + } + + /** + * 移除用户的某个门户关联 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void removeTenantFromUser(String userId, String tenantId) { + if (StrUtil.isBlank(userId) || StrUtil.isBlank(tenantId)) { + throw new RuntimeException("用户ID和门户ID不能为空"); + } + sysUserTenantMapper.deleteByUserIdAndTenantId(userId, tenantId); + } + + /** + * 获取用户关联的门户ID列表 + */ + @Override + public List getUserTenants(String userId) { + if (StrUtil.isBlank(userId)) { + return new ArrayList<>(); + } + return sysUserTenantMapper.getTenantIdsByUserId(userId); + } + + + public boolean isSuperAdmin(String userId) { + String maxLevel = sysUserMapper.getMaxLevel(userId); + SysUser sysUser = sysUserMapper.selectById(userId); + return (sysUser!=null && sysUser.getUsertype()==0) || "1".equals(maxLevel); + } + } diff --git a/backend/src/main/java/com/yfd/platform/utils/DataSourceRequestUtil.java b/backend/src/main/java/com/yfd/platform/utils/DataSourceRequestUtil.java index 25b78886..1de686a1 100644 --- a/backend/src/main/java/com/yfd/platform/utils/DataSourceRequestUtil.java +++ b/backend/src/main/java/com/yfd/platform/utils/DataSourceRequestUtil.java @@ -92,6 +92,8 @@ public class DataSourceRequestUtil { List excludes = excludeFields != null ? excludeFields : new ArrayList<>(); + applySelect(request, wrapper, entityClass, fieldMapping, excludes); + applyFilters(request.getFilter(), wrapper, entityClass, fieldMapping, excludes, "and"); applySort(request.getSort(), wrapper, entityClass); @@ -145,6 +147,49 @@ public class DataSourceRequestUtil { return service.list(wrapper); } + /** + * 应用查询字段(select / distinctSelect) + * distinctSelect 优先于 select,并附带 DISTINCT 去重 + */ + private static void applySelect(DataSourceRequest request, + QueryWrapper wrapper, + Class entityClass, + Map fieldMapping, + List excludeFields) { + List selectFields = request.getSelect(); + boolean distinct = false; + if (CollectionUtil.isNotEmpty(request.getDistinctSelect())) { + selectFields = request.getDistinctSelect(); + distinct = true; + } + + if (CollectionUtil.isEmpty(selectFields)) { + return; + } + + List columns = new ArrayList<>(); + for (String field : selectFields) { + if (StrUtil.isBlank(field) || excludeFields.contains(field)) { + continue; + } + String columnName = getColumnName(field, entityClass, fieldMapping); + if (columnName != null) { + columns.add(columnName); + } + } + + if (columns.isEmpty()) { + return; + } + + String[] columnArray = columns.toArray(new String[0]); + if (distinct) { + // MyBatis-Plus 3.5.16 无 wrapper.distinct() 方法,在首个查询列前加 DISTINCT 关键字实现去重 + columnArray[0] = "DISTINCT " + columnArray[0]; + } + wrapper.select(columnArray); + } + private static void applyFilters(DataSourceRequest.FilterDescriptor filter, QueryWrapper wrapper, Class entityClass, diff --git a/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java b/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java index 8d667c15..8c90a931 100644 --- a/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java +++ b/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java @@ -19,6 +19,7 @@ import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.yfd.platform.exception.BadRequestException; +import com.yfd.platform.system.domain.LoginUser; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; @@ -105,4 +106,40 @@ public class SecurityUtils { .anyMatch(auth -> permission.equals(auth.getAuthority())); } + /** + * 获取当前登录用户的门户ID + * @return 门户ID,超级管理员可能返回null + */ + public static String getCurrentTenantId() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) { + return null; + } + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + return loginUser.getCurrentTenantId(); + } + + /** + * 判断当前用户是否为超级管理员 + */ + public static boolean isSuperAdmin() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) { + return false; + } + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + return loginUser.isSuperAdmin(); + } + + /** + * 获取当前用户可访问的门户ID列表 + */ + public static List getAccessibleTenantIds() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) { + return null; + } + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + return loginUser.getAccessibleTenantIds(); + } } diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index a87887d5..98127603 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -197,7 +197,7 @@ logging: level: root: info com.yfd.platform: info - com.yfd.platform.common.MicroservicDynamicSQLMapper: debug + com.yfd.platform.common.MicroservicDynamicSQLMapper: info # ... existing code ... # com.yfd.platform.*.mapper: trace diff --git a/backend/src/main/resources/mapper/system/SysMenuMapper.xml b/backend/src/main/resources/mapper/system/SysMenuMapper.xml index a65f0c7f..797c7314 100644 --- a/backend/src/main/resources/mapper/system/SysMenuMapper.xml +++ b/backend/src/main/resources/mapper/system/SysMenuMapper.xml @@ -27,7 +27,7 @@ SELECT r.id, r.rolecode, r.rolename, r."LEVEL", r.description, r.orgscope, r.optscope, r.busscope, r.isvaild, @@ -136,7 +136,6 @@ AND r.tenant_id = #{tenantId} - AND r."LEVEL" != '1' ORDER BY r."LEVEL" ASC, lastmodifydate ASC diff --git a/backend/src/main/resources/mapper/system/SysUserMapper.xml b/backend/src/main/resources/mapper/system/SysUserMapper.xml index 5600fd5d..8ba9cf6e 100644 --- a/backend/src/main/resources/mapper/system/SysUserMapper.xml +++ b/backend/src/main/resources/mapper/system/SysUserMapper.xml @@ -29,7 +29,7 @@ - insert into sys_role_users values (#{id},#{roleid},#{userid}) + insert into sys_role_users(operator,id,roleid,userid) values (#{operator},#{id},#{roleid},#{userid}) @@ -73,20 +73,22 @@ u.lastmodifydate FROM sys_user u + LEFT JOIN SYS_USER_TENANT ut ON u.id = ut.USER_ID WHERE 1 = 1 AND ( ( u.REG_STATUS != 'PENDING' AND u.REG_STATUS != 'REJECTED' ) OR u.REG_STATUS IS NULL ) - AND u.usertype != 0 +-- AND u.usertype != 0 + AND u.username != 'admin' and u.orgid = #{orgid} - and u.username LIKE '%' || #{username} || '%' + and (u.username LIKE '%' || #{username} || '%' OR u.nickname LIKE '%' || #{username} || '%' OR u.phone LIKE '%' || #{username} || '%') - and u.tenant_id = #{tenantId} + and (ut.TENANT_ID = #{tenantId} OR u.tenant_id = #{tenantId}) - ORDER BY u.lastmodifydate DESC + ORDER BY u.username + SELECT TENANT_ID + FROM SYS_USER_TENANT + WHERE USER_ID = #{userId} + + + + + DELETE FROM SYS_USER_TENANT WHERE USER_ID = #{userId} + + + + + MERGE INTO SYS_USER_TENANT T + USING ( + + SELECT + #{userId, jdbcType=VARCHAR} AS USER_ID, + #{operator} AS OPERATOR, + #{tenantId, jdbcType=VARCHAR} AS TENANT_ID + FROM DUAL + + ) S + ON (T.USER_ID = S.USER_ID AND T.TENANT_ID = S.TENANT_ID) + WHEN NOT MATCHED THEN + INSERT (ID, USER_ID, TENANT_ID, OPERATOR) + VALUES (SYS_GUID(), S.USER_ID, S.TENANT_ID, S.OPERATOR) + + + + + DELETE FROM SYS_USER_TENANT WHERE USER_ID = #{userId} AND TENANT_ID = #{tenantId} + + + + + + + + +