zhangying преди 1 седмица
родител
ревизия
ab18ec39d7
променени са 20 файла, в които са добавени 1250 реда и са изтрити 37 реда
  1. 12 0
      zjrs-service-backend/pom.xml
  2. 0 1
      zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/blo/impl/SxblBLOImpl.java
  3. 49 0
      zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/controller/CaptchaController.java
  4. 1 1
      zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/po/RsWbBjSub.java
  5. 164 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/controller/AuthController.java
  6. 370 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/controller/UserInfoController.java
  7. 32 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperator.java
  8. 21 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperatorMapper.java
  9. 37 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperatorMapper.xml
  10. 95 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/service/AuthRedisService.java
  11. 77 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/util/JwtUtil.java
  12. 253 7
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/blo/impl/DhyyBLOimpl.java
  13. 10 10
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/blo/impl/RcglBLOimpl.java
  14. 0 13
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/entity/VRsSyZskMapper.xml
  15. 59 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/po/VRsSyYydhInfoPO.java
  16. 10 4
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/rlzysc/entity/VRsRlzyZwxxMapper.java
  17. 1 1
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/rlzysc/entity/VRsRlzyZwxxMapper.xml
  18. 14 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/entity/FwRight2ResourceMapper.java
  19. 40 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/po/FwRight2ResourcePO.java
  20. 5 0
      zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/po/FwrightPO.java

+ 12 - 0
zjrs-service-backend/pom.xml

@@ -143,6 +143,13 @@
             <scope>system</scope>
             <systemPath>${project.basedir}/src/main/resources/lib/leaf6-uni-log-mybatis-2.0.0-SinoBest.21.jar</systemPath>
         </dependency>
+        <dependency>
+            <groupId>com.yinhai</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.60</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/src/main/resources/lib/bcprov-jdk15on-1.60.jar</systemPath>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.poi</groupId>
@@ -294,6 +301,11 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 0 - 1
zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/blo/impl/SxblBLOImpl.java

@@ -484,7 +484,6 @@ public class SxblBLOImpl extends BLOImpl implements SxblBLO {
 								wrapper.or();
 							}
 						}
-						return wrapper;
 					}
 			);
 		}

+ 49 - 0
zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/controller/CaptchaController.java

@@ -0,0 +1,49 @@
+package com.zjrs.ggfw.portal.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import jakarta.annotation.Resource;
+import com.zjrs.ggfw.portal.bpo.UserBPO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 验证码控制器
+ * 兼容前端默认请求路径 /api/captcha 和 /api/captcha/render
+ */
+@Api("验证码")
+@RestController
+@RequestMapping("/api/captcha")
+public class CaptchaController {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CaptchaController.class);
+
+    @Resource
+    private UserBPO userBPO;
+
+    /**
+     * 获取图片验证码 (兼容 /api/captcha/render)
+     */
+    @ApiOperation(value = "验证身份,获取图片验证码", notes = "验证身份,获取图片验证码")
+    @GetMapping("/render")
+    public void createKaptcha(HttpServletRequest request, HttpServletResponse response) {
+        LOG.info("CaptchaController render (path: /render)...");
+        userBPO.render();
+    }
+
+    /**
+     * 获取图片验证码 (兼容 /api/captcha)
+     */
+    @ApiOperation(value = "验证身份,获取图片验证码", notes = "验证身份,获取图片验证码")
+    @GetMapping
+    public void createKaptchaDefault(HttpServletRequest request, HttpServletResponse response) {
+        LOG.info("CaptchaController render (default path)...");
+        userBPO.render();
+    }
+}

+ 1 - 1
zjrs-service-backend/src/main/java/com/zjrs/ggfw/portal/po/RsWbBjSub.java

@@ -14,7 +14,7 @@ public class RsWbBjSub {
     private String rsWbBjSubLsh;
 
     @ApiModelProperty(value = "办件流水号")
-    @TableId(value = "RS_WB_BJ_LSH")
+    @TableField("RS_WB_BJ_LSH")
     private String rsWbBjLsh;
 
     @ApiModelProperty(value = "用户ID")

+ 164 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/controller/AuthController.java

@@ -0,0 +1,164 @@
+package com.zjrs.zwnw.auth.controller;
+
+import com.zjrs.zwnw.auth.entity.FwOperator;
+import com.zjrs.zwnw.auth.entity.FwOperatorMapper;
+import com.zjrs.zwnw.auth.service.AuthRedisService;
+import com.zjrs.zwnw.auth.util.JwtUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.util.DigestUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 认证控制器
+ * 提供登录(/api/auth/password/login)和登出(/api/auth/logout)接口,
+ * 对应原 leaf6-uni-cloud-auth 服务的核心功能。
+ */
+@RestController
+public class AuthController {
+
+    private static final Logger log = LoggerFactory.getLogger(AuthController.class);
+
+    @Autowired
+    private FwOperatorMapper fwOperatorMapper;
+
+    @Autowired
+    private JwtUtil jwtUtil;
+
+    @Autowired
+    private AuthRedisService authRedisService;
+
+    /**
+     * 用户名密码登录接口 (支持 Form-Encoded)
+     */
+    @PostMapping(value = "/api/auth/password/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    public Map<String, Object> loginForm(
+            @RequestParam("username") String username,
+            @RequestParam("password") String password,
+            @RequestParam(value = "captcha", required = false) String captcha,
+            @RequestParam(value = "reqid", required = false) String reqid,
+            HttpServletRequest request) {
+        return doLogin(username, password, captcha, request);
+    }
+
+    /**
+     * 用户名密码登录接口 (支持 JSON)
+     */
+    @PostMapping(value = "/api/auth/password/login", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Map<String, Object> loginJson(@RequestBody Map<String, String> body, HttpServletRequest request) {
+        String username = body.get("username");
+        String password = body.get("password");
+        String captcha = body.get("captcha");
+        return doLogin(username, password, captcha, request);
+    }
+
+    /**
+     * 核心登录逻辑
+     */
+    private Map<String, Object> doLogin(String username, String password, String captcha, HttpServletRequest request) {
+        log.info("[Auth] 用户 {} 发起登录请求", username);
+
+        if (username == null || username.isEmpty()) {
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.BAD_REQUEST, "用户名不能为空");
+        }
+
+        // 1. 查询用户
+        FwOperator operator = fwOperatorMapper.selectByLoginId(username);
+        if (operator == null) {
+            log.warn("[Auth] 登录失败:用户 {} 不存在", username);
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.UNAUTHORIZED, "用户名或密码错误");
+        }
+
+        // 2. 验证状态
+        if (!"1".equals(operator.getAae100())) {
+            log.warn("[Auth] 登录失败:用户 {} 已被禁用", username);
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.UNAUTHORIZED, "用户已被禁用");
+        }
+
+        // 3. 验证密码
+        if (!checkPassword(password, operator.getPassword(), operator.getPwencrypt())) {
+            log.warn("[Auth] 登录失败:用户 {} 密码错误", username);
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.UNAUTHORIZED, "用户名或密码错误");
+        }
+
+        // 4. 生成 JWT Token
+        String token = jwtUtil.generateToken(
+                operator.getLoginid(),
+                operator.getOpername(),
+                operator.getOperid(),
+                operator.getOperunitid());
+
+        // 5. 将用户信息存入 Redis
+        String userId = operator.getSguserid();
+        if (!StringUtils.hasText(userId)) {
+            userId = operator.getOperid();
+        }
+        Map<String, Object> userInfo = new HashMap<>();
+        userInfo.put("id", userId);
+        userInfo.put("loginId", operator.getLoginid());
+        userInfo.put("userName", operator.getOpername());
+        userInfo.put("operunitid", operator.getOperunitid());
+        userInfo.put("bae001", operator.getBae001());
+        userInfo.put("opertype", operator.getOpertype());
+        authRedisService.saveToken(token, userInfo, jwtUtil.getExpireSeconds());
+
+        // 6. 返回前端期望的格式
+        Map<String, Object> result = new HashMap<>();
+        Map<String, Object> mapData = new HashMap<>();
+        mapData.put("Access-Token", token);
+        mapData.put("msg", "登录成功");
+        result.put("map", mapData);
+
+        log.info("[Auth] 用户 {} 登录成功", username);
+        return result;
+    }
+
+    /**
+     * 登出接口:清除 Redis 中的 Token
+     * GET /api/auth/logout
+     */
+    @GetMapping("/api/auth/logout")
+    public Map<String, Object> logout(HttpServletRequest request) {
+        String token = request.getHeader("Access-Token");
+        if (token != null && !token.isEmpty()) {
+            authRedisService.deleteToken(token);
+        }
+        Map<String, Object> result = new HashMap<>();
+        result.put("code", "200");
+        result.put("msg", "退出成功");
+        return result;
+    }
+
+    /**
+     * 校验密码
+     *
+     * @param inputPwd  用户输入的明文密码
+     * @param dbPwd     数据库中存储的密码
+     * @param pwEncrypt 加密标志:'0'-明文,'1'-MD5
+     */
+    private boolean checkPassword(String inputPwd, String dbPwd, String pwEncrypt) {
+        if (dbPwd == null) {
+            return false;
+        }
+        if ("1".equals(pwEncrypt)) {
+            // MD5 验证
+            String md5Input = DigestUtils.md5DigestAsHex(inputPwd.getBytes(StandardCharsets.UTF_8));
+            return md5Input.equalsIgnoreCase(dbPwd);
+        } else {
+            // 明文比较(PWENCRYPT='0')
+            return inputPwd.equals(dbPwd);
+        }
+    }
+}

+ 370 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/controller/UserInfoController.java

@@ -0,0 +1,370 @@
+package com.zjrs.zwnw.auth.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.zjrs.zwnw.auth.entity.FwOperator;
+import com.zjrs.zwnw.auth.entity.FwOperatorMapper;
+import com.zjrs.zwnw.auth.service.AuthRedisService;
+import com.zjrs.zwnw.portal.entity.SSgMenuMapper;
+import com.zjrs.zwnw.portal.entity.VRsSyYydhInfoMapper;
+import com.zjrs.zwnw.portal.po.SSgMenuPO;
+import com.zjrs.zwnw.portal.po.VRsSyYydhInfoPO;
+import com.zjrs.zwnw.sxgl.entity.FwRight2ResourceMapper;
+import com.zjrs.zwnw.sxgl.entity.FwrightMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+/**
+ * 用户信息控制器
+ * <p>
+ * 对应原 leaf6-uni-cloud-uc-service 中的用户信息接口。
+ * 前端在登录获取 Token 后调用此接口获取用户基本信息(loginUserDTO)。
+ * 路径前缀为 /leaf6-uni-cloud-uc-service(与前端 vue.config.js 中的代理路径一致)。
+ */
+@RestController
+public class UserInfoController {
+
+    private static final Logger log = LoggerFactory.getLogger(UserInfoController.class);
+
+    @Autowired
+    private AuthRedisService authRedisService;
+
+    @Autowired
+    private VRsSyYydhInfoMapper vRsSyYydhInfoMapper;
+
+    @Autowired
+    private SSgMenuMapper sSgMenuMapper;
+
+    @Autowired
+    private FwrightMapper fwrightMapper;
+
+    @Autowired
+    private FwRight2ResourceMapper fwRight2ResourceMapper;
+
+    @Autowired
+    private FwOperatorMapper fwOperatorMapper;
+
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/users/{id}")
+    public Map<String, Object> getUserById(@PathVariable("id") String id) {
+        if (StringUtils.isEmpty(id)) {
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.BAD_REQUEST, "ID不能为空");
+        }
+
+        FwOperator operator = fwOperatorMapper.selectByOperId(id);
+        if (operator == null) {
+            // 如果不是操作员ID,尝试作为sguserid查询?或者直接返回404
+            // 鉴于用户请求示例是UUID,可能是operid
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.NOT_FOUND, "用户不存在");
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("id", operator.getOperid());
+        result.put("loginId", operator.getLoginid());
+        result.put("userName", operator.getOpername());
+        result.put("operunitid", operator.getOperunitid());
+        result.put("bae001", operator.getBae001());
+        result.put("opertype", operator.getOpertype());
+        
+        return result;
+    }
+
+    /**
+     * 获取当前登录用户信息
+     * <p>
+     * 请求方式:GET /leaf6-uni-cloud-uc-service/api/security/users/current/loginResponse
+     * Header:Access-Token: eyJ...
+     * <p>
+     * 成功响应:{ "loginUserDTO": { "id": "...", "loginId": "...", "userName": "..." } }
+     * 失败响应(Token 无效或已过期):HTTP 401
+     */
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/security/users/current/loginResponse")
+    public Map<String, Object> getCurrentUser(HttpServletRequest request) {
+        String token = request.getHeader("Access-Token");
+
+        if (token == null || token.trim().isEmpty()) {
+            log.warn("[UserInfo] 请求未携带 Access-Token");
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.UNAUTHORIZED, "未提供 Token");
+        }
+
+        // 从 Redis 获取用户信息
+        Map<String, Object> userInfo = authRedisService.getUserInfo(token.trim());
+        if (userInfo == null) {
+            log.warn("[UserInfo] Token 对应的用户信息不存在或已过期");
+            throw new org.springframework.web.server.ResponseStatusException(
+                    org.springframework.http.HttpStatus.UNAUTHORIZED, "Token 已过期,请重新登录");
+        }
+
+        // 构造前端期望的 loginUserDTO 格式
+        Map<String, Object> loginUserDTO = new HashMap<>();
+        loginUserDTO.put("id", userInfo.get("id"));
+        loginUserDTO.put("loginId", userInfo.get("loginId"));
+        loginUserDTO.put("userName", userInfo.get("userName"));
+        loginUserDTO.put("operunitid", userInfo.get("operunitid"));
+        loginUserDTO.put("bae001", userInfo.get("bae001"));
+        loginUserDTO.put("opertype", userInfo.get("opertype"));
+        loginUserDTO.put("belongsOrgName", userInfo.get("belongsOrgName"));
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("loginUserDTO", loginUserDTO);
+
+        log.debug("[UserInfo] 返回用户信息,loginId={}", userInfo.get("loginId"));
+        return result;
+    }
+
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/version")
+    public Map<String, Object> getVersion() {
+        Map<String, Object> result = new HashMap<>();
+        result.put("version", "0.15.0");
+        result.put("isShowVersion", true);
+        return result;
+    }
+
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/users/{id}/navMenus")
+    public List<Map<String, Object>> getNavMenus(@PathVariable("id") String id, HttpServletRequest request) {
+        String token = request.getHeader("Access-Token");
+        Map<String, Object> userInfo = token == null ? null : authRedisService.getUserInfo(token.trim());
+        String userId = null;
+        if (userInfo != null && userInfo.get("id") != null) {
+            userId = String.valueOf(userInfo.get("id"));
+        } else {
+            userId = id;
+        }
+        if (userId == null || userId.trim().isEmpty()) {
+            return new ArrayList<>();
+        }
+        
+        // 1. 查询用户常用/授权的扁平菜单列表 (基于视图 v_rs_sy_yydh_info)
+        // 这个列表代表“用户拥有的应用权限”
+        List<VRsSyYydhInfoPO> userApps = vRsSyYydhInfoMapper.selectList(
+                new QueryWrapper<VRsSyYydhInfoPO>()
+                        .eq("userid", userId)
+        );
+        
+        // 提取用户拥有的应用 ID 集合
+        Set<String> userAppIds = new HashSet<>();
+        for (VRsSyYydhInfoPO app : userApps) {
+            if (StringUtils.hasText(app.getCdid())) {
+                userAppIds.add(app.getCdid().trim());
+            }
+        }
+        
+        // 如果用户没有任何应用权限,返回空列表
+        if (userAppIds.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 2. 从 S_SG_MENU 表加载完整菜单树结构 (替换之前的硬编码)
+        List<SSgMenuPO> allMenus = sSgMenuMapper.selectList(
+                new QueryWrapper<SSgMenuPO>().orderByAsc("ORDER_NUMBER")
+        );
+        
+        if (allMenus == null || allMenus.isEmpty()) {
+            log.warn("S_SG_MENU table is empty, returning empty menu tree");
+            return new ArrayList<>();
+        }
+
+        // 构建 ID -> Node 映射
+        Map<String, MenuNode> menuMap = new HashMap<>();
+        for (SSgMenuPO po : allMenus) {
+            MenuNode node = new MenuNode(
+                po.getId(), 
+                po.getMenuName(), 
+                po.getIcon(), 
+                po.getUrl(), 
+                po.getParentId(), 
+                po.getOrderNumber() != null ? po.getOrderNumber() : 999
+            );
+            menuMap.put(node.id, node);
+        }
+
+        // 3. 根据用户拥有的应用权限,筛选并补全树结构
+        // 逻辑修正:如果用户拥有某个节点权限,则:
+        //   (1) 该节点的所有祖先可见(向上递归)
+        //   (2) 该节点的所有子孙可见(向下递归,级联显示子菜单)
+        Set<String> visibleMenuIds = new HashSet<>();
+        
+        // 第一轮:标记直接拥有的权限节点
+        for (String appId : userAppIds) {
+            if (menuMap.containsKey(appId)) {
+                visibleMenuIds.add(appId);
+                // 级联添加所有子孙节点
+                addDescendants(appId, menuMap, visibleMenuIds);
+            }
+        }
+        
+        // 第二轮:向上递归补全父节点
+        boolean added;
+        do {
+            added = false;
+            // 创建副本进行遍历,避免并发修改异常
+            Set<String> currentIds = new HashSet<>(visibleMenuIds);
+            for (String menuId : currentIds) {
+                MenuNode node = menuMap.get(menuId);
+                if (node != null && StringUtils.hasText(node.parentId)) {
+                    if (!visibleMenuIds.contains(node.parentId)) {
+                        visibleMenuIds.add(node.parentId);
+                        added = true;
+                    }
+                }
+            }
+        } while (added);
+
+        // 4. 组装树形结构
+        List<MenuNode> rootNodes = new ArrayList<>();
+        for (MenuNode node : menuMap.values()) {
+            // 只处理可见节点
+            if (!visibleMenuIds.contains(node.id)) {
+                continue;
+            }
+            
+            // 如果父节点为空,或者父节点不可见,则视为当前上下文的根节点
+            // 注意:如果父节点存在但不可见(理论上第二轮已补全,除非数据异常),也暂且视为根节点显示,防止断链
+            if (!StringUtils.hasText(node.parentId) || !menuMap.containsKey(node.parentId) || !visibleMenuIds.contains(node.parentId)) {
+                rootNodes.add(node);
+            } else {
+                MenuNode parent = menuMap.get(node.parentId);
+                parent.addChild(node);
+            }
+        }
+        
+        // 根节点排序
+        rootNodes.sort(Comparator.comparingInt(o -> o.sortNo));
+
+        // 转换为 Map 结构返回
+        return convertToMapList(rootNodes);
+    }
+    
+    // 递归添加所有子孙节点
+    private void addDescendants(String parentId, Map<String, MenuNode> menuMap, Set<String> visibleMenuIds) {
+        for (MenuNode node : menuMap.values()) {
+            if (parentId.equals(node.parentId)) {
+                if (!visibleMenuIds.contains(node.id)) {
+                    visibleMenuIds.add(node.id);
+                    // 继续递归添加该子节点的子孙
+                    addDescendants(node.id, menuMap, visibleMenuIds);
+                }
+            }
+        }
+    }
+
+    private List<Map<String, Object>> convertToMapList(List<MenuNode> nodes) {
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (MenuNode node : nodes) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("id", node.id);
+            map.put("name", node.name);
+            map.put("icon", node.icon);
+            map.put("path", node.path);
+            
+            // OpenType 推断
+            String openType = "1";
+            if (node.path != null && (node.path.startsWith("http://") || node.path.startsWith("https://"))) {
+                openType = "2";
+            }
+            map.put("openType", openType);
+            
+            if (!node.children.isEmpty()) {
+                map.put("children", convertToMapList(node.children));
+            }
+            result.add(map);
+        }
+        return result;
+    }
+
+    // 内部类用于构建树
+    static class MenuNode {
+        String id;
+        String name;
+        String icon;
+        String path;
+        String parentId;
+        int sortNo;
+        List<MenuNode> children = new ArrayList<>();
+
+        public MenuNode(String id, String name, String icon, String path, String parentId, int sortNo) {
+            this.id = id;
+            this.name = name;
+            this.icon = icon;
+            this.path = path;
+            this.parentId = parentId;
+            this.sortNo = sortNo;
+        }
+        
+        public void addChild(MenuNode child) {
+            children.add(child);
+            children.sort(Comparator.comparingInt(o -> o.sortNo));
+        }
+    }
+
+    // --- 保留原有辅助方法 (UserConfig, Avatar 等) ---
+
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/userConfig/find/{type}")
+    public Map<String, Object> getUserConfig(@PathVariable("type") String type) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("type", type);
+        if ("global-setting".equals(type)) {
+            Map<String, Object> attribute = new HashMap<>();
+            attribute.put("layout", "sider-layout");
+            attribute.put("enableMultiTags", false);
+            attribute.put("showBreadcrumb", false);
+            result.put("attribute", attribute);
+        }
+        return result;
+    }
+
+    @PostMapping("/leaf6-uni-cloud-uc-service/api/userConfig/save")
+    public Map<String, Object> saveUserConfig(@RequestBody Map<String, Object> request) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("type", request.get("type"));
+        result.put("attribute", request.get("attribute"));
+        return result;
+    }
+
+    @GetMapping("/leaf6-uni-cloud-uc-service/api/users/{id}/avatar")
+    public ResponseEntity<byte[]> getAvatar(@PathVariable("id") String id) {
+        String base64 = authRedisService.getUserAvatar(id);
+        if (!StringUtils.hasText(base64)) {
+            return ResponseEntity.noContent().build();
+        }
+        byte[] avatar;
+        try {
+            avatar = Base64.getDecoder().decode(base64);
+        } catch (IllegalArgumentException e) {
+            return ResponseEntity.noContent().build();
+        }
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.IMAGE_PNG);
+        return ResponseEntity.ok().headers(headers).body(avatar);
+    }
+
+    @PostMapping("/leaf6-uni-cloud-uc-service/api/users/{id}/avatar")
+    public ResponseEntity<String> uploadAvatar(@PathVariable("id") String id, @RequestParam("file") MultipartFile file) {
+        if (file.isEmpty()) {
+            return ResponseEntity.badRequest().body("文件不能为空");
+        }
+        try {
+            if (file.getSize() > 2 * 1024 * 1024) {
+                return ResponseEntity.badRequest().body("文件大小不能超过2MB");
+            }
+            byte[] bytes = file.getBytes();
+            String base64 = Base64.getEncoder().encodeToString(bytes);
+            authRedisService.saveUserAvatar(id, base64);
+            return ResponseEntity.ok("头像上传成功");
+        } catch (Exception e) {
+            log.error("头像上传失败", e);
+            return ResponseEntity.status(500).body("头像上传失败: " + e.getMessage());
+        }
+    }
+}

+ 32 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperator.java

@@ -0,0 +1,32 @@
+package com.zjrs.zwnw.auth.entity;
+
+import lombok.Data;
+
+/**
+ * FW_OPERATOR 表 对应实体类(操作员)
+ */
+@Data
+public class FwOperator {
+    /** 行政区划代码 */
+    private String bae001;
+    /** 经办单位ID */
+    private Long operunitid;
+    /** 操作员ID(主键) */
+    private String operid;
+    /** SG用户ID */
+    private String sguserid;
+    /** 操作员名称 */
+    private String opername;
+    /** 操作员类型 */
+    private String opertype;
+    /** 登录ID */
+    private String loginid;
+    /** 密码 */
+    private String password;
+    /** 密码加密标志:0-明文,1-MD5 */
+    private String pwencrypt;
+    /** 状态:1-有效 */
+    private String aae100;
+    /** 操作员类型2 */
+    private String opertype2;
+}

+ 21 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperatorMapper.java

@@ -0,0 +1,21 @@
+package com.zjrs.zwnw.auth.entity;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * FW_OPERATOR 表 Mapper
+ */
+@Mapper
+public interface FwOperatorMapper {
+
+    /**
+     * 根据 loginId 查询操作员信息(含密码、状态)
+     */
+    FwOperator selectByLoginId(@Param("loginId") String loginId);
+
+    /**
+     * 根据 operid 查询操作员信息
+     */
+    FwOperator selectByOperId(@Param("operid") String operid);
+}

+ 37 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/entity/FwOperatorMapper.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.mohrss.leaf.zjrs.auth.entity.FwOperatorMapper">
+
+    <resultMap id="FwOperatorResultMap" type="org.mohrss.leaf.zjrs.auth.entity.FwOperator">
+        <result column="BAE001"     property="bae001"/>
+        <result column="OPERUNITID" property="operunitid"/>
+        <result column="OPERID"     property="operid"/>
+        <result column="SGUSERID"   property="sguserid"/>
+        <result column="OPERNAME"   property="opername"/>
+        <result column="OPERTYPE"   property="opertype"/>
+        <result column="LOGINID"    property="loginid"/>
+        <result column="PASSWORD"   property="password"/>
+        <result column="PWENCRYPT"  property="pwencrypt"/>
+        <result column="AAE100"     property="aae100"/>
+        <result column="OPERTYPE2"  property="opertype2"/>
+    </resultMap>
+
+    <!-- 根据 loginId 查询操作员(只取必要字段,含密码) -->
+    <select id="selectByLoginId" resultMap="FwOperatorResultMap">
+        SELECT BAE001, OPERUNITID, OPERID, SGUSERID, OPERNAME, OPERTYPE,
+               LOGINID, PASSWORD, PWENCRYPT, AAE100, OPERTYPE2
+        FROM ZJRS_YWXT.FW_OPERATOR
+        WHERE LOGINID = #{loginId}
+          AND ROWNUM = 1
+    </select>
+
+    <select id="selectByOperId" resultMap="FwOperatorResultMap">
+        SELECT BAE001, OPERUNITID, OPERID, SGUSERID, OPERNAME, OPERTYPE,
+               LOGINID, PASSWORD, PWENCRYPT, AAE100, OPERTYPE2
+        FROM ZJRS_YWXT.FW_OPERATOR
+        WHERE OPERID = #{operid}
+          AND ROWNUM = 1
+    </select>
+
+</mapper>

+ 95 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/service/AuthRedisService.java

@@ -0,0 +1,95 @@
+package com.zjrs.zwnw.auth.service;
+
+import com.alibaba.fastjson.JSON;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 认证 Redis 服务
+ * 负责将登录用户信息存入 Redis,以 Token 为 key,供后续接口鉴别身份
+ */
+@Service
+public class AuthRedisService {
+
+    private static final Logger log = LoggerFactory.getLogger(AuthRedisService.class);
+
+    /** Redis key 前缀 */
+    private static final String KEY_PREFIX = "zjrs:auth:token:";
+
+    /** Redis 头像 key 前缀 */
+    private static final String AVATAR_KEY_PREFIX = "zjrs:user:avatar:";
+
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    /**
+     * 将用户头像存入 Redis
+     *
+     * @param userId 用户ID
+     * @param avatarBase64 头像Base64字符串
+     */
+    public void saveUserAvatar(String userId, String avatarBase64) {
+        String key = AVATAR_KEY_PREFIX + userId;
+        // 头像不设置过期时间,或者设置较长的过期时间
+        redisTemplate.opsForValue().set(key, avatarBase64);
+        log.info("[Auth] 用户 {} 头像已缓存至 Redis", userId);
+    }
+
+    /**
+     * 根据 用户ID 从 Redis 获取用户头像
+     *
+     * @param userId 用户ID
+     * @return 头像Base64字符串,不存在时返回 null
+     */
+    public String getUserAvatar(String userId) {
+        String key = AVATAR_KEY_PREFIX + userId;
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 将用户信息存入 Redis
+     *
+     * @param token         JWT Token 字符串
+     * @param userInfo      用户信息 Map(loginId, userName, operid, operunitid)
+     * @param expireSeconds 有效期(秒)
+     */
+    public void saveToken(String token, Map<String, Object> userInfo, long expireSeconds) {
+        String key = KEY_PREFIX + token;
+        String value = JSON.toJSONString(userInfo);
+        redisTemplate.opsForValue().set(key, value, expireSeconds, TimeUnit.SECONDS);
+        log.info("[Auth] 用户 {} 登录成功,Token 已缓存至 Redis,有效期 {}s", userInfo.get("loginId"), expireSeconds);
+    }
+
+    /**
+     * 根据 Token 从 Redis 获取用户信息
+     *
+     * @param token JWT Token 字符串
+     * @return 用户信息 Map,不存在时返回 null
+     */
+    @SuppressWarnings("unchecked")
+    public Map<String, Object> getUserInfo(String token) {
+        String key = KEY_PREFIX + token;
+        String value = redisTemplate.opsForValue().get(key);
+        if (value == null) {
+            return null;
+        }
+        return JSON.parseObject(value, Map.class);
+    }
+
+    /**
+     * 删除 Token(登出)
+     *
+     * @param token JWT Token 字符串
+     */
+    public void deleteToken(String token) {
+        String key = KEY_PREFIX + token;
+        redisTemplate.delete(key);
+        log.info("[Auth] Token {} 已从 Redis 中删除(用户登出)", token);
+    }
+}

+ 77 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/auth/util/JwtUtil.java

@@ -0,0 +1,77 @@
+package com.zjrs.zwnw.auth.util;
+
+import io.jsonwebtoken.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * JWT 工具类(HMAC-SHA256)
+ * 使用 jjwt 0.9.1 API
+ */
+@Component
+public class JwtUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
+
+    /** Token 有效期:4小时(秒) */
+    private static final long EXPIRE_SECONDS = 4 * 60 * 60;
+
+    /**
+     * HMAC 密钥(生产环境应从配置文件读取)
+     */
+    private static final String SECRET = "zjrs-zwnw-service-2019-auth-key-xK9mP3qR7vZ1nL5wY8eA";
+
+    /**
+     * 生成 JWT Token
+     */
+    public String generateToken(String loginId, String userName, String operid, Long operunitid) {
+        Map<String, Object> claims = new HashMap<>();
+        claims.put("loginId", loginId);
+        claims.put("userName", userName);
+        claims.put("operid", operid);
+        claims.put("operunitid", operunitid);
+
+        Date now = new Date();
+        Date expiry = new Date(now.getTime() + EXPIRE_SECONDS * 1000L);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .setSubject(loginId)
+                .setIssuedAt(now)
+                .setExpiration(expiry)
+                .signWith(SignatureAlgorithm.HS256, SECRET.getBytes())
+                .compact();
+    }
+
+    /**
+     * 解析 Token,失败返回 null
+     */
+    public Claims parseToken(String token) {
+        try {
+            return Jwts.parser()
+                    .setSigningKey(SECRET.getBytes())
+                    .parseClaimsJws(token)
+                    .getBody();
+        } catch (ExpiredJwtException e) {
+            log.warn("Token 已过期: {}", e.getMessage());
+        } catch (JwtException e) {
+            log.warn("Token 解析失败: {}", e.getMessage());
+        }
+        return null;
+    }
+
+    /** 校验 Token 是否有效 */
+    public boolean isValid(String token) {
+        return parseToken(token) != null;
+    }
+
+    /** 获取 Token 有效期(秒) */
+    public long getExpireSeconds() {
+        return EXPIRE_SECONDS;
+    }
+}

+ 253 - 7
zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/blo/impl/DhyyBLOimpl.java

@@ -1,6 +1,11 @@
 package com.zjrs.zwnw.portal.blo.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.zjrs.zwnw.sxgl.entity.FwRight2ResourceMapper;
+import com.zjrs.zwnw.sxgl.entity.FwrightMapper;
+import com.zjrs.zwnw.sxgl.po.FwRight2ResourcePO;
+import com.zjrs.zwnw.sxgl.po.FwrightPO;
+import org.apache.commons.lang.StringUtils;
 import org.mohrss.leaf.core.framework.domain.bpo.impl.BPOImpl;
 import org.mohrss.leaf.core.framework.util.CurrentUser;
 import com.zjrs.zwnw.portal.blo.DhyyBLO;
@@ -9,11 +14,13 @@ import com.zjrs.zwnw.portal.entity.VRsSyYydhInfoMapper;
 import com.zjrs.zwnw.portal.entity.VRsSyYydhSzMapper;
 import com.zjrs.zwnw.portal.po.VRsSyYydhInfoPO;
 import com.zjrs.zwnw.portal.po.VRsSyYydhSzPO;
+import org.mohrss.leaf.core.framework.web.exception.AppException;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import jakarta.annotation.Resource;
-import java.util.List;
-import java.util.Map;
+
+import java.util.*;
 
 
 @Service
@@ -24,25 +31,264 @@ public class DhyyBLOimpl extends BPOImpl implements DhyyBLO {
     @Resource
     private VRsSyYydhSzMapper vRsSyYydhSzMapper;
 
+    @Autowired
+    private FwrightMapper fwrightMapper;
+
+    @Autowired
+    private FwRight2ResourceMapper fwRight2ResourceMapper;
+
     @Override
     public List<VRsSyYydhInfoPO> getuserApp() {
-        CurrentUser currentUser = getCurrentUser();
-        String userid = currentUser.getUserid();
+        String userid = resolveUserid(getCurrentUser());
         List<VRsSyYydhInfoPO> result = vRsSyYydhInfoMapper.selectList(new QueryWrapper<VRsSyYydhInfoPO>().eq("userid", userid));
+
+        if (result != null && !result.isEmpty()) {
+            List<String> cdids = new ArrayList<>();
+            List<String> appNames = new ArrayList<>();
+            Map<String, List<String>> nameToCdids = new HashMap<>();
+            for (VRsSyYydhInfoPO app : result) {
+                if (StringUtils.isNotBlank(app.getCdid())) {
+                    cdids.add(app.getCdid().trim());
+                }
+                if (StringUtils.isNotBlank(app.getLname())) {
+                    String appName = app.getLname().trim();
+                    appNames.add(appName);
+                    nameToCdids.computeIfAbsent(appName, k -> new ArrayList<>()).add(app.getCdid() == null ? "" : app.getCdid().trim());
+                }
+            }
+
+            Map<String, String> rightUrlMap = new HashMap<>();
+            Set<String> repairableCdids = new HashSet<>();
+            if (!cdids.isEmpty()) {
+                List<FwRight2ResourcePO> resourcesByRightId = fwRight2ResourceMapper.selectList(
+                        new QueryWrapper<FwRight2ResourcePO>().in("RIGHTID", cdids)
+                );
+                for (FwRight2ResourcePO res : resourcesByRightId) {
+                    if (StringUtils.isNotBlank(res.getUrl()) && StringUtils.isNotBlank(res.getRightid())) {
+                        rightUrlMap.put(res.getRightid().trim(), res.getUrl().trim());
+                    }
+                }
+
+                List<String> missingCdids = new ArrayList<>();
+                for (String cdid : cdids) {
+                    if (!rightUrlMap.containsKey(cdid)) {
+                        missingCdids.add(cdid);
+                    }
+                }
+
+                if (!missingCdids.isEmpty()) {
+                    List<FwRight2ResourcePO> resourcesBySubsystem = fwRight2ResourceMapper.selectList(
+                            new QueryWrapper<FwRight2ResourcePO>().in("SUBSYSTYPE", missingCdids)
+                    );
+                    for (FwRight2ResourcePO res : resourcesBySubsystem) {
+                        if (StringUtils.isNotBlank(res.getUrl()) && StringUtils.isNotBlank(res.getSubsystype())) {
+                            rightUrlMap.put(res.getSubsystype().trim(), res.getUrl().trim());
+                        }
+                    }
+                }
+
+                List<String> stillMissingCdids = new ArrayList<>();
+                for (String cdid : cdids) {
+                    if (!rightUrlMap.containsKey(cdid)) {
+                        stillMissingCdids.add(cdid);
+                    }
+                }
+
+                if (!stillMissingCdids.isEmpty()) {
+                    List<FwrightPO> rights = fwrightMapper.selectList(new QueryWrapper<FwrightPO>().in("RIGHTID", stillMissingCdids));
+                    for (FwrightPO right : rights) {
+                        if (StringUtils.isNotBlank(right.getUrl()) && StringUtils.isNotBlank(right.getRightid())) {
+                            rightUrlMap.putIfAbsent(right.getRightid().trim(), right.getUrl().trim());
+                            repairableCdids.add(right.getRightid().trim());
+                        }
+                    }
+                }
+
+                stillMissingCdids = new ArrayList<>();
+                for (String cdid : cdids) {
+                    if (!rightUrlMap.containsKey(cdid)) {
+                        stillMissingCdids.add(cdid);
+                    }
+                }
+
+                if (!stillMissingCdids.isEmpty()) {
+                    List<FwrightPO> subsystemRights = fwrightMapper.selectList(
+                            new QueryWrapper<FwrightPO>().in("SUBSYSTYPE", stillMissingCdids)
+                    );
+                    for (FwrightPO right : subsystemRights) {
+                        if (StringUtils.isNotBlank(right.getUrl()) && StringUtils.isNotBlank(right.getSubsystype())) {
+                            rightUrlMap.putIfAbsent(right.getSubsystype().trim(), right.getUrl().trim());
+                            repairableCdids.add(right.getSubsystype().trim());
+                        }
+                    }
+                }
+
+                stillMissingCdids = new ArrayList<>();
+                for (String cdid : cdids) {
+                    if (!rightUrlMap.containsKey(cdid)) {
+                        stillMissingCdids.add(cdid);
+                    }
+                }
+
+                if (!stillMissingCdids.isEmpty() && !appNames.isEmpty()) {
+                    List<FwrightPO> nameRights = fwrightMapper.selectList(
+                            new QueryWrapper<FwrightPO>().in("RIGHTNAME", appNames)
+                    );
+                    Set<String> missingCdidSet = new HashSet<>(stillMissingCdids);
+                    for (FwrightPO right : nameRights) {
+                        if (StringUtils.isBlank(right.getUrl()) || StringUtils.isBlank(right.getRightname())) {
+                            continue;
+                        }
+                        List<String> mappedCdids = nameToCdids.get(right.getRightname().trim());
+                        if (mappedCdids == null || mappedCdids.isEmpty()) {
+                            continue;
+                        }
+                        for (String mappedCdid : mappedCdids) {
+                            if (missingCdidSet.contains(mappedCdid)) {
+                                rightUrlMap.putIfAbsent(mappedCdid, right.getUrl().trim());
+                                repairableCdids.add(mappedCdid);
+                            }
+                        }
+                    }
+                }
+
+                stillMissingCdids = new ArrayList<>();
+                for (String cdid : cdids) {
+                    if (!rightUrlMap.containsKey(cdid)) {
+                        stillMissingCdids.add(cdid);
+                    }
+                }
+
+                if (!stillMissingCdids.isEmpty()) {
+                    List<FwRight2ResourcePO> allResources = fwRight2ResourceMapper.selectList(
+                            new QueryWrapper<FwRight2ResourcePO>().isNotNull("URL")
+                    );
+                    Map<String, String> normalizedRightIdUrlMap = new HashMap<>();
+                    Map<String, String> normalizedSubsysUrlMap = new HashMap<>();
+                    for (FwRight2ResourcePO res : allResources) {
+                        if (StringUtils.isBlank(res.getUrl())) {
+                            continue;
+                        }
+                        String url = res.getUrl().trim();
+                        String normalizedRightId = normalizeKey(res.getRightid());
+                        if (StringUtils.isNotBlank(normalizedRightId)) {
+                            normalizedRightIdUrlMap.putIfAbsent(normalizedRightId, url);
+                        }
+                        String normalizedSubsys = normalizeKey(res.getSubsystype());
+                        if (StringUtils.isNotBlank(normalizedSubsys)) {
+                            normalizedSubsysUrlMap.putIfAbsent(normalizedSubsys, url);
+                        }
+                    }
+                    for (String cdid : stillMissingCdids) {
+                        String normalizedCdid = normalizeKey(cdid);
+                        if (StringUtils.isBlank(normalizedCdid)) {
+                            continue;
+                        }
+                        String url = pickFirstText(normalizedRightIdUrlMap.get(normalizedCdid), normalizedSubsysUrlMap.get(normalizedCdid));
+                        if (StringUtils.isNotBlank(url)) {
+                            rightUrlMap.put(cdid, url);
+                        }
+                    }
+                }
+
+                repairMissingRight2Resource(cdids, rightUrlMap, repairableCdids);
+            }
+
+            for (VRsSyYydhInfoPO app : result) {
+                String cdid = app.getCdid() != null ? app.getCdid().trim() : "";
+                String path = rightUrlMap.get(cdid);
+                if (StringUtils.isNotBlank(path)) {
+                    app.setPath(path);
+                    if (StringUtils.isBlank(app.getOpenType())) {
+                        if (path.startsWith("http://") || path.startsWith("https://")) {
+                            app.setOpenType("2");
+                        } else {
+                            app.setOpenType("1");
+                        }
+                    }
+                }
+            }
+        }
+
         return result;
     }
 
     @Override
     public void changeUseApp(ChangeUseAppDTO dto) {
         List<Map<String, Object>> data = dto.getData();
+        String userid = resolveUserid(getCurrentUser());
         for (int i = 0; i < data.size(); i++) {
             VRsSyYydhSzPO po = new VRsSyYydhSzPO();
-            CurrentUser currentUser = getCurrentUser();
-            String userid = currentUser.getUserid();
-            
             po.setCdid(data.get(i).get("id").toString());
             po.setUserid(userid);
             vRsSyYydhSzMapper.insert(po);
         }
     }
+
+    private String resolveUserid(CurrentUser currentUser) {
+        String userid = trimToNull(currentUser == null ? null : currentUser.getUserid());
+        if (StringUtils.isBlank(userid)) {
+            userid = trimToNull(currentUser == null ? null : currentUser.getUsername());
+        }
+        if (StringUtils.isBlank(userid)) {
+            throw new AppException("获取不到该用户信息");
+        }
+        return userid;
+    }
+
+    private void repairMissingRight2Resource(List<String> cdids, Map<String, String> rightUrlMap, Set<String> repairableCdids) {
+        if (cdids == null || cdids.isEmpty() || repairableCdids == null || repairableCdids.isEmpty()) {
+            return;
+        }
+        List<FwRight2ResourcePO> existedResources = fwRight2ResourceMapper.selectList(
+                new QueryWrapper<FwRight2ResourcePO>().in("RIGHTID", cdids)
+        );
+        Set<String> existedRightIds = new HashSet<>();
+        for (FwRight2ResourcePO resource : existedResources) {
+            if (StringUtils.isNotBlank(resource.getRightid())) {
+                existedRightIds.add(resource.getRightid().trim());
+            }
+        }
+        for (String cdid : cdids) {
+            if (!repairableCdids.contains(cdid) || existedRightIds.contains(cdid)) {
+                continue;
+            }
+            String url = rightUrlMap.get(cdid);
+            if (StringUtils.isBlank(url)) {
+                continue;
+            }
+            FwRight2ResourcePO toInsert = new FwRight2ResourcePO();
+            toInsert.setRightid(cdid);
+            toInsert.setSubsystype(cdid);
+            toInsert.setUrl(url);
+            fwRight2ResourceMapper.insert(toInsert);
+            existedRightIds.add(cdid);
+        }
+    }
+
+    private String pickFirstText(String... values) {
+        if (values == null) {
+            return null;
+        }
+        for (String value : values) {
+            if (StringUtils.isNotBlank(value)) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    private String normalizeKey(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        return value.replaceAll("[^0-9A-Za-z]", "").toLowerCase();
+    }
+
+    private String trimToNull(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        return value.trim();
+    }
 }

+ 10 - 10
zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/blo/impl/RcglBLOimpl.java

@@ -45,15 +45,15 @@ public class RcglBLOimpl extends BLOImpl implements RcglBLO {
         VRsSyOrgAreaPO orgareapo = vRsSyOrgAreaMapper.selectOne(new QueryWrapper<VRsSyOrgAreaPO>()
                 .select("org_id", "area_id")
                 .eq("user_id", userid));
-        String orgid = orgareapo.getOrgid();
-        String areaid = orgareapo.getAreaid();
+        String orgid = orgareapo != null ? orgareapo.getOrgid() : "";
+        String areaid = orgareapo != null ? orgareapo.getAreaid() : "";
         List<Object> result = new ArrayList<Object>();
         if (dto.getFlag().equals("month")) {
             // 个人日程
             if (StringUtils.isNotBlank(userid)) {
                 List<VRsSyRcglPO> result1 = vRsSyRcglMapper.selectList(new QueryWrapper<VRsSyRcglPO>()
-                        .apply("to_date (rcsj,'YY-MM-DD HH24:MI:SS') <= last_day(to_date('" + (dto.getId() + " 23:59:59") + "','YY-MM-DD HH24:MI:SS'))")
-                );
+                        .apply("to_date (rcsj,'YY-MM-DD HH24:MI:SS') <= last_day(to_date('"
+                                + (dto.getId() + " 23:59:59") + "','YY-MM-DD HH24:MI:SS'))"));
                 result.addAll(result1);
             }
             // 同科室日程timeline
@@ -138,20 +138,20 @@ public class RcglBLOimpl extends BLOImpl implements RcglBLO {
         // 获取日程所需要接收的人,个人的,科室的,全局的
         List<String> sjrList = new ArrayList<String>();
         if (rcfl.equals("3")) {
-            //个人日程
+            // 个人日程
             // sjrList.add(userid);
         } else {
             // 查询日程操作人的组织机构和行政区划
             VRsSyOrgAreaPO orgareapo = vRsSyOrgAreaMapper.selectOne(new QueryWrapper<VRsSyOrgAreaPO>()
-                     .eq("user_id", userid));
-            String orgid = orgareapo.getOrgid();
-            String areaid = orgareapo.getAreaid();
+                    .eq("user_id", userid));
+            String orgid = orgareapo != null ? orgareapo.getOrgid() : "";
+            String areaid = orgareapo != null ? orgareapo.getAreaid() : "";
             if (rcfl.equals("2") && StringUtils.isNotBlank(orgid)) {
-                //科室日程
+                // 科室日程
                 QueryWrapper<VRsSyOrgAreaPO> queryWrapper = new QueryWrapper<VRsSyOrgAreaPO>();
                 queryWrapper.select("user_id").eq("org_id", orgid);
             } else if (rcfl.equals("1") && StringUtils.isNotBlank(areaid)) {
-                //全局日程
+                // 全局日程
                 QueryWrapper<VRsSyOrgAreaPO> queryWrapper = new QueryWrapper<VRsSyOrgAreaPO>();
                 queryWrapper.select("user_id").eq("area_id", areaid);
             }

+ 0 - 13
zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/entity/VRsSyZskMapper.xml

@@ -64,19 +64,6 @@
         order by TS_CJSJ desc
     </select>
 
-    <select id="getZskList" parameterType="com.zjrs.zwnw.portal.dto.ZskQueryDTO" resultType="map">
-        SELECT RS_SY_ZSK_LSH "rssyzsklsh",bt "bt",strsplit2dict(ywzt, ',', 'RS_SY_ZSK_YWZT') "ywzt",
-        fbzt "fbzt", TS_YXBZ "tsyxbz",
-        f_common_getSSgUserOrg(bae001) as "bae001",
-        f_common_getSSgUser(bae004) as "bae004", bae005 "bae005",
-        f_common_getSSgUserOrg(bae006) as "bae006" FROM RS_SY_ZSK
-        WHERE 
-        <if test="dto.qwss != null and dto.qwss != ''">
-            (ztc like '%'||#{dto.qwss}||'%' or bt like '%'||#{dto.qwss}||'%' or zw like '%'||#{dto.qwss}||'%')
-        </if>
-        ORDER BY bae005 DESC
-    </select>
-
     <select id="getZskIds" parameterType="com.zjrs.zwnw.portal.dto.ZskQueryDTO" resultType="map">
         SELECT LISTAGG(RS_SY_ZSK_LSH, ',') WITHIN GROUP(ORDER BY RS_SY_ZSK_LSH) "ids" FROM RS_SY_ZSK
         WHERE 

+ 59 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/portal/po/VRsSyYydhInfoPO.java

@@ -1,5 +1,6 @@
 package com.zjrs.zwnw.portal.po;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 
 @TableName(value = "v_rs_sy_yydh_info")
@@ -8,6 +9,16 @@ public class VRsSyYydhInfoPO {
     private String cdid;//应用id
     private String yysx;//应用顺序
     private String lname;//应用全称
+    @TableField(value = "path", exist = false)
+    private String path;
+    @TableField(value = "open_type", exist = false)
+    private String openType;
+    @TableField(value = "icon", exist = false)
+    private String icon;
+    @TableField(value = "parent_id", exist = false)
+    private String parentId;
+    @TableField(value = "sort_no", exist = false)
+    private Integer sortNo;
 
     public String getUserid() {
         return userid;
@@ -40,4 +51,52 @@ public class VRsSyYydhInfoPO {
     public void setLname(String lname) {
         this.lname = lname;
     }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public String getOpenType() {
+        return openType;
+    }
+
+    public void setOpenType(String openType) {
+        this.openType = openType;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public Integer getSortNo() {
+        return sortNo;
+    }
+
+    public void setSortNo(Integer sortNo) {
+        this.sortNo = sortNo;
+    }
+
+    public String getId() {
+        return cdid;
+    }
+
+    public String getName() {
+        return lname;
+    }
 }

+ 10 - 4
zjrs-service-backend/src/main/java/com/zjrs/zwnw/rlzysc/entity/VRsRlzyZwxxMapper.java

@@ -14,9 +14,15 @@ import java.util.Map;
 
 @Mapper
 public interface VRsRlzyZwxxMapper extends BaseMapper<VRsRlzyZwxxPO> {
-    public Page<Map<String,Object>> getDwzpxxshList(Page<Map<String,Object>> page, @Param("dto") ZpxxQueryDTO dto);
+    public Page<Map<String, Object>> getDwzpxxshList(Page<Map<String, Object>> page, @Param("dto") ZpxxQueryDTO dto);
+
     public List<DwzpxxglDTO> getDwzpxxglExportList(@Param("dto") ZpxxQueryDTO dto);
-    public Map<String,Object> getDwzpxxshXx(@Param("dto") ZjQueryDTO dto);
-    public Page<Map<String,Object>> getDwzpxxglList(Page<Map<String,Object>> page, @Param("dto") ZpxxQueryDTO dto);
-    public Page<Map<String,Object>> getZpxxGwppList(Page<Map<String,Object>> page, @Param("dto") ZpxxQueryDTO dto);
+
+    public Map<String, Object> getDwzpxxshXx(@Param("dto") ZjQueryDTO dto);
+
+    public Page<Map<String, Object>> getDwzpxxglList(Page<Map<String, Object>> page, @Param("dto") ZpxxQueryDTO dto);
+
+    public Page<Map<String, Object>> getZpxxGwppList(Page<Map<String, Object>> page, @Param("dto") ZpxxQueryDTO dto);
+
+    public Page<Map<String, Object>> getZpxxYyshList(Page<Map<String, Object>> page, @Param("dto") ZpxxQueryDTO dto);
 }

+ 1 - 1
zjrs-service-backend/src/main/java/com/zjrs/zwnw/rlzysc/entity/VRsRlzyZwxxMapper.xml

@@ -157,7 +157,7 @@
         order by b.ts_xgsj DESC
     </select>
 
-    <select id="getZpxxGwppList" parameterType="com.zjrs.zwnw.rlzysc.dto.ZpxxQueryDTO" resultType="HashMap">
+    <select id="getZpxxYyshList" parameterType="com.zjrs.zwnw.rlzysc.dto.ZpxxQueryDTO" resultType="HashMap">
         select c.aab004 as "gsmc",
         (select count(rs_zwwz_lsh)
         from v_rs_rlzy_zwwzyysh

+ 14 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/entity/FwRight2ResourceMapper.java

@@ -0,0 +1,14 @@
+package com.zjrs.zwnw.sxgl.entity;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zjrs.zwnw.portal.po.VRsSyYydhInfoPO;
+import com.zjrs.zwnw.sxgl.po.FwRight2ResourcePO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface FwRight2ResourceMapper extends BaseMapper<FwRight2ResourcePO> {
+    List<VRsSyYydhInfoPO> selectList(QueryWrapper<FwRight2ResourcePO> rightid);
+}

+ 40 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/po/FwRight2ResourcePO.java

@@ -0,0 +1,40 @@
+package com.zjrs.zwnw.sxgl.po;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+@TableName(value = "FW_RIGHT2RESOURCE")
+public class FwRight2ResourcePO {
+    @TableField("RIGHTID")
+    private String rightid;
+
+    @TableField("SUBSYSTYPE")
+    private String subsystype;
+
+    @TableField("URL")
+    private String url;
+
+    public String getRightid() {
+        return rightid;
+    }
+
+    public void setRightid(String rightid) {
+        this.rightid = rightid;
+    }
+
+    public String getSubsystype() {
+        return subsystype;
+    }
+
+    public void setSubsystype(String subsystype) {
+        this.subsystype = subsystype;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+}

+ 5 - 0
zjrs-service-backend/src/main/java/com/zjrs/zwnw/sxgl/po/FwrightPO.java

@@ -1,9 +1,13 @@
 package com.zjrs.zwnw.sxgl.po;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 
 @TableName(value = "fw_right")
 public class FwrightPO {
+    @TableId(value = "RIGHTID", type = IdType.INPUT)
     private String rightid;       //权限表ID
     private String subsystype;       //子系统类别
     private String rightname;       //权限名称
@@ -11,6 +15,7 @@ public class FwrightPO {
     private String rightlevel;       //树根是1、然后树干、树叶往后排
     private String sortno;       //在同一层级下的排序大小
     private String actionDefId;       //包括流程定义id和环节id,用竖线分隔。
+    @TableField("URL")
     private String url;       //如果是枝干则为空
     private String aae100;       //停办时为无效
     private String bae003;       //创建时间