7 Commits a23210ff2e ... a98bdd5068

Autor SHA1 Mensagem Data
  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
  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 下午提交 3 meses atrás

+ 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);
-    }
 }

+ 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;

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

@@ -18,5 +18,4 @@ public class AppUserInfo {
     private String id;
     private String appid;
     private String userid;
-    private String roles;
 }

+ 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);
 }
 

+ 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;
     }
+
+
 }

+ 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
     },
     {