25 Commits 37f71abce8 ... 6cb4750f1a

Autor SHA1 Mensagem Data
  ZL 6cb4750f1a 判断条件修改 2 meses atrás
  ZL fd20e3475a Merge branch 'ZL' into dev 2 meses atrás
  ZL 092a2fe20d Merge remote-tracking branch 'origin/ZL' into ZL 2 meses atrás
  ZL a6f9f20a1a 菜单管理与角色管理数据权限修改 2 meses atrás
  danch 81cf8bdc1b 前端部署配置文件修改 2 meses atrás
  danch 289544aed9 恢复demo 2 meses atrás
  danch 0116db52b8 去掉demo、xxl-job和sentinel 2 meses atrás
  danch 2dcd71e480 添加xxl-job和sentinel 2 meses atrás
  ZL 127914908b 数据权限问题 2 meses atrás
  danch eac9062814 Merge branch 'jiahao' into dev 2 meses atrás
  danch 14c7282c5f 修改nacos和xxl-job到测试数据库 2 meses atrás
  ZL 9b43425243 数据权限问题 2 meses atrás
  ZL e9d10abf06 用户数据规则保存问题修复 2 meses atrás
  ZL 417f9d7810 修改appUserInfo构造函数 2 meses atrás
  ZL 459433f5e0 用户角色分组显示,新增用户应用同步 2 meses atrás
  ZL 9d608f43e4 Merge remote-tracking branch 'origin/dev' into dev 2 meses atrás
  ZL 056c38c91b 保存新增用户接口增加同步用户应用关系 2 meses atrás
  LT32820A a98bdd5068 Merge branch 'zrq' into dev 2 meses atrás
  LT32820A 28c2b86e3d Merge remote-tracking branch 'origin/dev' into dev 2 meses atrás
  LT32820A b1aad44696 829 早上提交 2 meses atrás
  ZL a23210ff2e 1、添加查看全部角色(按照应用分组)接口 2、修改角色分配用户列表前台接口、用户添加角色下拉框 2 meses atrás
  LT32820A 8777b961a4 830 早上提交 2 meses atrás
  LT32820A d6d08bb44c Merge branch 'zrq' into dev 2 meses atrás
  LT32820A 3e345ba13f 829 早上提交 2 meses atrás
  LT32820A 4b08a920c8 828 下午提交 2 meses atrás
42 arquivos alterados com 636 adições e 269 exclusões
  1. 0 4
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/AppmanageController.java
  2. 13 21
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
  3. 68 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java
  4. 1 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/AppmanageEntity/AppEnvInfo.java
  5. 8 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/AppmanageEntity/AppUserInfo.java
  6. 1 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java
  7. 5 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java
  8. 2 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserPermissionMapper.java
  9. 44 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml
  10. 17 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml
  11. 22 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPermissionMapper.xml
  12. 0 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/AppmanageService.java
  13. 1 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysPermissionService.java
  14. 2 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java
  15. 2 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserPermissionService.java
  16. 57 66
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AppmanageServiceImpl.java
  17. 23 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java
  18. 4 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysRoleServiceImpl.java
  19. 4 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserPermissionServiceImpl.java
  20. 11 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
  21. 9 6
      jeecg-boot/jeecg-server-cloud/docker-compose.yml
  22. 2 2
      jeecg-boot/jeecg-server-cloud/jeecg-cloud-nacos/src/main/resources/application.yml
  23. 2 2
      jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/resources/application.yml
  24. 2 2
      jeecgboot-vue3/Dockerfile
  25. 17 0
      jeecgboot-vue3/docker-compose.yml
  26. 6 1
      jeecgboot-vue3/src/views/appmanage/AppBaseInfo.api.ts
  27. 12 8
      jeecgboot-vue3/src/views/appmanage/AppInfoList.vue
  28. 12 9
      jeecgboot-vue3/src/views/appmanage/addForm/Step2.vue
  29. 71 86
      jeecgboot-vue3/src/views/appmanage/addForm/Step4.vue
  30. 55 0
      jeecgboot-vue3/src/views/appmanage/addForm/data.tsx
  31. 30 15
      jeecgboot-vue3/src/views/appmanage/addForm/index.vue
  32. 2 2
      jeecgboot-vue3/src/views/appmanage/components/data.tsx
  33. 13 9
      jeecgboot-vue3/src/views/system/menu/components/AppPermissionTree.vue
  34. 1 1
      jeecgboot-vue3/src/views/system/menu/menu/menu.api.ts
  35. 23 5
      jeecgboot-vue3/src/views/system/role/components/RoleUserTable.vue
  36. 25 8
      jeecgboot-vue3/src/views/system/role/components/UseSelectModal.vue
  37. 10 0
      jeecgboot-vue3/src/views/system/role/index.vue
  38. 5 1
      jeecgboot-vue3/src/views/system/role/role.api.ts
  39. 24 0
      jeecgboot-vue3/src/views/system/role/role.data.ts
  40. 7 2
      jeecgboot-vue3/src/views/system/user/UserDrawer.vue
  41. 16 3
      jeecgboot-vue3/src/views/system/user/user.api.ts
  42. 7 9
      jeecgboot-vue3/src/views/system/user/user.data.ts

+ 0 - 4
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/AppmanageController.java

@@ -168,8 +168,4 @@ public class AppmanageController {
         return Result.ok(appInfoService.isAppAdminOrDevOrOpe(appid));
     }
 
-    @GetMapping("/addAppUserRoleInfos")
-    public void addAppUserRoleInfos(SysUserRole sysUserRole){
-        appInfoService.addAppUserRoleInfos(sysUserRole);
-    }
 }

+ 13 - 21
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java

@@ -9,10 +9,12 @@ import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.apache.shiro.subject.Subject;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.PermissionData;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.IpUtils;
 import org.jeecg.common.util.Md5Util;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.config.JeecgBaseConfig;
@@ -95,27 +97,16 @@ public class SysPermissionController {
 	 *
 	 * @return
 	 */
-	//@RequiresPermissions("system:permission:list")
-	@RequestMapping(value = "/list", method = RequestMethod.GET)
+	@RequiresPermissions("system:permission:list")
+	@RequestMapping(value = "/sqlList", method = RequestMethod.GET)
+	@PermissionData
 	public Result<List<SysPermissionTree>> list(SysPermission sysPermission, HttpServletRequest req) {
         long start = System.currentTimeMillis();
 		Result<List<SysPermissionTree>> result = new Result<>();
 		try {
-//			LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
-//			query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0);
-//			query.orderByAsc(SysPermission::getSortNo);
-//
-//			//支持通过菜单名字,模糊查询
-//			if(oConvertUtils.isNotEmpty(sysPermission.getName())){
-//				query.like(SysPermission::getName, sysPermission.getName());
-//			}
-//			//通过应用id条件查询
-//			if(oConvertUtils.isNotEmpty(sysPermission.getAppId())){
-//				query.eq(SysPermission::getAppId, sysPermission.getAppId());
-//			}
-//			List<SysPermission> list = sysPermissionService.list(query);
 			sysPermission.setDelFlag(CommonConstant.DEL_FLAG_0);
-			List<SysPermission> list = sysPermissionService.listAndAppName(sysPermission);
+//			List<SysPermission> list = sysPermissionService.listAndAppName(sysPermission);
+			List<SysPermission> list = sysPermissionService.listAndAppNameWithPermission(sysPermission);
 			List<SysPermissionTree> treeList = new ArrayList<>();
 
 			//如果有菜单名查询条件,则平铺数据 不做上下级
@@ -149,17 +140,13 @@ public class SysPermissionController {
 		sysPermission.setAppId(appId);
 		sysPermission.setBusiness(business);
 		sysPermission.setPermission(permission);
-		System.out.println(type);
-		System.out.println(sysPermission);
 
 		try{
 			List<SysPermissionReportVO> list = new ArrayList<>();
 			if("role".equals(type)){
 				 list = sysPermissionService.reportRole(sysPermission);
-				System.out.println(list);
 			}else {
 				list = sysPermissionService.reportUser(sysPermission);
-				System.out.println(list);
 			}
 
 			result.setResult(list);
@@ -816,7 +803,12 @@ public class SysPermissionController {
 						.eq(SysUserPermission::getUserId,userId);
 				SysUserPermission sysUserPermission = sysUserPermissionService.getOne(query);
 				if(sysUserPermission ==null) {
-					return Result.error("请先保存用户菜单权限!");
+					String permission= sysUserPermissionService.getOneByUserId(userId, permissionId);
+					if (permission == null){
+						return Result.error("请先保存用户菜单权限!");
+					}
+					SysUserPermission newUserPermission = new SysUserPermission(userId, permissionId).setDataRuleIds(dataRuleIds).setOperateDate(new Date());
+					sysUserPermissionService.save(newUserPermission);
 				}else {
 					sysUserPermission.setDataRuleIds(dataRuleIds);
 					this.sysUserPermissionService.updateById(sysUserPermission);

+ 68 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java

@@ -18,6 +18,7 @@ import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.PermissionData;
 import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.config.TenantContext;
 import org.jeecg.common.constant.CommonConstant;
@@ -113,6 +114,32 @@ public class SysRoleController {
 		result.setResult(pageList);
 		return result;
 	}
+	/**
+	 * 分页列表查询 【系统角色,通过应用隔离】
+	 * @param role
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	@RequiresPermissions("system:role:list")
+	@PermissionData
+	@RequestMapping(value = "/listByApp", method = RequestMethod.GET)
+	public Result<IPage<SysRole>> listByApp(SysRole role,
+												@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+												@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+												HttpServletRequest req) {
+		Result<IPage<SysRole>> result = new Result<IPage<SysRole>>();
+		QueryWrapper<SysRole> queryWrapper = QueryGenerator.initQueryWrapper(role, req.getParameterMap());
+		String s = QueryGenerator.installAuthJdbc(SysRole.class);
+		queryWrapper.orderByDesc("create_time");
+		Page<SysRole> page = new Page<SysRole>(pageNo, pageSize);
+		IPage<SysRole> pageList = sysRoleService.page(page, queryWrapper);
+
+		result.setSuccess(true);
+		result.setResult(pageList);
+		return result;
+	}
 	
 	/**
 	 * 分页列表查询【租户角色,做租户隔离】
@@ -340,6 +367,47 @@ public class SysRoleController {
 		}
 		return result;
 	}
+
+	/**
+	 * 查询全部系统角色(根据应用分组)
+	 * @return
+	 */
+	@RequiresPermissions("system:role:queryallGroupByApp")
+	@RequestMapping(value = "/queryallGroupByApp", method = RequestMethod.GET)
+	public Result<List<Map>> queryallGroupByApp() {
+		Result<List<Map>> result = new Result<>();
+		List<SysRole> list = sysRoleService.listAllSysRoleNoPage();
+		if(list==null||list.size()<=0) {
+			result.error500("未找到角色信息");
+		}else {
+			List<Map> objects = new ArrayList<>();
+			Map<String, List<SysRole>> listMap = list.stream().collect(Collectors.groupingBy(SysRole::getAppId));
+			listMap.forEach((appId, roleList) -> {
+				Map<String, Object> map = new HashMap<>();
+				List<Map<String, String>> extractedList = roleList.stream()
+						.map(sysRole -> {
+							Map<String, String> roleInfo = new HashMap<>();
+							roleInfo.put("value", sysRole.getId());
+							roleInfo.put("label", sysRole.getRoleName());
+							return roleInfo;
+						})
+						.collect(Collectors.toList());
+				map.put("label",roleList.get(0).getAppName());
+//				map.put("value",appId);
+				map.put("roleList", extractedList);
+				objects.add(map);
+			});
+			//排序,基础平台永远在首位
+			List<Map> resultList = new ArrayList<>();
+			objects.stream().filter(map -> "基础平台".equals(map.get("label")))
+					.forEach(resultList::add);
+			objects.stream().filter(map -> !"基础平台".equals(map.get("label")))
+					.forEach(resultList::add);
+			result.setResult(resultList);
+			result.setSuccess(true);
+		}
+		return result;
+	}
 	
 	/**
 	  * 校验角色编码唯一

+ 1 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/AppmanageEntity/AppEnvInfo.java

@@ -15,7 +15,7 @@ import lombok.Data;
 public class AppEnvInfo {
     @TableId
     private String id;
-    private String appId;
+    private String appid;
     private String leadingIp;
     private String backendIp;
     private String backupFrequency;

+ 8 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/AppmanageEntity/AppUserInfo.java

@@ -18,5 +18,12 @@ public class AppUserInfo {
     private String id;
     private String appid;
     private String userid;
-    private String roles;
+
+    public AppUserInfo() {
+    }
+
+    public AppUserInfo(String appid, String userid) {
+        this.appid = appid;
+        this.userid = userid;
+    }
 }

+ 1 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java

@@ -28,6 +28,7 @@ public interface SysPermissionMapper extends BaseMapper<SysPermission> {
 	 */
 	public List<TreeModel> queryListByParentId(@Param("parentId") String parentId);
 	public List<SysPermission> listAndAppName( SysPermission sysPermission) ;
+	public List<SysPermission> listAndAppNameWithPermission( @Param("permission")SysPermission sysPermission,@Param("permissionSql")String permissionSql);
 	public List<AppBaseInfo> appList();
 	/**
 	 * 根据用户查询用户权限

+ 5 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java

@@ -28,7 +28,8 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
      */
     @InterceptorIgnore(tenantLine = "true")
     List<SysRole> listAllSysRole(@Param("page") Page<SysRole> page, @Param("role") SysRole role);
-
+    //查询全部的角色(不分页)
+    List<SysRole> listAllSysRoleNoPage();
     /**
      * 查询角色是否存在不做租户隔离
      *
@@ -78,4 +79,7 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
     List<SysRole> listExport(@Param("role") SysRole role);
 
     List<String> listRoleIdsByAppId(@Param("appId") String appId);
+
+    //根据角色ids查询appids并去重
+    List<String> listAppIdsByRoleIds(@Param("roleIds") String[] roleIds);
 }

+ 2 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysUserPermissionMapper.java

@@ -20,4 +20,6 @@ public interface SysUserPermissionMapper extends BaseMapper<SysUserPermission> {
      * @return List<SysPermission>
      */
     public List<String> listByUser(@Param("userId") String userId);
+
+    String getOneByUserId(@Param("userId")String userId, @Param("permissionId")String permissionId);
 }

+ 44 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml

@@ -80,6 +80,50 @@
 			ORDER BY p.sort_no ASC
 
 
+	</select>
+
+	<!--查询权限列表并添加app名称(数据权限)-->
+	<select id="listAndAppNameWithPermission" parameterType="Object"  resultMap="SysPermission">
+		SELECT  p.id,
+		p.parent_id,
+		p.name,
+		p.app_id,
+		p.url,
+		p.component,
+		p.is_route ,
+		p.component_name,
+		p.redirect,
+		p.menu_type,
+		p.perms,
+		p.perms_type,
+		p.sort_no,
+		p.always_show,
+		p.icon,
+		p.is_leaf,
+		p.keep_alive,
+		p.hidden,
+		p.hide_tab,
+		p.rule_flag,
+		p.status,
+		p.internal_or_external,
+		sa.name AS app_name
+		FROM
+		sys_permission p
+		INNER JOIN
+		app_base_info sa ON p.app_id = sa.id
+		WHERE p.del_flag = #{permission.delFlag}
+		<if test="permissionSql !=null and permissionSql != ''">
+			${permissionSql}
+		</if>
+		<if test="permission.name !=null and permission.name != ''">
+			AND p.name LIKE CONCAT('%', #{permission.name},'%')
+		</if>
+		<if test="permission.appId !=null and permission.appId != ''">
+			AND ( p.app_id = #{permission.appId})
+		</if>
+		ORDER BY p.sort_no ASC
+
+
 	</select>
 	
 	<select id="queryListByParentId" parameterType="Object"  resultMap="TreeModel">

+ 17 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml

@@ -22,6 +22,14 @@
         </if>
         order by r.create_time desc
     </select>
+    <select id="listAllSysRoleNoPage" resultType="org.jeecg.modules.system.entity.SysRole">
+        SELECT * ,
+        sa.name as app_name
+        from sys_role r
+        INNER JOIN
+        app_base_info sa ON r.app_id = sa.id
+        order by r.create_time desc
+    </select>
    
 
     <select id="getRoleNoTenant" resultType="org.jeecg.modules.system.entity.SysRole">
@@ -68,4 +76,13 @@
             SELECT id from sys_role
             WHERE app_id = #{appId}
     </select>
+
+    <!-- 根据角色ids查询appids并去重-->
+    <select id="listAppIdsByRoleIds"  resultType="java.lang.String">
+        SELECT DISTINCT app_id FROM sys_role
+        WHERE id IN
+        <foreach item="item" index="index" collection="roleIds" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
 </mapper>

+ 22 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPermissionMapper.xml

@@ -21,4 +21,26 @@
             WHERE up.user_id =#{userId}
         </if>
     </select>
+
+    <select id="getOneByUserId" parameterType="map" resultType="java.lang.String">
+        SELECT
+            permission_id
+        FROM
+            sys_user_permission
+        WHERE
+            user_id = #{userId}
+          AND permission_id = #{permissionId}
+
+        UNION
+        SELECT
+            rp.permission_id
+        FROM
+            sys_user_role ur
+                LEFT JOIN sys_role_permission rp ON ur.role_id = rp.role_id
+        WHERE
+            ur.user_id = #{userId}
+          AND rp.permission_id = #{permissionId}
+
+    </select>
+
 </mapper>

+ 0 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/AppmanageService.java

@@ -59,6 +59,5 @@ public interface AppmanageService {
     // 是否为应用管理员或开发负责人、运维负责人
     boolean isAppAdminOrDevOrOpe(String appid);
 
-    boolean addAppUserRoleInfos(SysUserRole sysUserRole);
 }
 

+ 1 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysPermissionService.java

@@ -31,6 +31,7 @@ public interface ISysPermissionService extends IService<SysPermission> {
 	public List<TreeModel> queryListByParentId(String parentId);
 //	public List<SysPermission> joinList(MPJLambdaWrapper<SysPermission> querywrapper);
 	public List<SysPermission> listAndAppName( SysPermission sysPermission);
+	public List<SysPermission> listAndAppNameWithPermission( SysPermission sysPermission);
 	public List<AppBaseInfo> appList();
 	/**
      * 真实删除

+ 2 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java

@@ -28,7 +28,8 @@ public interface ISysRoleService extends IService<SysRole> {
      * @return
      */
     Page<SysRole> listAllSysRole(@Param("page") Page<SysRole> page, SysRole role);
-
+    //查询全部的角色(不分页)
+    List<SysRole> listAllSysRoleNoPage();
     /**
      * 查询角色是否存在不做租户隔离
      *

+ 2 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserPermissionService.java

@@ -29,4 +29,6 @@ public interface ISysUserPermissionService extends IService<SysUserPermission> {
      * @param lastPermissionIds
      */
     public void saveUserPermission(String userId,String permissionIds,String lastPermissionIds);
+
+    String getOneByUserId(String userId, String permissionId);
 }

+ 57 - 66
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AppmanageServiceImpl.java

@@ -1,10 +1,13 @@
 package org.jeecg.modules.system.service.impl;
 
 import cn.hutool.system.UserInfo;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.system.controller.SysUserController;
 import org.jeecg.modules.system.entity.*;
 import org.jeecg.modules.system.entity.AppmanageEntity.*;
@@ -29,6 +32,8 @@ import java.util.stream.Collectors;
 @Service
 public class AppmanageServiceImpl implements AppmanageService {
 
+    @Autowired
+    private BaseCommonService baseCommonService;
 
     // 操作用户与角色关系的(授予角色,撤销角色)
     @Autowired
@@ -130,7 +135,6 @@ public class AppmanageServiceImpl implements AppmanageService {
             AppUserInfo userInfo = new AppUserInfo();
             userInfo.setAppid(appid);
             userInfo.setUserid(userid);
-            userInfo.setRoles(roleid);
             useridlist.add(userid);
             userInfoMapper.insert(userInfo);
         });
@@ -145,8 +149,10 @@ public class AppmanageServiceImpl implements AppmanageService {
         SysPermission sysPermission = new SysPermission();
         // 设置菜单名称即为应用名称
         sysPermission.setName(appBaseInfo.getName());
-        // 设置菜单权限编码
-        sysPermission.setPerms("sys:appmanage:enter:"+sysPermission.getName());
+        // 设置菜单所属应用
+        sysPermission.setAppId(appid);
+//        // 设置菜单权限编码
+//        sysPermission.setPerms("sys:appmanage:enter:"+sysPermission.getName());
         // 设置菜单路径
         sysPermission.setUrl(appBaseInfo.getMenuInfo());
         // 设置组件(即 菜单路径去掉第一个 "/")
@@ -171,7 +177,7 @@ public class AppmanageServiceImpl implements AppmanageService {
         if (!appInfo.getAppEnvInfoDTO().isEmpty()){
             System.out.println("环境信息不为空");
             for (AppEnvInfo appEnvInfo : appInfo.getAppEnvInfoDTO()){
-                appEnvInfo.setAppId(appid);
+                appEnvInfo.setAppid(appid);
                 envInfoMapper.insert(appEnvInfo);
             }
         }
@@ -183,46 +189,52 @@ public class AppmanageServiceImpl implements AppmanageService {
     }
 
     /**
-     * 删除应用信息
+     * 删除应用信息 - 将会删除属于该应用的角色信息、菜单信息
      * @param ids 应用id集合
      * @return
      */
+    @Transactional
     @Override
     public Boolean deleteAppInfo(String[] ids) {
         // 需先判断用户是否拥有所删除的应用信息的权限(平台管理员-应用管理员)
         // 获取当前登录用户信息
         LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-        QueryWrapper<AppBaseInfo> baseInfoPOQueryWrapper = new QueryWrapper<>();
+
         // 查询当前应用的应用管理员信息
-        if (ids.length == 1){  // 删除单条信息时
-            baseInfoPOQueryWrapper.select("admin").in("id", ids[0]);
-            AppBaseInfo appBaseInfo = baseInfoMapper.selectOne(baseInfoPOQueryWrapper);
-            if (!appBaseInfo.getAdmin().equals(loginUser.getId())) return false;
-        }else {  //  批量删除应用信息时,如果有一个应用不是当前登录用户所创建,则返回false
-            for (String id : ids) {
-                AppBaseInfo appBaseInfo = baseInfoMapper.selectById(id);
-                if (!appBaseInfo.getAdmin().equals(loginUser.getId())) return false;
-            }
-        }
         for (String id : ids) {
             // 不能删除基础平台的应用信息
             if (id.equals("0")) return false;
+            AppBaseInfo appBaseInfo = baseInfoMapper.selectById(id);
+            if (!(appBaseInfo.getAdmin().equals(loginUser.getId()))) return false;
 
             // 删除所属该应用的基础信息、环境信息、文档信息、用户信息
             baseInfoMapper.deleteById(id);
             envInfoMapper.delete(new QueryWrapper<AppEnvInfo>().eq("appid", id));
             docInfoMapper.delete(new QueryWrapper<AppDocInfo>().eq("appid", id));
+            // 简易注册下的应用信息不具备用户、菜单、权限等信息,所有不需要删除
+            if (appBaseInfo.getAddType().equals("easy")) break;
             userInfoMapper.delete(new QueryWrapper<AppUserInfo>().eq("appid", id));
 
             // 删除该应用下所创建的菜单
-//            List<SysPermission> sysPermissions = sysPermissionService(loginUser.getUsername());
-//            String permissionsid = sysPermissions.stream().filter(permission -> permission.getAppId().equals(id)).findFirst().get().getId();
-//            sysPermissionService.deletePermission(permissionsid);
+            // 查询该应用的一级菜单
+            LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
+            query.eq(SysPermission::getMenuType,CommonConstant.MENU_TYPE_0);
+            query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0);
+            query.eq(SysPermission::getAppId, id);
+            List<SysPermission> list = sysPermissionService.list(query);
+            for (SysPermission sysPermission : list){
+                sysPermissionService.deletePermission(sysPermission.getId());
+            }
 
             // 删除该应用下所创建的角色信息
-//            sysRoleService.listRoleIdsByAppId()
-
+            String[] Approleids = sysRoleService.listRoleIdsByAppId(id);
+            if (Approleids!=null){
+                boolean tag = sysRoleService.deleteBatchRole(Approleids);
+                if (!tag) return false;
+            }
         }
+        // 记录日志
+        baseCommonService.addLog("删除应用信息:id"+Arrays.toString(ids), CommonConstant.LOG_TYPE_2, 3 );
         return true;
     }
 
@@ -252,7 +264,7 @@ public class AppmanageServiceImpl implements AppmanageService {
             for (AppEnvInfo appEnvInfo : envInfo) {
                 // 如果没有id信息,则为新增的数据
                 if (appEnvInfo.getId()==null){
-                    appEnvInfo.setAppId(appid);
+                    appEnvInfo.setAppid(appid);
                     envInfoMapper.insert(appEnvInfo);
                 }else { // 有id信息则为在原有数据基础上需修改的数据
                     envInfoMapper.updateById(appEnvInfo);
@@ -281,20 +293,22 @@ public class AppmanageServiceImpl implements AppmanageService {
     @Transactional
     public Boolean editUserInfo(AppUpdataUserInfo updataUserInfo) {
         String appid = updataUserInfo.getAppid();
-        // 删除用户 删除应用用户默认权限
+        // 移除应用用户时,将去角色收回
         if (updataUserInfo.getDelUserids()!=null&&!updataUserInfo.getDelUserids().isEmpty()){
             updataUserInfo.getDelUserids().forEach(userid -> {
                 System.out.println("删除用户:"+userid);
+                // 获取要移除的用户的信息
                 QueryWrapper<AppUserInfo> userInfoPOQueryWrapper = new QueryWrapper<>();
                 userInfoPOQueryWrapper.eq("appid",appid).eq("userid",userid);
-                AppUserInfo userInfoPO = userInfoMapper.selectOne(userInfoPOQueryWrapper);
-                // 先去除字符串两端的空格
-                String userDefaultRoleId = userInfoPO.getRoles().trim();
-                // 根据逗号分割字符串
-                String[] parts = userDefaultRoleId.split(",");
-                QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<SysUserRole>();
-                queryWrapper.eq("role_id", parts[0]).eq("user_id",userid);
-                sysUserRoleService.remove(queryWrapper);
+                AppUserInfo userInfo = userInfoMapper.selectOne(userInfoPOQueryWrapper);
+                // 获取该用户在该应用下的角色信息
+                List<String> roleIds = sysUserRoleService.listByAppId(appid, userid);
+                // 删除该用户在该应用下的角色信息
+                roleIds.forEach(roleId -> {
+                    QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<SysUserRole>();
+                    queryWrapper.eq("role_id", roleId).eq("user_id",userid);
+                    sysUserRoleService.remove(queryWrapper);
+                });
                 QueryWrapper<AppUserInfo> wrapper = new QueryWrapper<>();
                 wrapper.eq("appid",updataUserInfo.getAppid()).eq("userid",userid);
                 userInfoMapper.delete(wrapper);
@@ -392,7 +406,7 @@ public class AppmanageServiceImpl implements AppmanageService {
     @Override
     public List<AppEnvInfo> queryEnvInfoByAppId(String appid) {
         List<AppEnvInfo> envInfos = envInfoMapper.
-                selectList(new QueryWrapper<AppEnvInfo>().eq("app_id", appid));
+                selectList(new QueryWrapper<AppEnvInfo>().eq("appid", appid));
         return envInfos;
     }
 
@@ -450,25 +464,22 @@ public class AppmanageServiceImpl implements AppmanageService {
                 AppBaseInfo appBaseInfo = baseInfoMapper.selectById(queryParams.getAppid());
                 // 查询用户角色信息
                 appUserInfos.forEach(map -> {
-                    QueryWrapper<AppUserInfo> appUserInfoQueryWrapper = new QueryWrapper<>();
-                    appUserInfoQueryWrapper.select("roles")
-                            .eq("userid", map.get("id")).eq("appid", queryParams.getAppid());
-                    AppUserInfo roleInfo = userInfoMapper.selectOne(appUserInfoQueryWrapper);
-                    // 查询应用基础信息的相关用户信息
                     String roleNameInfo = baseInfoToUserInfoRoles(appBaseInfo, (String) map.get("id"));
-                    // 使用 Stream API 将字符串转换为 List
-                    if (roleInfo!=null){
-                        // 将应用用户表中存的的角色信息字符串转换为List
-                        List<String> list = Arrays.stream(roleInfo.getRoles().split(","))
-                                .collect(Collectors.toList());
-                        QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
-                        sysRoleQueryWrapper.select("role_name").in("id", list);
+                    List<String> roleIds = sysUserRoleService.listByAppId(queryParams.getAppid(), (String) map.get("id"));
+
+                    if (!roleIds.isEmpty()){
                         // 查询角色名信息
+                        QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
+                        sysRoleQueryWrapper.select("role_name").in("id", roleIds);
                         List<SysRole> sysRoles = sysRoleMapper.selectList(sysRoleQueryWrapper);
                         if (!sysRoles.isEmpty()&&!roleNameInfo.isEmpty()){
                             roleNameInfo =roleNameInfo +", "+ sysRoles.stream()
                                     .map(SysRole::getRoleName)
                                     .collect(Collectors.joining(", "));
+                        }else {
+                            roleNameInfo = sysRoles.stream()
+                                    .map(SysRole::getRoleName)
+                                    .collect(Collectors.joining(", "));
                         }
                     }
                     map.put("roles", roleNameInfo);
@@ -599,28 +610,6 @@ public class AppmanageServiceImpl implements AppmanageService {
         return false;
     }
 
-    /**
-     * 角色分配用户时添加应用用户角色信息
-     * @param sysUserRole
-     */
-    @Override
-    public boolean addAppUserRoleInfos(SysUserRole sysUserRole){
-        // 根据角色id查询所属的应用id
-        SysRole sysRole = sysRoleMapper.selectById(sysUserRole.getRoleId());
-        String appid = sysRole.getAppId();
-        QueryWrapper<AppUserInfo> appUserInfoQueryWrapper = new QueryWrapper<>();
-        // 先查询应用用户原来的角色信息,若为空,则直接更新,若不为空,将原角色信息与新的角色信息进行拼接后再更新,新旧角色id信息通过逗号分隔的字符串
-        appUserInfoQueryWrapper.eq("appid",appid).eq("userid",sysUserRole.getUserId());
-        AppUserInfo appUserInfo = userInfoMapper.selectOne(appUserInfoQueryWrapper);
-        String appUserRolesInfo = appUserInfo.getRoles();
-        if (appUserRolesInfo!=null){
-            appUserInfo.setRoles(appUserRolesInfo+","+sysUserRole.getRoleId());
-        }else {
-            appUserInfo.setRoles(sysUserRole.getRoleId());
-        }
-        int i = userInfoMapper.updateById(appUserInfo);
-        return i>0;
-    }
 
     private String baseInfoToUserInfoRoles(AppBaseInfo appBaseInfo, String userid){
         String roleNameInfo = "";
@@ -657,4 +646,6 @@ public class AppmanageServiceImpl implements AppmanageService {
         }
         return roleNameInfo;
     }
+
+
 }

+ 23 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.jeecg.common.constant.CacheConstant;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
 import org.jeecg.modules.system.entity.AppmanageEntity.AppBaseInfo;
@@ -29,6 +30,8 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * <p>
@@ -76,7 +79,26 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
 	public List<SysPermission> listAndAppName( SysPermission sysPermission) {
 		return sysPermissionMapper.listAndAppName(sysPermission);
 	}
-
+	public List<SysPermission> listAndAppNameWithPermission( SysPermission sysPermission) {
+		String sql = QueryGenerator.installAuthJdbc(SysPermission.class);
+		//处理sql格式,避免注入风险
+		//只对应用进行数据隔离
+		if (sql!= null){
+			String modifiedSql = modifySql(sql);
+			sql = modifiedSql;
+		}
+		return sysPermissionMapper.listAndAppNameWithPermission(sysPermission,sql);
+	}
+	public static String modifySql(String sql) {
+		String regex ="(?i)\\s+AND\\s+";
+		String modiSQL = "";
+		for (String s : sql.split(regex)) {
+			if(s.trim().length()>0){
+				modiSQL += " AND p."+s.trim();
+			}
+		}
+		return modiSQL;
+	}
 	@Override
 	public List<AppBaseInfo> appList() {
 		return sysPermissionMapper.appList();

+ 4 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysRoleServiceImpl.java

@@ -44,6 +44,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
     public Page<SysRole> listAllSysRole(Page<SysRole> page, SysRole role) {
         return page.setRecords(sysRoleMapper.listAllSysRole(page,role));
     }
+    @Override
+    public List<SysRole> listAllSysRoleNoPage() {
+        return sysRoleMapper.listAllSysRoleNoPage();
+    }
 
     @Override
     public SysRole getRoleNoTenant(String roleCode,String appId) {

+ 4 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserPermissionServiceImpl.java

@@ -119,4 +119,8 @@ public class SysUserPermissionServiceImpl extends ServiceImpl<SysUserPermissionM
         return res;
     }
 
+    @Override
+    public String getOneByUserId(String userId, String permissionId) {
+        return sysUserPermissionMapper.getOneByUserId(userId,permissionId);
+    }
 }

+ 11 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java

@@ -38,6 +38,7 @@ import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
 import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.modules.message.handle.impl.SystemSendMsgHandle;
 import org.jeecg.modules.system.entity.*;
+import org.jeecg.modules.system.entity.AppmanageEntity.AppUserInfo;
 import org.jeecg.modules.system.mapper.*;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
 import org.jeecg.modules.system.service.ISysRoleIndexService;
@@ -87,7 +88,9 @@ import java.util.stream.Collectors;
 @Service
 @Slf4j
 public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
-	
+
+	@Autowired
+	private AppUserInfoMapper appUserInfoMapper;
 	@Autowired
 	private SysUserMapper userMapper;
 	@Autowired
@@ -854,7 +857,14 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 				SysUserRole userRole = new SysUserRole(user.getId(), roleId);
 				sysUserRoleMapper.insert(userRole);
 			}
+			//step.2.5 保存应用关系
+			List<String> sysRoles = sysRoleMapper.listAppIdsByRoleIds(arr);
+			for (String appId : sysRoles){
+				AppUserInfo appUserInfo = new AppUserInfo(appId,user.getId());
+				appUserInfoMapper.insert(appUserInfo);
+			}
 		}
+
 		
 		//step.3 保存所属部门
 		if(oConvertUtils.isNotEmpty(selectedDeparts)) {

+ 9 - 6
jeecg-boot/jeecg-server-cloud/docker-compose.yml

@@ -50,11 +50,6 @@ services:
     hostname: jeecg-boot-gateway
     networks:
       - jeecg-boot
-
-networks:
-  jeecg-boot:
-    name: jeecg_boot
-
 #  jeecg-boot-sentinel:
 #    restart: on-failure
 #    build:
@@ -68,7 +63,8 @@ networks:
 #      - jeecg-boot-gateway
 #    container_name: jeecg-boot-sentinel
 #    hostname: jeecg-boot-sentinel
-#
+#    networks:
+#      - jeecg-boot
 #  jeecg-boot-xxljob:
 #    build:
 #      context: ./jeecg-visual/jeecg-cloud-xxljob
@@ -76,3 +72,10 @@ networks:
 #      - 9080:9080
 #    container_name: jeecg-boot-xxljob
 #    hostname: jeecg-boot-xxljob
+#    networks:
+#      - jeecg-boot
+networks:
+  jeecg-boot:
+    name: jeecg_boot
+
+

+ 2 - 2
jeecg-boot/jeecg-server-cloud/jeecg-cloud-nacos/src/main/resources/application.yml

@@ -13,9 +13,9 @@ spring:
 db:
   num: 1
   password:
-    '0': ${MYSQL-PWD:root}
+    '0': ${MYSQL-PWD:Lttc123!}
   url:
-    '0': jdbc:mysql://${MYSQL-HOST:jeecg-boot-mysql}:${MYSQL-PORT:3306}/${MYSQL-DB:nacos}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
+    '0': jdbc:mysql://${MYSQL-HOST:10.200.1.115}:${MYSQL-PORT:3306}/${MYSQL-DB:luthai-basis-platform-nacos}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
   user:
     '0': ${MYSQL-USER:root}
 management:

+ 2 - 2
jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/resources/application.yml

@@ -5,9 +5,9 @@ server:
   #数据源配置
 spring:
   datasource:
-    url: jdbc:mysql://jeecg-boot-mysql:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+    url: jdbc:mysql://10.200.1.115:3306/luthai-basis-platform-xxl-job?Unicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
     username: ${MYSQL-USER:root}
-    password: ${MYSQL-PWD:root}
+    password: ${MYSQL-PWD:Lttc123!}
     driver-class-name: com.mysql.jdbc.Driver
     type: com.zaxxer.hikari.HikariDataSource
     hikari:

+ 2 - 2
jeecgboot-vue3/Dockerfile

@@ -5,9 +5,9 @@ ENV LANG en_US.UTF-8
 RUN echo "server {  \
                       listen       80; \
                       location   /jeecgboot/ { \
-                      proxy_pass              http://jeecg-boot-system:8080/jeecg-boot/; \
+                      proxy_pass              http://10.200.1.115:9999/; \
                       proxy_redirect          off; \
-                      proxy_set_header        Host jeecg-boot-system; \
+                      proxy_set_header        Host jeecg-boot-gateway; \
                       proxy_set_header        X-Real-IP \$remote_addr; \
                       proxy_set_header        X-Forwarded-For \$proxy_add_x_forwarded_for; \
                   } \

+ 17 - 0
jeecgboot-vue3/docker-compose.yml

@@ -0,0 +1,17 @@
+version: '3.8'
+
+services:
+  jeecgboot-vue3-nginx:
+    image: jeecgboot-vue3
+    build:
+      context: .
+    container_name: jeecgboot-vue3-nginx
+    networks:
+      - jeecg_boot
+    ports:
+      - "80:80"
+    restart: always
+
+networks:
+  jeecg_boot:
+    external: true

+ 6 - 1
jeecgboot-vue3/src/views/appmanage/AppBaseInfo.api.ts

@@ -30,8 +30,13 @@ enum Api {
     getAppuserids = '/sys/applicationInfo/getAppuserids',
     isInfoUser = '/sys/applicationInfo/isInfoUser',
     isAppAdminOrDevOrOpe = '/sys/applicationInfo/isAppAdminOrDevOrOpe',
-    isAppAdmin = '/sys/applicationInfo/isAppAdmin'
+    isAppAdmin = '/sys/applicationInfo/isAppAdmin',
+    checkMenuInfoisExist = '/sys/permission/checkPermDuplication'
 }
+export const checkMenuInfoisExist=(params)=>{
+    return defHttp.get({url: Api.checkMenuInfoisExist+"?url="+params+"&alwaysShow="+false},  { errorMessageMode: false, successMessageMode: false })
+}
+
 export const isAppAdmin=()=>{
   return defHttp.get({url: Api.isAppAdmin})
 }

+ 12 - 8
jeecgboot-vue3/src/views/appmanage/AppInfoList.vue

@@ -65,7 +65,8 @@
         <div style="height: 50vh" v-if="isLoading"></div>
       </a-spin>
         <div v-show="!isLoading">
-          <FormStepPage v-if="modalVisible" ref="addForm" @closeModal="closeModal" :addType="addType" :addFormDraftData="addFormDraftData"/>
+          <FormStepPage v-if="modalVisible" ref="addForm" @closeModal="closeModal" :addType="addType"
+                        :addFormDraftData="addFormDraftData" test="123"/>
         </div>
     </a-modal>
 
@@ -230,7 +231,7 @@ import BaseInfoFrom from '@/views/appmanage/addForm/Step1.vue'
 import EnvInfoFrom from '@/views/appmanage/addForm/Step2.vue'
 import DocInfoFrom from '@/views/appmanage/addForm/Step3.vue'
 import UserInfoFrom from '@/views/appmanage/addForm/Step4.vue'
-import { message } from 'ant-design-vue';
+import { message, Modal } from 'ant-design-vue';
 import Description from '@/components/Description/src/Description.vue'
 import { useDescription } from '/@/components/Description';
 import {menuInfoisshow} from "@/views/appmanage/addForm/data";
@@ -258,14 +259,13 @@ const addFormDraftData = ref({
   base: {},
   env:{},
   doc:{},
-  user:{},
+  userInfo:{},
   current: 0
 })  // 添加表单草稿数据,存储添加至一半时关闭表单且已填入的数据
+const draftUserInfo = ref()
 
 type Key = string | number;
 
-
-
 interface FormState {
   appname: string;
   apptype: string;
@@ -322,6 +322,7 @@ export default defineComponent({
 
   async created() {
     console.log("创建完成啦啦啦")
+    // 清除草稿数据缓存
     columns.value = listColumns2
     const isInfoDeptUser = await isInfoUser()
     isInfoDeptUserTag.value = isInfoDeptUser
@@ -361,6 +362,7 @@ export default defineComponent({
         case 'isAdd':
           console.log("主页面关闭添加表单事件")
           addFormDraftData.value = value.data
+          console.log("关闭注册对话框时存储的草稿数据")
           console.dir(addFormDraftData)
           modalVisible.value = false;
           break;
@@ -590,11 +592,11 @@ export default defineComponent({
     handleAdd(isaddType) {
       isLoading.value = true
       let time = isaddType === 'full'? 1500:1000
-      console.log("time:"+time)
       addType.value = isaddType
+      console.log("点击注册时查看草稿数据")
+      console.dir(addFormDraftData)
       menuInfoisshow.value = isaddType === 'full';
       setTimeout(function (){
-        console.log("step1变成false了")
         isLoading.value = false
       },time)
       modalVisible.value = true;
@@ -602,6 +604,7 @@ export default defineComponent({
   },
 
   setup() {
+
     const [descriPtionregister] = useDescription({
       schema: Appdescschema,
     });
@@ -703,7 +706,8 @@ export default defineComponent({
 }
 
 .detail{
-  height: 70vh;
+  height: auto;
+  max-height: 70vh;
   overflow-y: auto;
 }
 </style>

+ 12 - 9
jeecgboot-vue3/src/views/appmanage/addForm/Step2.vue

@@ -337,19 +337,22 @@
           delids.value = []
         })
       },
-    },
 
-    emits: ['next', 'prev', 'closeModal'],
-    setup(_, { emit }) {
-      async function customResetFunc() {
+      async customResetFunc() {
         console.log("上一页")
-        emit('prev');
+        this.assmblyData()
+        this.$emit('prev',envData);
       }
-
-      return {
-        customResetFunc
-      };
     },
+    //
+    // emits: ['next', 'prev', 'closeModal'],
+    // setup(_, { emit }) {
+    //
+    //
+    //   return {
+    //
+    //   };
+    // },
   });
 </script>
 <style lang="less" scoped>

+ 71 - 86
jeecgboot-vue3/src/views/appmanage/addForm/Step4.vue

@@ -38,23 +38,41 @@
       <div class="appUserOperateitem">
         <a-button @click="clearConditionAndData">重 置</a-button>
       </div>
-      <div class="appUserOperateitem" style="margin-left: 15%">
+      <div>
+      <!-- 作为编辑页面时显示   -->
+      <a-button type="primary"
+                :disabled="adduserCount===0"
+                @click="removeUserInfo('edit')"
+                v-if="!tag"  v-show="!uncheckTag">移 除</a-button>
+      </div>
+      <!-- 作为编辑页面时显示  -->
+      <div class="appUserOperateitem" style="margin-left: 10%">
+        <span v-if="!tag" style="padding-right: 5%; white-space: nowrap"> <b>新增用户:{{(newlyUserData as any).length}}</b> </span>
         <a-button type="primary" :disabled="uncheckTag" @click="handleOpen" v-if="!uncheckTag&&!tag">添加用户</a-button>
         <AppUserSelectByDepModal ref="addNewUser" :rowKey="rowKey" v-if="!uncheckTag&&!tag"
                                  :appid="appid" :appuserids="appUserids" @register="regModal"
                                  @getSelectResult="setValue" v-bind="getBindValue"/>
-      </div>
+        <a-popconfirm
+            title="你确定要移除全部信息吗?"
+            ok-text="是"
+            cancel-text="否"
+            @confirm="removeAllUserInfo('editForm_newlyUserData')"
+            @cancel="cancel">
+          <a-button v-if="!tag" style="padding-right: 10%" v-show="(newlyUserData as any).length>0">全部移除</a-button>
+        </a-popconfirm>
 
-      <div class="appUserOperateitem">
         <!-- 作为添加页面时显示  -->
-        <a-button type="primary" :disabled="adduserCount===0"
-                  @click="removeUserInfo('add')"
-                  v-if="tag" >添 加</a-button>
-        <!-- 作为编辑页面时显示   -->
-        <a-button type="primary"
-                  :disabled="adduserCount===0"
-                  @click="removeUserInfo('edit')"
-                  v-if="!tag"  v-show="!uncheckTag">移 除</a-button>
+        <span v-if="tag" style="padding-right: 5%; white-space: nowrap"><b>已添加应用用户:{{(addForm_newlyUserData as any).length}}</b></span>
+        <a-button  v-if="tag" type="primary" :disabled="adduserCount===0" @click="removeUserInfo('add')">添 加</a-button>
+        <a-popconfirm
+            title="你确定要移除全部信息吗?"
+            ok-text="是"
+            cancel-text="否"
+            @confirm="removeAllUserInfo('addForm_newlyUserData')"
+            @cancel="cancel">
+        <a-button v-if="tag" style="padding-right: 10%" v-show="(addForm_newlyUserData as any).length>0">全部移除</a-button>
+        </a-popconfirm>
+
       </div>
     </div>
 
@@ -69,13 +87,8 @@
           <a-table :row-selection="rowSelection" :columns="columns"
                    :data-source="data" v-show="!uncheckTag||tag" size="small"
                     class="userTableClass" :pagination="pagination" @change="handleTableChange">
-            <template #bodyCell="{ column, record }">
-              <template v-if="column.dataIndex === 'editform_action'">
-                <a-button type="link" @click="openPermissionModal">授 权</a-button>
-                <a-modal :open="permissionTag">
-                  <AppPermissionTree  app-list=""/>
-                </a-modal>
-              </template>
+            <template #title>
+              <b>平台用户</b>
             </template>
           </a-table>
         </div>
@@ -86,11 +99,11 @@
         <div class="table_right" v-if="tag">
           <!-- 新增用户列表 -->
           <div class="table_top">
-            <div style="margin-bottom: 5px">
-              <b>已添加应用用户:{{(addForm_newlyUserData as any).length}}</b>
-              <a-button style="margin-left: 40%" v-show="(addForm_newlyUserData as any).length>0">全部移除</a-button>
-            </div>
-            <a-table :columns="addForm_newlyUsercolumns" :data-source="addForm_newlyUserData" :scroll="{y: 500}" :pagination="false" size="small">
+            <a-table :columns="addForm_newlyUsercolumns" :data-source="addForm_newlyUserData" :scroll="{y: 500}"
+                     :pagination="false" size="small" class="rightuserTableClass">
+              <template #title>
+                <b>将要加入该应用的用户</b>
+              </template>
               <template #bodyCell="{ column, record }">
                 <template v-if="column.dataIndex === 'action'">
                   <a-button type="link" @click="recoverNewlyOneUserInfo(record.key, 'add')">移 出</a-button>
@@ -104,10 +117,6 @@
         <div class="table_right" v-if="!tag&&!uncheckTag">
           <!-- 新增用户列表 -->
           <div class="table_top">
-            <div style="margin-bottom: 5px">
-              <span> <b>新增用户:{{(newlyUserData as any).length}}</b> </span>
-              <a-button style="margin-left: 40%" v-show="(newlyUserData as any).length>0">全部移除</a-button>
-            </div>
             <a-table :columns="newlyUsercolumns" :data-source="newlyUserData"
                      :scroll="{y: 230}" :pagination="false" size="small"
                       class="rightuserTableClass">
@@ -119,6 +128,8 @@
             </a-table>
           </div>
 
+          <div style="height: 1vh; width: 100%;"/>
+
           <!-- 移除用户列表 -->
           <div class="table_bottom">
             <a-table :columns="removeUsercolumns" :data-source="removeUserData"
@@ -126,11 +137,18 @@
                       class="rightuserTableClass">
               <template #title>
                 <b>移除用户:{{(removeUserData as any).length}}</b>
+                <a-popconfirm
+                    title="你确定要移除全部信息吗?"
+                    ok-text="是"
+                    cancel-text="否"
+                    @confirm="removeAllUserInfo('editForm_removeUserData')"
+                    @cancel="cancel">
                 <a-button style="margin-left: 40%" v-show="(removeUserData as any).length>0">全部移除</a-button>
+                </a-popconfirm>
               </template>
               <template #bodyCell="{ column, record }">
                 <template v-if="column.dataIndex === 'action'">
-                  <a-button type="link" @click="recoverRemoveOneUserInfo(record.key)">移 出</a-button>
+                  <a-button type="link" @click="recoverRemoveOneUserInfo(record.key)">恢 复</a-button>
                 </template>
               </template>
             </a-table>
@@ -155,17 +173,9 @@
       <a-button v-if="tag" type="primary" @click="addCheck">
         提交审核
       </a-button>
-<!--      <a-popconfirm-->
-<!--        v-if="removeUserData.length>0"-->
-<!--        title="注意!移除用户将同时移除该用户在该应用下的所有权限,是否继续?"-->
-<!--        ok-text="是"-->
-<!--        cancel-text="否"-->
-<!--        @confirm=""-->
-<!--        @cancel="">-->
         <a-button v-if="!tag&&isEdit" type="primary" @click="save" :disabled="uncheckTag">
           保 存
         </a-button>
-<!--      </a-popconfirm>-->
     </div>
 
     <!-- 提交审核事件二次确认 -->
@@ -363,48 +373,6 @@ export default defineComponent({
       await this.queryAppUserMethod(1)
     },
 
-    // 作为添加表单时使用,根据表单一所选用户的角色,将用户加入新增用户列表及授予相应的角色
-    async step1Tostep4DataRelationDeal(step1FormData){
-      console.log("表单四拿到表单一数据")
-      console.dir(step1FormData)
-      let step1userData = []
-      // 将右列表用户数据添加至
-      if (step1FormData.admin!=undefined) step1userData.push(step1FormData.admin)
-      if (step1FormData.businessUser!=undefined) step1userData.push(step1FormData.businessUser)
-      if (step1FormData.developUser!=undefined) step1userData.push(step1FormData.developUser)
-      if (step1FormData.operationUser!=undefined) step1userData.push(step1FormData.operationUser)
-      if (step1FormData.requirementUser!=undefined) step1userData.push(step1FormData.requirementUser)
-      const params = {
-        userids: step1userData
-      }
-      await queryAppUser(params).then(res=>{
-        console.log("表单四查询表单一填写的用户数据")
-        console.dir(res)
-        // 根据表单一所选用户,初始化表单四添加用户列表数据
-        addForm_newlyUserData.value.length = 0
-        res.userinfos.forEach(item=>{
-          const itemObj = {
-            key: item.id,
-            name: item.realname,
-            username: item.username,
-            sex: item.sex,
-            depart: item.dept.deptName,
-            roles: ''
-          }
-          addForm_newlyUserData.value.push(itemObj)
-        })
-      })
-      selectedRowKeys.value = step1userData
-      userData.value = step1userData
-      addForm_newlyUserData.value.forEach( item =>{
-        if (item.key === step1FormData.admin) item.roles = '应用管理员'
-        if (item.key === step1FormData.businessUser) item.roles = '业务对接人'
-        if (item.key === step1FormData.developUser) item.roles = '开发负责人'
-        if (item.key === step1FormData.operationUser) item.roles = '运维负责人'
-        if (item.key === step1FormData.requirementUser) item.roles = '需求对接人'
-      })
-    },
-
     transformTreeData(data) {
       return data.map(item => {
         const transformedItem = {
@@ -420,19 +388,19 @@ export default defineComponent({
     },
 
     // 初始化表单样式,判断是添加表单还是编辑表单
-    async initUserInfo(value, step1Values){
+    async initUserInfo(value){
       // 获取部门信息
       console.log("先看看这个value吧")
+      console.dir(value)
       const deptInfo = await queryTreeList()
       treeData.value = this.transformTreeData(deptInfo);
       tag.value = this.formType === 'isAdd'
       if (tag.value){                             // 作为添加表单的初始化
         console.log("表单四:作为添加表单的初始化")
         // 由于分页限制了data的大小,故需自己去查询表单一所添加的用户的信息
-        await this.step1Tostep4DataRelationDeal(step1Values)
+        // if (step1Values!=undefined) await this.step1Tostep4DataRelationDeal(step1Values)
         // 将左用户信息栏角色列去除
         columns.value = userTableSchemas.filter(item => item.dataIndex !== 'roles');// 应用用户表列配置
-        console.dir(value)
         try {
           if (value.value!==undefined) addForm_newlyUserData.value = value
         }catch (e){
@@ -453,7 +421,18 @@ export default defineComponent({
       modalVisible.value=false
     },
 
-    // 移除用户信息
+    // 全部移除 新增(添加)用户信息
+    removeAllUserInfo(tag){
+      console.log("执行了全部移除:"+tag)
+      // 全部移除新增表单将要加入该应用的用户列表数据
+      if (tag==='addForm_newlyUserData') addForm_newlyUserData.value.length = 0
+      if (tag==='editForm_newlyUserData') newlyUserData.value.length = 0
+      if (tag==='editForm_removeUserData') removeUserData.value.length = 0
+      this.queryAppUserMethod(this.pagination.current)
+    },
+
+
+    // 移除右列表信息
     removeUserInfo(isType){
       console.log("移除用户信息执行了");
       console.dir(userData);
@@ -467,6 +446,7 @@ export default defineComponent({
           isType==='edit'? removeUserData.value.push(dataObject) : addForm_newlyUserData.value.push(dataObject)
         }
       })
+      this.clearConditionAndData()
       console.dir(addForm_newlyUsercolumns)
       selectedRowKeys.value = []
       this.adduserCount = 0
@@ -530,7 +510,7 @@ export default defineComponent({
       if (this.formType === 'isAdd'){  // 处于添加表单下的关闭事件,需收集表单已填数据进行存储
         console.log("表单四添加状态下关闭")
         const obj = {
-          data: addForm_newlyUserData,
+          data: addForm_newlyUserData.value,
           info: 'user',
           type: 'isAdd'
         }
@@ -589,6 +569,9 @@ export default defineComponent({
   },
 
   setup(props, { emit }) {
+    const cancel = (e: MouseEvent) => {
+      message.error('取消移除');
+    };
 
     watch(deptInfovalue, () => {
       realnameSearchvalue.value = ''
@@ -709,7 +692,8 @@ export default defineComponent({
       setValue,
       getBindValue,
       deptInfovalue,
-      searchValue
+      searchValue,
+      cancel
     };
   },
 });
@@ -750,6 +734,7 @@ export default defineComponent({
   align-items: center; /* 垂直居中对齐 */
   justify-content: center; /* 水平居中对齐 */
   margin-right: 10px; /* 为每个 .item 添加右边距 */
+  gap: 10px;
 }
 
 .item:last-child {
@@ -790,12 +775,12 @@ export default defineComponent({
 }
 
 .userTableClass{
-  border-right: 1px solid #d9d9d9;
+  border: 1px solid #d9d9d9;
 }
 
 .rightuserTableClass{
   height: 29%;
-  border-left: 1px solid #d9d9d9;
+  border: 1px solid #d9d9d9;
 }
 /* 如果需要,可以在这里添加额外的样式 */
 

+ 55 - 0
jeecgboot-vue3/src/views/appmanage/addForm/data.tsx

@@ -1,9 +1,23 @@
 import { FormSchema } from '/@/components/Form';
 import {ref} from "vue";
+import {checkPermDuplication} from "@/views/system/menu/menu/menu.api";
+import {ComponentTypes} from "@/views/system/menu/menu/menu.data";
+import {checkMenuInfoisExist} from "@/views/appmanage/AppBaseInfo.api";
 
 
 export const menuInfoisshow = ref(false)
 
+
+export const checkMenuInfo = async (_rule, value, callback) => {
+  console.log("菜单value:" + value)
+  const res = await checkMenuInfoisExist(value)
+  if (res === '该值可用!') {
+    callback(); // 校验通过
+  } else {
+    callback(new Error(res)); // 校验失败
+  }
+};
+
 export const step1Schemas: FormSchema[] = [
   {
     field: 'name',
@@ -100,6 +114,11 @@ export const step1Schemas: FormSchema[] = [
     component: 'Input',
     label: '菜单信息',
     required: true,
+    ifShow: ({ values }) => !(values.component === ComponentTypes.IFrame && values.internalOrExternal),
+    rules:[{required: true, validator: checkMenuInfo, trigger: 'blur'}],
+    // dynamicRules: ({ model, schema, values }) => {
+    //   return checkPermDuplication(model, schema, values.menuType !== 2);
+    // },
     show: ()=>{
       return menuInfoisshow.value
     },
@@ -120,8 +139,38 @@ export const step1Schemas: FormSchema[] = [
     component: 'Input',
     show: false,
   },
+  {
+    field: 'alwaysShow',
+    label: '',
+    component: 'Switch',
+    defaultValue: false,
+    show: false
+  },
 ];
 
+
+const isValidIp = (_rule, value, callback) => {
+  if (!value) {
+    return callback(new Error('请输入 IP 地址'));
+  }
+  if (!isValidIpAddress(value)) {
+    return callback(new Error('请输入正确的 IP 地址格式'));
+  }
+  callback();
+};
+
+const isValidIpAddress = (ip) => {
+  const regex = /^(\d{1,3}\.){3}\d{1,3}$/;
+  const parts = ip.split('.');
+  if (parts.length !== 4) return false;
+  for (let part of parts) {
+    if (isNaN(part) || part < 0 || part > 255) {
+      return false;
+    }
+  }
+  return regex.test(ip);
+};
+
 export const step2Schemas: FormSchema[] = [
   {
     field: 'env',
@@ -156,6 +205,7 @@ export const step2Schemas: FormSchema[] = [
     field: 'leadingIp',
     component: 'Input',
     required: true,
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     label: '前端部署IP',
     colProps: {
       span: 8,
@@ -165,6 +215,7 @@ export const step2Schemas: FormSchema[] = [
     field: 'backendIp',
     component: 'Input',
     label: '后端部署IP',
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     colProps: {
       span: 8,
     },
@@ -266,6 +317,7 @@ export const step2_1Schemas: FormSchema[] = [
     component: 'Input',
     required: true,
     label: '前端部署IP',
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     colProps: {
       span: 8,
     },
@@ -274,6 +326,7 @@ export const step2_1Schemas: FormSchema[] = [
     field: 'backendIp',
     component: 'Input',
     label: '后端部署IP',
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     colProps: {
       span: 8,
     },
@@ -376,6 +429,7 @@ export const step2_2Schemas: FormSchema[] = [
     component: 'Input',
     required: true,
     label: '前端部署IP',
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     colProps: {
       span: 8,
     },
@@ -384,6 +438,7 @@ export const step2_2Schemas: FormSchema[] = [
     field: 'backendIp',
     component: 'Input',
     label: '后端部署IP',
+    rules:[{ required: true, validator: isValidIp, trigger: 'blur' }],
     colProps: {
       span: 8,
     },

+ 30 - 15
jeecgboot-vue3/src/views/appmanage/addForm/index.vue

@@ -9,21 +9,21 @@
     </div>
     <div class="mt-5">
       <Step1 ref="step1" @next="handleStep1Next" v-show="current === 0"  @closeModal="closeModal" formType="isAdd" :addType="addType"/>
-      <Step2 ref="step2" @prev="handleStepPrev" formType="isAdd" @next="handleStep2Next" v-show="current === 1" v-if="initSetp2" @closeModal="closeModal"/>
+      <Step2 ref="step2" @prev="handleStepPrev" formType="isAdd" @next="handleStep2Next" v-show="current === 1" @closeModal="closeModal"/>
       <Step3 ref="step3" v-show="current === 2" @prev="handleStepPrev" @next="handleStep3Next" @closeModal="closeModal" formType="isAdd"/>
       <Step4 ref="userManage" v-show="current === 3" formType="isAdd" @prev="handleStepPrev" @redo="handleRedo" @add="handAdd" @closeModal="closeModal"/>
     </div>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, reactive, toRefs } from 'vue';
+import {defineComponent, ref, reactive, toRefs, toRaw} from 'vue';
   import Step1 from './Step1.vue';
   import Step2 from './Step2.vue';
   import Step3 from './Step3.vue';
   import Step4 from './Step4.vue';
   import { PageWrapper } from '/@/components/Page';
   import { Steps } from 'ant-design-vue';
-  import { saveOrUpdate } from  "../AppBaseInfo.api"
-  import {any, string} from "vue-types";
+  import {saveOrUpdate } from  "../AppBaseInfo.api"
+import {any, array, string} from "vue-types";
 
   const current = ref(0);
   const tag = ref(true)
@@ -56,7 +56,9 @@
           addType: string,
           current: number
         }>
-      }
+      },
+      test: any,
+      // draftUserInfo: any
     },
     components: {
       Step1,
@@ -69,8 +71,16 @@
     },
     mounted() {
       console.log("分步表单挂载完成事件:"+this.addType);
+      console.log(this.test)
       console.dir(this.addFormDraftData);
-      tag.value = this.addType === 'full'
+
+      tag.value = this.addType === 'full';
+      (appInfoData.appBaseInfoDTO as any) = this.addFormDraftData?.appBaseInfoDTO
+      appInfoData.appEnvInfoDTO = this.addFormDraftData?.appEnvInfoDTO
+      appInfoData.appDocInfoDTO = this.addFormDraftData?.appDocInfoDTO
+      appInfoData.userInfo = this.addFormDraftData?.userInfo
+      appInfoData.current = this.addFormDraftData?.current
+      appInfoData.addType = this.addType
       this.$nextTick(() => {
         if (this.$refs.step1) {
           (this.$refs.step1 as any).getData11(this.addFormDraftData?.appBaseInfoDTO);
@@ -85,6 +95,11 @@
           if (this.$refs.step3) {
             (this.$refs.step3 as any).initDocForm(this.addFormDraftData?.appDocInfoDTO);
           }
+          if (this.$refs.userManage) {
+            console.log("分步主页面调用表单四的初始化方法:");
+            console.dir(this.addFormDraftData?.userInfo);
+            (this.$refs.userManage as any).initUserInfo(this.addFormDraftData?.userInfo, this.addFormDraftData?.appBaseInfoDTO);
+          }
         });
       }else { // 简易添加
         current.value = 0
@@ -94,24 +109,21 @@
 
     methods:{
       handleStep3Next(step3Values: any) {
-        console.log("打开第四页")
         current.value++;
         state.initSetp4 = true;
         console.log(step3Values);
         appInfoData.appDocInfoDTO = step3Values;
       },
 
-      handleStep1Next(step1Values: any) {
+      async handleStep1Next(step1Values: any) {
+        // 检查菜单路径是否已存在
+        console.log("表单一点击下一步")
         current.value++;
         state.initSetp2 = true;
-        console.log(step1Values);
-        appInfoData.appBaseInfoDTO = step1Values;
+        appInfoData.appBaseInfoDTO = step1Values
         this.$nextTick(() => {
-          if (this.$refs.userManage) {
-            (this.$refs.userManage as any).initUserInfo(this.addFormDraftData?.userInfo, step1Values);
-          }
           if(this.$refs.step2){
-            (this.$refs.step2 as any).initEnvFrom(this.addFormDraftData?.appEnvInfoDTO)
+            (this.$refs.step2 as any).initEnvFrom(this.appInfoData.appEnvInfoDTO)
           }
         })
 
@@ -121,8 +133,11 @@
     emits: ['closeModal','submit'],
     setup(_, { emit }) {
 
-      function handleStepPrev() {
+      function handleStepPrev(step2Values: any) {
         current.value--;
+        console.log("表单二点击上一步")
+        console.dir(step2Values)
+        appInfoData.appEnvInfoDTO = step2Values;
       }
 
       function handleStep2Next(step2Values: any) {

+ 2 - 2
jeecgboot-vue3/src/views/appmanage/components/data.tsx

@@ -51,8 +51,8 @@ export const addForm_newlyuserTableSchemas = [
         width: 150
     },
     {
-      title: '角色',
-      dataIndex: 'roles',
+      title: '部门',
+      dataIndex: 'depart',
       width: 150
     },
     {

+ 13 - 9
jeecgboot-vue3/src/views/system/menu/components/AppPermissionTree.vue

@@ -245,16 +245,19 @@ async function onSubmit() {
 /**
  * 选中节点,打开数据权限抽屉
  */
-function onTreeNodeSelect(key) {
-  if (key && key.length > 0) {
-    selectedKeys.value = key;
-  }
-  if (tabType.value === 'role') {
-    openDataRuleDrawer(true, { functionId: unref(selectedKeys)[0], selectId: unref(selectId), ruleType: unref(tabType) });
+function onTreeNodeSelect(key,{selectedNodes}) {
+  // if (key && key.length > 0) {
+  //   selectedKeys.value = key;
+  // }
+  if(key[0]&&selectedNodes[0].ruleFlag){
+    if (tabType.value === 'role') {
+    openDataRuleDrawer(true, { functionId: key[0], selectId: unref(selectId), ruleType: unref(tabType) });
   } else {
-    openDataRuleDrawer(true, { functionId: unref(selectedKeys)[0], selectId: unref(selectId), ruleType: unref(tabType) });
+    openDataRuleDrawer(true, { functionId: key[0], selectId: unref(selectId), ruleType: unref(tabType) });
   }
-  toggleExpandAll(true);
+  }
+  onExpand(key)
+  // toggleExpandAll(true);
 }
 
 function getNodeAllKey(node: any, children: any, key: string) {
@@ -300,7 +303,8 @@ function onCheck(o, e) {
 
 // tree展开事件
 function onExpand($expandedKeys) {
-  expandedKeys.value = $expandedKeys;
+  // expandedKeys.value = $expandedKeys;
+  expandedKeys.value =  [...new Set([...expandedKeys.value, ...$expandedKeys])];
 }
 
 // tree选中事件

+ 1 - 1
jeecgboot-vue3/src/views/system/menu/menu/menu.api.ts

@@ -2,7 +2,7 @@ import { defHttp } from '/@/utils/http/axios';
 import { Modal } from 'ant-design-vue';
 
 enum Api {
-  list = '/sys/permission/list',
+  list = '/sys/permission/sqlList',
   save = '/sys/permission/add',
   edit = '/sys/permission/edit',
   delete = '/sys/permission/delete',

+ 23 - 5
jeecgboot-vue3/src/views/system/role/components/RoleUserTable.vue

@@ -39,7 +39,7 @@
   import UseSelectModal from './UseSelectModal.vue';
   import { userList, deleteUserRole, batchDeleteUserRole, addUserRole } from '../role.api';
   import { userColumns, searchUserFormSchema } from '../role.data';
-  import { getUserRoles } from '../../user/user.api';
+  import { getUserRoles,userComplexConditionTwo } from '../../user/user.api';
 
   const emit = defineEmits(['register', 'hideUserList']);
   const props = defineProps({
@@ -48,8 +48,10 @@
   
   const checkedKeys = ref<Array<string | number>>([]);
   const roleId = ref('');
+  const appId = ref('');
   const [registerBaseDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
     roleId.value = data.id;
+    appId.value = data.appId;
     setProps({ searchInfo: { roleId: data.id } });
     reload();
   });
@@ -59,7 +61,7 @@
   const [registerModal, { openModal }] = useModal();
   const [registerTable, { reload, updateTableDataRecord, setProps,getDataSource }] = useTable({
     title: '用户列表',
-    api: userList,
+    api: userComplexConditionTwo,
     columns: userColumns,
     formConfig: {
       //update-begin---author:wangshuai ---date:20230703  for:【QQYUN-5685】3、租户角色下,查询居左显示
@@ -67,8 +69,24 @@
       //update-end---author:wangshuai ---date:20230703  for:【QQYUN-5685】3、租户角色下,查询居左显示
       schemas: searchUserFormSchema,
       autoSubmitOnEnter: true,
-      showAdvancedButton: false,
-      showSubmitButton:false
+      baseColProps: {
+        xs: 24,
+        sm: 10,
+        md: 10,
+        lg: 10,
+        xl: 10,
+        xxl: 10,
+      },
+      actionColOptions: {
+        push: 3,
+        xs: 24,
+        sm: 8,
+        md: 8,
+        lg: 8,
+        xl: 8,
+        xxl: 8,
+      },
+
     },
     striped: true,
     useSearchForm: true,
@@ -162,7 +180,7 @@
   function handleSelect() {
     const list = getDataSource();
     console.log('list', list);
-    openModal(true,{list:list});
+    openModal(true,{list:list,appId:ref(appId)});
   }
   /**
    * 添加已有用户

+ 25 - 8
jeecgboot-vue3/src/views/system/role/components/UseSelectModal.vue

@@ -1,5 +1,5 @@
 <template>
-  <BasicModal v-bind="$attrs" @register="registerModal" title="用户选择列表" width="1000px" @ok="handleSubmit" destroyOnClose>
+  <BasicModal v-bind="$attrs" @register="registerModal" title="用户选择列表" width="900px" @ok="handleSubmit" destroyOnClose>
     <BasicTable @register="registerTable" :rowSelection="rowSelection" />
   </BasicModal>
 </template>
@@ -8,34 +8,51 @@ import { ref, unref, toRaw } from 'vue';
 import { BasicModal, useModalInner } from '/src/components/Modal';
 import { BasicTable, useTable, TableAction } from '/src/components/Table';
 import { userColumns, searchUsermodelSchema } from '../role.data';
-import { list } from '../../user/user.api';
+import { listNoCareTenant, userComplexConditionTwo } from '../../user/user.api';
 // 声明Emits
 const emit = defineEmits(['select', 'register']);
 const checkedKeys = ref<Array<string | number>>([]);
 const [registerModal, { setModalProps, closeModal }] = useModalInner((data) => {
   const list = data.list || [];
   checkedKeys.value = list.map((item) => item.id);
+  let appId = data.appId;
+  setProps({ searchInfo: { appId: appId ==='0'?null:data.appId } });
 });
 //注册table数据
-const [registerTable] = useTable({
-  api: list,
+const [registerTable, { setProps }] = useTable({
+  api: userComplexConditionTwo,
   rowKey: 'id',
   columns: userColumns,
   formConfig: {
-    labelWidth: 60,
     schemas: searchUsermodelSchema,
-    baseRowStyle: { maxHeight: '20px' },
     autoSubmitOnEnter: true,
-    showAdvancedButton: false,
-    // showSubmitButton:false
+    baseColProps: {
+      xs: 24,
+      sm: 10,
+      md: 10,
+      lg: 10,
+      xl: 10,
+      xxl: 10,
+    },
+    actionColOptions: {
+      push: 5,
+      xs: 24,
+      sm: 8,
+      md: 8,
+      lg: 8,
+      xl: 8,
+      xxl: 8,
+    },
   },
   striped: true,
+  size: 'small',
   useSearchForm: true,
   showTableSetting: false,
   bordered: true,
   showIndexColumn: false,
   canResize: false,
 });
+
 /**
  * 选择列配置
  */

+ 10 - 0
jeecgboot-vue3/src/views/system/role/index.vue

@@ -46,6 +46,7 @@ import RoleIndexModal from './components/RoleIndexModal.vue';
 import RoleUserTable from './components/RoleUserTable.vue';
 import { columns, searchFormSchema } from './role.data';
 import { list, deleteRole, batchDeleteRole, getExportUrl, getImportUrl } from './role.api';
+import { appList } from '../menu/menu/menu.api';
 import { useListPage } from '/@/hooks/system/useListPage';
 const showFooter = ref(true);
 const [roleUserDrawer, { openDrawer: openRoleUserDrawer }] = useDrawer();
@@ -76,6 +77,15 @@ const { prefixCls, tableContext, onImportXls, onExportXls } = useListPage({
       column: 'createTime',
       order: 'desc',
     },
+    afterFetch: async (record) => {
+      const app = await appList();
+      record.forEach((item) => {
+        // 获取当前角色的appName
+        const rightApp = app.find((m) => m.id === item.appId);
+        item.appName = rightApp ? rightApp.name : '';
+      });
+      return record;
+    },
   },
   exportConfig: {
     name: '角色列表',

+ 5 - 1
jeecgboot-vue3/src/views/system/role/role.api.ts

@@ -2,7 +2,7 @@ import { defHttp } from '/@/utils/http/axios';
 import { Modal } from 'ant-design-vue';
 
 enum Api {
-  list = '/sys/role/list',
+  list = '/sys/role/listByApp',
   listByTenant = '/sys/role/listByTenant',
   save = '/sys/role/add',
   edit = '/sys/role/edit',
@@ -25,6 +25,7 @@ enum Api {
   saveRoleIndex = '/sys/sysRoleIndex/add',
   editRoleIndex = '/sys/sysRoleIndex/edit',
   queryIndexByCode = '/sys/sysRoleIndex/queryByCode',
+  addAppUserRoleInfos = '/sys/applicationInfo/addAppUserRoleInfos'
 }
 /**
  * 导出api
@@ -178,6 +179,9 @@ export const batchDeleteUser = (params) => {
  */
 export const addUserRole = (params, handleSuccess) => {
   return defHttp.post({ url: Api.addUserRole, params }).then(() => {
+    //同步更新应用用户关联表
+    console.log('添加成功啦');
+    // defHttp.post({ url: Api.addAppUserRoleInfos, params })
     handleSuccess();
   });
 };

+ 24 - 0
jeecgboot-vue3/src/views/system/role/role.data.ts

@@ -46,6 +46,7 @@ export const userColumns = [
     width: 80,
   },
 ];
+
 export const searchFormSchema: FormSchema[] = [
   {
     label: '应用',
@@ -87,6 +88,17 @@ export const searchUserFormSchema: FormSchema[] = [
     component: 'Input',
     colProps: { span: 14 },
   },
+  {
+    field: 'deptId',
+    label: '部门',
+    component: 'JSelectDept',
+    componentProps:{
+      labelKey:'departName',
+      multiple:false,
+      rowKey:'id'
+  },
+    colProps: { span: 15 },
+  },
 ];
 /**
  * 角色用户搜索form
@@ -98,12 +110,24 @@ export const searchUsermodelSchema: FormSchema[] = [
     component: 'Input',
     colProps: { span: 12 },
   },
+  {
+    field: 'deptId',
+    label: '部门',
+    component: 'JSelectDept',
+    componentProps:{
+      labelKey:'departName',
+      multiple:false,
+      rowKey:'id'
+  },
+    colProps: { span: 12, },
+  },
   {
     field: 'realname',
     label: '用户姓名',
     component: 'Input',
     colProps: { span: 12 },
   },
+  
 ];
 
 export const onCleanCode = (formRef: any) => {

+ 7 - 2
jeecgboot-vue3/src/views/system/user/UserDrawer.vue

@@ -16,7 +16,7 @@
   import { BasicForm, useForm } from '/@/components/Form/index';
   import { formSchema } from './user.data';
   import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
-  import { saveOrUpdateUser, getUserRoles, getUserDepartList, getAllRolesListNoByTenant, getAllRolesList } from './user.api';
+  import { saveOrUpdateUser, getUserRoles, getUserDepartList, queryallGroupByApp } from './user.api';
   import { useDrawerAdaptiveWidth } from '/@/hooks/jeecg/useAdaptiveWidth';
   import { getTenantId } from "/@/utils/auth";
 
@@ -78,6 +78,9 @@
     }
     //处理角色用户列表情况(和角色列表有关系)
     data.selectedroles && (await setFieldsValue({ selectedroles: data.selectedroles }));
+    //角色列表分组
+    const roleList = await queryallGroupByApp();
+    console.log("roleList",roleList)
     //编辑时隐藏密码/角色列表隐藏角色信息/我的部门时隐藏所属部门
     updateSchema([
       {
@@ -107,7 +110,9 @@
         //update-begin---author:wangshuai ---date:20230424  for:【issues/4844】多租户模式下,新增或编辑用户,选择角色一栏,角色选项没有做租户隔离------------
         //判断是否为多租户模式
         componentProps:{
-          api: data.tenantSaas?getAllRolesList:getAllRolesListNoByTenant
+          // api: data.tenantSaas?getAllRolesList:getAllRolesListNoByTenant
+          //多应用情况下采用分组下拉框显示角色
+          options:roleList
         }
         //update-end---author:wangshuai ---date:20230424  for:【issues/4844】多租户模式下,新增或编辑用户,选择角色一栏,角色选项没有做租户隔离------------
       },

+ 16 - 3
jeecgboot-vue3/src/views/system/user/user.api.ts

@@ -19,6 +19,7 @@ enum Api {
   deleteRecycleBin = '/sys/user/deleteRecycleBin',
   allRolesList = '/sys/role/queryall',
   allRolesListNoByTenant = '/sys/role/queryallNoByTenant',
+  queryallGroupByApp = '/sys/role/queryallGroupByApp', 
   allTenantList = '/sys/tenant/queryList',
   allPostList = '/sys/position/list',
   userDepartList = '/sys/user/userDepartList',
@@ -28,9 +29,10 @@ enum Api {
   userQuitAgent = '/sys/user/userQuitAgent',
   getQuitList = '/sys/user/getQuitList',
   putCancelQuit = '/sys/user/putCancelQuit',
-  updateUserTenantStatus='/sys/tenant/updateUserTenantStatus',
-  getUserTenantPageList='/sys/tenant/getUserTenantPageList',
-  getDeptList="/sys/sysDepart/listAll",
+  updateUserTenantStatus = '/sys/tenant/updateUserTenantStatus',
+  getUserTenantPageList = '/sys/tenant/getUserTenantPageList',
+  getDeptList = "/sys/sysDepart/listAll",
+  userComplexConditionTwo = '/sys/user/userComplexConditionTwo',
 }
 /**
  * 导出api
@@ -125,6 +127,11 @@ export const duplicateCheckDelay = (params) => {
  * @param params
  */
 export const getAllRolesList = (params) => defHttp.get({ url: Api.allRolesList, params });
+
+/**
+ * 获取全部角色(根据应用分组)
+ */
+export const queryallGroupByApp = () => defHttp.get({ url: Api.queryallGroupByApp });
 /**
  * 获取全部角色(不租户隔离)
  * @param params
@@ -253,3 +260,9 @@ export const exportUserList = (params) => {
 
   return defHttp.get({ url: Api.exportXls, params, responseType: 'blob' });
 };
+/**
+ * 用户复合查询2
+ */
+export const userComplexConditionTwo = (params) => {
+  return defHttp.post({ url: Api.userComplexConditionTwo, params });
+};

+ 7 - 9
jeecgboot-vue3/src/views/system/user/user.data.ts

@@ -95,7 +95,7 @@ export const searchFormSchema: FormSchema[] = [
     label: '名字',
     field: 'realname',
     component: 'JInput',
-   //colProps: { span: 6 },
+    //colProps: { span: 6 },
   },
   {
     label: '性别',
@@ -123,7 +123,7 @@ export const searchFormSchema: FormSchema[] = [
       placeholder: '请选择状态',
       stringToNumber: true,
     },
-   //colProps: { span: 6 },
+    //colProps: { span: 6 },
   },
 ];
 
@@ -147,7 +147,7 @@ export const formSchema: FormSchema[] = [
     label: '登录密码',
     field: 'password',
     component: 'StrengthMeter',
-    componentProps:{
+    componentProps: {
       autocomplete: 'new-password',
     },
     rules: [
@@ -192,13 +192,11 @@ export const formSchema: FormSchema[] = [
   {
     label: '角色',
     field: 'selectedroles',
-    component: 'ApiSelect',
+    component: 'Select',
     componentProps: {
       mode: 'multiple',
-      api: getAllRolesListNoByTenant,
-      labelField: 'roleName',
-      valueField: 'id',
-      immediate: false,
+      options: [{}],
+      fieldNames: { label: 'label', value: 'value', options: 'roleList' }
     },
   },
   {
@@ -222,7 +220,7 @@ export const formSchema: FormSchema[] = [
             },
           ]);
           //update-begin---author:wangshuai---date:2024-05-11---for:【issues/1222】用户编辑界面“所属部门”与“负责部门”联动出错整---
-          if(!values){
+          if (!values) {
             formModel.departIds = [];
             return;
           }