This is an automated email from the ASF dual-hosted git repository.

benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git


The following commit(s) were added to refs/heads/dev by this push:
     new 8056c1724 remove delete user function and add transfer resource of 
user function (#2734)
8056c1724 is described below

commit 8056c17249ff7082aeefe1e1b99d7ce0c363511f
Author: VampireAchao <[email protected]>
AuthorDate: Mon May 8 22:33:27 2023 +0800

    remove delete user function and add transfer resource of user function 
(#2734)
    
    * [improve] The administrator cancels the user deletion function
    
    * [improve] When the user account is disabled, it cannot own resources 
(application and project ownership)
    
    * [test] add test case of lock user
    
    * [improve] when need transfer resources,return needTransferResource true
    
    * [improve] add resource transfer function to transfer disabled user 
resources to new users
    
    * [improve] remove "delete user" and integrate "resource transfer"
    
    * [fix] change function name to changeOwnership
    
    * [fix] change icon to <Icon icon="ant-design:swap-outlined" />
    
    * [improve] Update the modal style of "transfer resource" to use a vertical 
layout
    
    * [style] code style optimize
---
 .../console/core/mapper/ApplicationMapper.java     |   2 +
 .../console/core/mapper/ResourceMapper.java        |   2 +
 .../console/core/service/ApplicationService.java   |   4 +
 .../console/core/service/ResourceService.java      |  16 +++
 .../core/service/impl/ApplicationServiceImpl.java  |  14 +++
 .../core/service/impl/ResourceServiceImpl.java     |  27 +++++
 .../console/system/controller/UserController.java  |  14 +--
 .../console/system/service/UserService.java        |  13 +--
 .../system/service/impl/UserServiceImpl.java       |  33 +++++-
 .../resources/mapper/core/ApplicationMapper.xml    |  10 ++
 .../main/resources/mapper/core/ProjectMapper.xml   |  10 ++
 .../main/resources/mapper/core/ResourceMapper.xml  |  11 ++
 .../console/core/service/UserServiceTest.java      | 123 +++++++++++++++++++++
 .../src/api/system/user.ts                         |  10 +-
 .../src/locales/lang/en/system/user.ts             |   5 +-
 .../src/locales/lang/zh-CN/system/user.ts          |   5 +-
 .../src/views/system/user/User.vue                 |  30 +----
 .../views/system/user/components/UserDrawer.vue    |  85 +++++++++++++-
 18 files changed, 348 insertions(+), 66 deletions(-)

diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ApplicationMapper.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ApplicationMapper.java
index a1f05be74..dc7c129b6 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ApplicationMapper.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ApplicationMapper.java
@@ -58,6 +58,8 @@ public interface ApplicationMapper extends 
BaseMapper<Application> {
 
   Boolean existsByJobName(@Param("jobName") String jobName);
 
+  Boolean existsByUserId(@Param("userId") Long userId);
+
   List<Application> getByProjectId(@Param("projectId") Long id);
 
   boolean existsRunningJobByClusterId(@Param("clusterId") Long clusterId);
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ResourceMapper.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ResourceMapper.java
index 0901f2eab..585b8bdf6 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ResourceMapper.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/mapper/ResourceMapper.java
@@ -28,4 +28,6 @@ import 
com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 public interface ResourceMapper extends BaseMapper<Resource> {
 
   IPage<Resource> page(Page<Resource> page, @Param("resource") Resource 
resource);
+
+  boolean existsByUserId(@Param("userId") Long userId);
 }
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
index 1960540a1..f78dcf6f2 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ApplicationService.java
@@ -39,6 +39,8 @@ public interface ApplicationService extends 
IService<Application> {
 
   boolean existsByTeamId(Long teamId);
 
+  boolean existsByUserId(Long userId);
+
   boolean create(Application app) throws IOException;
 
   Long copy(Application app) throws IOException;
@@ -120,4 +122,6 @@ public interface ApplicationService extends 
IService<Application> {
   List<String> historyUploadJars();
 
   String k8sStartLog(Long id, Integer offset, Integer limit) throws Exception;
+
+  void changeOwnership(Long userId, Long targetUserId);
 }
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
index 8874d93a3..d59df4a59 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/ResourceService.java
@@ -36,6 +36,14 @@ public interface ResourceService extends IService<Resource> {
    */
   IPage<Resource> page(Resource resource, RestRequest restRequest);
 
+  /**
+   * check resource exists by user id
+   *
+   * @param userId user id
+   * @return true if exists
+   */
+  boolean existsByUserId(Long userId);
+
   /**
    * add resource
    *
@@ -71,4 +79,12 @@ public interface ResourceService extends IService<Resource> {
    * @return team resources
    */
   List<Resource> findByTeamId(Long teamId);
+
+  /**
+   * change resource owner
+   *
+   * @param userId original user id
+   * @param targetUserId target user id
+   */
+  void changeOwnership(Long userId, Long targetUserId);
 }
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
index b6c55342f..f74650e40 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ApplicationServiceImpl.java
@@ -518,6 +518,11 @@ public class ApplicationServiceImpl extends 
ServiceImpl<ApplicationMapper, Appli
     return baseMapper.existsByTeamId(teamId);
   }
 
+  @Override
+  public boolean existsByUserId(Long userId) {
+    return baseMapper.existsByUserId(userId);
+  }
+
   @Override
   public boolean existsRunningJobByClusterId(Long clusterId) {
     boolean exists = baseMapper.existsRunningJobByClusterId(clusterId);
@@ -631,6 +636,15 @@ public class ApplicationServiceImpl extends 
ServiceImpl<ApplicationMapper, Appli
     }
   }
 
+  @Override
+  public void changeOwnership(Long userId, Long targetUserId) {
+    LambdaUpdateWrapper<Application> updateWrapper =
+        new LambdaUpdateWrapper<Application>()
+            .eq(Application::getUserId, userId)
+            .set(Application::getUserId, targetUserId);
+    this.baseMapper.update(null, updateWrapper);
+  }
+
   @Override
   public String getYarnName(Application appParam) {
     String[] args = new String[2];
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
index b2894ab8e..97443191a 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/service/impl/ResourceServiceImpl.java
@@ -35,6 +35,7 @@ import 
org.apache.streampark.console.core.service.ResourceService;
 import org.apache.commons.collections.CollectionUtils;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -69,6 +70,17 @@ public class ResourceServiceImpl extends 
ServiceImpl<ResourceMapper, Resource>
     return this.baseMapper.page(page, resource);
   }
 
+  /**
+   * check resource exists by user id
+   *
+   * @param userId user id
+   * @return true if exists
+   */
+  @Override
+  public boolean existsByUserId(Long userId) {
+    return this.baseMapper.existsByUserId(userId);
+  }
+
   @Override
   public void addResource(Resource resource) {
     String resourceName = resource.getResourceName();
@@ -134,6 +146,21 @@ public class ResourceServiceImpl extends 
ServiceImpl<ResourceMapper, Resource>
     return baseMapper.selectList(queryWrapper);
   }
 
+  /**
+   * change resource owner
+   *
+   * @param userId original user id
+   * @param targetUserId target user id
+   */
+  @Override
+  public void changeOwnership(Long userId, Long targetUserId) {
+    LambdaUpdateWrapper<Resource> updateWrapper =
+        new LambdaUpdateWrapper<Resource>()
+            .eq(Resource::getCreatorId, userId)
+            .set(Resource::getCreatorId, targetUserId);
+    this.baseMapper.update(null, updateWrapper);
+  }
+
   private void transferTeamResource(Long teamId, String resourceName) {
     String teamUploads = String.format("%s/%d", 
Workspace.local().APP_UPLOADS(), teamId);
     if (!FsOperator.lfs().exists(teamUploads)) {
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
index 13fafed17..c299cd947 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
@@ -39,7 +39,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -87,15 +86,14 @@ public class UserController {
   @PutMapping("update")
   @RequiresPermissions("user:update")
   public RestResponse updateUser(@Valid User user) throws Exception {
-    this.userService.updateUser(user);
-    return RestResponse.success();
+    return this.userService.updateUser(user);
   }
 
-  @Operation(summary = "Delete user")
-  @DeleteMapping("delete")
-  @RequiresPermissions("user:delete")
-  public RestResponse deleteUser(Long userId) throws Exception {
-    this.userService.deleteUser(userId);
+  @Operation(summary = "Transfer User's Resource")
+  @PutMapping("transferResource")
+  @RequiresPermissions("user:update")
+  public RestResponse transferResource(Long userId, Long targetUserId) {
+    this.userService.transferResource(userId, targetUserId);
     return RestResponse.success();
   }
 
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
index 686e31b86..6cd179a87 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/UserService.java
@@ -18,6 +18,7 @@
 package org.apache.streampark.console.system.service;
 
 import org.apache.streampark.console.base.domain.RestRequest;
+import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.system.authentication.JWTToken;
 import org.apache.streampark.console.system.entity.User;
 
@@ -67,15 +68,9 @@ public interface UserService extends IService<User> {
    * update user
    *
    * @param user user
+   * @return
    */
-  void updateUser(User user) throws Exception;
-
-  /**
-   * delete user
-   *
-   * @param userId user id
-   */
-  void deleteUser(Long userId) throws Exception;
+  RestResponse updateUser(User user) throws Exception;
 
   /**
    * update password
@@ -116,4 +111,6 @@ public interface UserService extends IService<User> {
   List<User> findByAppOwner(Long teamId);
 
   Map<String, Object> generateFrontendUserInfo(User user, Long teamId, 
JWTToken token);
+
+  void transferResource(Long userId, Long targetUserId);
 }
diff --git 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
index 61c296956..504d6026e 100644
--- 
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
+++ 
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/service/impl/UserServiceImpl.java
@@ -19,8 +19,11 @@ package org.apache.streampark.console.system.service.impl;
 
 import org.apache.streampark.common.util.Utils;
 import org.apache.streampark.console.base.domain.RestRequest;
+import org.apache.streampark.console.base.domain.RestResponse;
 import org.apache.streampark.console.base.exception.ApiAlertException;
 import org.apache.streampark.console.base.util.ShaHashUtils;
+import org.apache.streampark.console.core.service.ApplicationService;
+import org.apache.streampark.console.core.service.ResourceService;
 import org.apache.streampark.console.system.authentication.JWTToken;
 import org.apache.streampark.console.system.entity.Team;
 import org.apache.streampark.console.system.entity.User;
@@ -61,6 +64,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, 
User> implements Us
 
   @Autowired private MenuService menuService;
 
+  @Autowired private ApplicationService applicationService;
+
+  @Autowired private ResourceService resourceService;
+
   @Override
   public User findByName(String username) {
     LambdaQueryWrapper<User> queryWrapper =
@@ -105,17 +112,24 @@ public class UserServiceImpl extends 
ServiceImpl<UserMapper, User> implements Us
 
   @Override
   @Transactional(rollbackFor = Exception.class)
-  public void updateUser(User user) {
+  public RestResponse updateUser(User user) {
+    User existsUser = getById(user.getUserId());
     user.setPassword(null);
     user.setModifyTime(new Date());
+    if (needTransferResource(existsUser, user)) {
+      return 
RestResponse.success(Collections.singletonMap("needTransferResource", true));
+    }
     updateById(user);
+    return RestResponse.success();
   }
 
-  @Override
-  @Transactional(rollbackFor = Exception.class)
-  public void deleteUser(Long userId) {
-    removeById(userId);
-    this.memberService.deleteByUserId(userId);
+  private boolean needTransferResource(User existsUser, User user) {
+    if (User.STATUS_LOCK.equals(existsUser.getStatus())
+        || User.STATUS_VALID.equals(user.getStatus())) {
+      return false;
+    }
+    return applicationService.existsByUserId(user.getUserId())
+        || resourceService.existsByUserId(user.getUserId());
   }
 
   @Override
@@ -246,4 +260,11 @@ public class UserServiceImpl extends 
ServiceImpl<UserMapper, User> implements Us
 
     return userInfo;
   }
+
+  @Override
+  @Transactional(rollbackFor = Exception.class)
+  public void transferResource(Long userId, Long targetUserId) {
+    applicationService.changeOwnership(userId, targetUserId);
+    resourceService.changeOwnership(userId, targetUserId);
+  }
 }
diff --git 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ApplicationMapper.xml
 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ApplicationMapper.xml
index e4eca78d0..88776e02d 100644
--- 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ApplicationMapper.xml
+++ 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ApplicationMapper.xml
@@ -102,6 +102,16 @@
         limit 1
     </select>
 
+    <select id="existsByUserId" resultType="java.lang.Boolean" 
parameterType="java.lang.Long">
+        select
+            CASE
+                WHEN  count(1) > 0 THEN true ELSE false
+            END
+        from t_flink_app
+        where user_id = #{userId}
+        limit 1
+    </select>
+
     <select id="existsJobByClusterId" resultType="java.lang.Boolean" 
parameterType="java.lang.Long">
         SELECT
             CASE
diff --git 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ProjectMapper.xml
 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ProjectMapper.xml
index 93f6bfe3f..46f733e58 100644
--- 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ProjectMapper.xml
+++ 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ProjectMapper.xml
@@ -49,6 +49,16 @@
             limit 1
     </select>
 
+    <select id="existsByUserId" resultType="java.lang.Boolean" 
parameterType="java.lang.String">
+        select
+            CASE
+                WHEN  count(1) > 0 THEN true ELSE false
+                END
+        from t_flink_project
+        where user_id = #{userId}
+        limit 1
+    </select>
+
     <select id="selectByTeamId" 
resultType="org.apache.streampark.console.core.entity.Project" 
parameterType="java.lang.Long">
         select *
         from t_flink_project
diff --git 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ResourceMapper.xml
 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ResourceMapper.xml
index 5ddd4a57f..9c9a89ed5 100644
--- 
a/streampark-console/streampark-console-service/src/main/resources/mapper/core/ResourceMapper.xml
+++ 
b/streampark-console/streampark-console-service/src/main/resources/mapper/core/ResourceMapper.xml
@@ -45,4 +45,15 @@
         </if>
     </select>
 
+    <select id="existsByUserId" resultType="java.lang.Boolean" 
parameterType="java.lang.Long">
+        select
+            CASE
+                WHEN  count(1) > 0 THEN true ELSE false
+                END
+        from t_resource
+        where creator_id = #{userId}
+        limit 1
+    </select>
+
+
 </mapper>
diff --git 
a/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
 
b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
new file mode 100644
index 000000000..9a2a15686
--- /dev/null
+++ 
b/streampark-console/streampark-console-service/src/test/java/org/apache/streampark/console/core/service/UserServiceTest.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.streampark.console.core.service;
+
+import org.apache.streampark.console.SpringTestBase;
+import org.apache.streampark.console.core.entity.Application;
+import org.apache.streampark.console.core.entity.Resource;
+import org.apache.streampark.console.core.enums.EngineType;
+import org.apache.streampark.console.core.enums.ResourceType;
+import org.apache.streampark.console.core.enums.UserType;
+import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.service.UserService;
+
+import com.baomidou.mybatisplus.extension.toolkit.Db;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Collections;
+import java.util.Map;
+
+/** org.apache.streampark.console.core.service.UserServiceTest. */
+class UserServiceTest extends SpringTestBase {
+  @Autowired private UserService userService;
+  @Autowired private ApplicationService applicationService;
+  @Autowired private ResourceService resourceService;
+
+  @Test
+  @SuppressWarnings("unchecked")
+  void testLockUser() throws Exception {
+    User user = new User();
+    user.setUsername("test");
+    user.setNickName("test");
+    user.setPassword("test");
+    user.setUserType(UserType.USER);
+    user.setStatus(User.STATUS_VALID);
+    Db.save(user);
+    // lock user
+    user.setStatus(User.STATUS_LOCK);
+    Map<String, Object> data =
+        (Map<String, Object>)
+            userService.updateUser(user).getOrDefault("data", 
Collections.emptyMap());
+    Assertions.assertNotEquals(true, data.get("needTransferResource"));
+    // unlock user
+    user.setStatus(User.STATUS_VALID);
+    Map<String, Object> data1 =
+        (Map<String, Object>)
+            userService.updateUser(user).getOrDefault("data", 
Collections.emptyMap());
+    Assertions.assertNotEquals(true, data1.get("needTransferResource"));
+
+    Resource resource = new Resource();
+    resource.setResourceName("test");
+    resource.setResourceType(ResourceType.FLINK_APP);
+    resource.setEngineType(EngineType.FLINK);
+    resource.setTeamId(1L);
+    resource.setCreatorId(user.getUserId());
+    Db.save(resource);
+    // lock user when has resource
+    user.setStatus(User.STATUS_LOCK);
+    Map<String, Object> data2 =
+        (Map<String, Object>)
+            userService.updateUser(user).getOrDefault("data", 
Collections.emptyMap());
+    Assertions.assertEquals(true, data2.get("needTransferResource"));
+  }
+
+  @Test
+  void testTransferResource() {
+    User user = new User();
+    user.setUsername("test");
+    user.setNickName("test");
+    user.setPassword("test");
+    user.setUserType(UserType.USER);
+    user.setStatus(User.STATUS_VALID);
+    Db.save(user);
+
+    Resource resource = new Resource();
+    resource.setResourceName("test");
+    resource.setResourceType(ResourceType.FLINK_APP);
+    resource.setEngineType(EngineType.FLINK);
+    resource.setTeamId(1L);
+    resource.setCreatorId(user.getUserId());
+    Db.save(resource);
+
+    Application app = new Application();
+    app.setUserId(user.getUserId());
+    app.setTeamId(1L);
+    Db.save(app);
+
+    User targetUser = new User();
+    targetUser.setUsername("test0");
+    targetUser.setNickName("test0");
+    targetUser.setPassword("test0");
+    targetUser.setUserType(UserType.USER);
+    targetUser.setStatus(User.STATUS_VALID);
+    Db.save(targetUser);
+
+    Assertions.assertTrue(applicationService.existsByUserId(user.getUserId()));
+    Assertions.assertTrue(resourceService.existsByUserId(user.getUserId()));
+
+    userService.transferResource(user.getUserId(), targetUser.getUserId());
+
+    
Assertions.assertFalse(applicationService.existsByUserId(user.getUserId()));
+    Assertions.assertFalse(resourceService.existsByUserId(user.getUserId()));
+
+    
Assertions.assertTrue(applicationService.existsByUserId(targetUser.getUserId()));
+    
Assertions.assertTrue(resourceService.existsByUserId(targetUser.getUserId()));
+  }
+}
diff --git 
a/streampark-console/streampark-console-webapp/src/api/system/user.ts 
b/streampark-console/streampark-console-webapp/src/api/system/user.ts
index b5767df01..7182afed9 100644
--- a/streampark-console/streampark-console-webapp/src/api/system/user.ts
+++ b/streampark-console/streampark-console-webapp/src/api/system/user.ts
@@ -37,13 +37,13 @@ enum Api {
   NoTokenUsers = '/user/getNoTokenUser',
   UserUpdate = '/user/update',
   UserAdd = '/user/post',
-  UserDelete = '/user/delete',
   ResetPassword = '/user/password/reset',
   Password = '/user/password',
   CheckName = '/user/check/name',
   SET_TEAM = '/user/setTeam',
   INIT_TEAM = '/user/initTeam',
   APP_OWNERS = '/user/appOwners',
+  TransferUserResource = '/user/transferResource',
 }
 
 /**
@@ -99,10 +99,6 @@ export function addUser(data: Recordable) {
   return defHttp.post({ url: Api.UserAdd, data });
 }
 
-export function deleteUser(data) {
-  return defHttp.delete({ url: Api.UserDelete, data });
-}
-
 export function resetPassword(data): Promise<AxiosResponse<Result<string>>> {
   return defHttp.put({ url: Api.ResetPassword, data },
     { isReturnNativeResponse: true },);
@@ -150,3 +146,7 @@ export function fetchSetUserTeam(data: { teamId: string }): 
Promise<TeamSetRespo
     data,
   });
 }
+
+export function transferUserResource(data: { userId: string, targetUserId: 
string }): Promise<TeamSetResponse> {
+  return defHttp.put({ url: Api.TransferUserResource, data });
+}
diff --git 
a/streampark-console/streampark-console-webapp/src/locales/lang/en/system/user.ts
 
b/streampark-console/streampark-console-webapp/src/locales/lang/en/system/user.ts
index 74d56ccdc..d056b4300 100644
--- 
a/streampark-console/streampark-console-webapp/src/locales/lang/en/system/user.ts
+++ 
b/streampark-console/streampark-console-webapp/src/locales/lang/en/system/user.ts
@@ -21,9 +21,6 @@ export default {
     modify: 'modify user',
     reset: 'reset password',
     resetTip: 'reset password, are you sure',
-    delete: 'delete user',
-    deleteTip: 'delete user, are you sure',
-    deleteSuccess: 'delete successful',
     resetSuccess: 'reset password successful, user [ {0} ] new password is 
streampark666',
   },
   form: {
@@ -46,6 +43,8 @@ export default {
     create: 'Create User',
     edit: 'Edit User',
     view: 'View User',
+    notice: 'Notice',
+    transferResource: 'Please transfer the resources of the user who needs to 
be disabled to a new user'
   },
   roleInfo: 'Role Info',
   modifyTime: 'Not yet modified',
diff --git 
a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/system/user.ts
 
b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/system/user.ts
index 4b51ee53a..5e092dcde 100644
--- 
a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/system/user.ts
+++ 
b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/system/user.ts
@@ -21,9 +21,6 @@ export default {
     modify: '修改用户',
     reset: '重置密码',
     resetTip: '你确定要重置密码吗?',
-    delete: '删除用户',
-    deleteTip: '你确定要删除用户吗',
-    deleteSuccess: '用户删除成功',
     resetSuccess: '重置密码成功,用户 [ {0} ] 新密码为 streampark666',
   },
   form: {
@@ -46,6 +43,8 @@ export default {
     create: '创建用户',
     edit: '编辑用户',
     view: '查看用户',
+    notice: '提示',
+    transferResource: '请将需要被禁用的用户资源转移到新的用户上'
   },
   roleInfo: '角色信息',
   modifyTime: '尚未修改',
diff --git 
a/streampark-console/streampark-console-webapp/src/views/system/user/User.vue 
b/streampark-console/streampark-console-webapp/src/views/system/user/User.vue
index 1d9d34a8f..b04cac08a 100644
--- 
a/streampark-console/streampark-console-webapp/src/views/system/user/User.vue
+++ 
b/streampark-console/streampark-console-webapp/src/views/system/user/User.vue
@@ -40,7 +40,7 @@
   import UserDrawer from './components/UserDrawer.vue';
   import UserModal from './components/UserModal.vue';
   import { useDrawer } from '/@/components/Drawer';
-  import { deleteUser, getUserList, resetPassword } from '/@/api/system/user';
+  import { getUserList, resetPassword } from '/@/api/system/user';
   import { columns, searchFormSchema } from './user.data';
   import { FormTypeEnum } from '/@/enums/formEnum';
   import { useMessage } from '/@/hooks/web/useMessage';
@@ -82,7 +82,7 @@
         showIndexColumn: false,
         canResize: false,
         actionColumn: {
-          width: 200,
+          width: 150,
           title: t('component.table.operation'),
           dataIndex: 'action',
         },
@@ -113,17 +113,6 @@
               confirm: handleReset.bind(null, record),
             },
           },
-          {
-            icon: 'ant-design:delete-outlined',
-            color: 'error',
-            auth: 'user:delete',
-            ifShow: record.username !== 'admin',
-            tooltip: t('system.user.table.delete'),
-            popConfirm: {
-              title: t('system.user.table.deleteTip'),
-              confirm: handleDelete.bind(null, record),
-            },
-          },
         ];
       }
       // user create
@@ -143,20 +132,6 @@
         openModal(true, record);
       }
 
-      // delete current user
-      async function handleDelete(record: UserListRecord) {
-        const hide = createMessage.loading('deleteing');
-        try {
-          await deleteUser({ userId: record.userId });
-          createMessage.success(t('system.user.table.deleteSuccess'));
-          reload();
-        } catch (error) {
-          console.error('user delete fail:', error);
-        } finally {
-          hide();
-        }
-      }
-
       async function handleReset(record: Recordable) {
         const hide = createMessage.loading('reseting');
         try {
@@ -189,7 +164,6 @@
         registerModal,
         handleCreate,
         handleEdit,
-        handleDelete,
         handleSuccess,
         handleView,
         handleReset,
diff --git 
a/streampark-console/streampark-console-webapp/src/views/system/user/components/UserDrawer.vue
 
b/streampark-console/streampark-console-webapp/src/views/system/user/components/UserDrawer.vue
index e53544abb..564e0d211 100644
--- 
a/streampark-console/streampark-console-webapp/src/views/system/user/components/UserDrawer.vue
+++ 
b/streampark-console/streampark-console-webapp/src/views/system/user/components/UserDrawer.vue
@@ -28,24 +28,44 @@
     </template>
     <BasicForm @register="registerForm" />
   </BasicDrawer>
+  <Modal
+    :visible="transferModalVisible"
+    :confirm-loading="transferModalLoading"
+    :ok-text="t('common.okText')"
+    centered
+    @ok="handleTransfer"
+    @cancel="transferModalVisible=false"
+  >
+    <template #title>
+      <Icon icon="ant-design:swap-outlined" />
+      {{ t('system.user.form.notice') }}
+    </template>
+    <BasicForm @register="transferForm" class="!mt-30px !ml-36px"/>
+  </Modal>
 </template>
 <script lang="ts">
-  import { computed, defineComponent, ref, unref } from 'vue';
+  import { computed, defineComponent, nextTick, ref, unref } from 'vue';
   import { BasicForm, useForm } from '/@/components/Form';
   import { formSchema } from '../user.data';
   import { FormTypeEnum } from '/@/enums/formEnum';
   import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
-  import { addUser, updateUser } from '/@/api/system/user';
+  import {addUser, getUserList, transferUserResource, updateUser} from 
'/@/api/system/user';
   import Icon from '/@/components/Icon';
   import { useI18n } from '/@/hooks/web/useI18n';
+  import { useUserStoreWithOut } from "/@/store/modules/user";
+  import { Modal } from 'ant-design-vue';
 
   export default defineComponent({
     name: 'MenuDrawer',
-    components: { BasicDrawer, Icon, BasicForm },
+    components: { Modal, BasicDrawer, Icon, BasicForm },
     emits: ['success', 'register'],
     setup(_, { emit }) {
       const { t } = useI18n();
+      const userStore = useUserStoreWithOut();
       const formType = ref(FormTypeEnum.Edit);
+      const userInfo = ref<Recordable>({});
+      const transferModalVisible = ref(false);
+      const transferModalLoading = ref(false);
 
       const [registerForm, { resetFields, setFieldsValue, updateSchema, 
validate, clearValidate }] =
         useForm({
@@ -58,6 +78,7 @@
 
       const [registerDrawer, { setDrawerProps, closeDrawer }] = 
useDrawerInner(async (data) => {
         formType.value = data.formType;
+        userInfo.value = data.record || {}
         resetFields();
         clearValidate();
         updateSchema(formSchema(unref(formType)));
@@ -73,6 +94,37 @@
         }
       });
 
+      const [transferForm, { resetFields: resetTransferFields, validate: 
transferValidate }] = useForm({
+        layout: 'vertical',
+        showActionButtonGroup: false,
+        baseColProps: { lg: 22, md: 22 },
+        schemas: [
+          {
+            field: 'userId',
+            label: t('system.user.form.transferResource'),
+            component: 'ApiSelect',
+            componentProps: {
+              api: async () =>  {
+                let {records} = await getUserList({ page: 1, pageSize: 999999, 
teamId: userStore.getTeamId || '' })
+                return records.filter( user => user.userId !== 
userInfo.value.userId )
+              },
+              labelField: 'username',
+              valueField: 'userId',
+              showSearch: false,
+              optionFilterGroup: 'username',
+              placeholder: t('system.member.userNameRequire'),
+            },
+            rules: [
+              {
+                required: true,
+                message: t('system.member.userNameRequire'),
+                trigger: 'blur',
+              },
+            ],
+          }
+        ],
+      });
+
       const getTitle = computed(() => {
         return {
           [FormTypeEnum.Create]: t('system.user.form.create'),
@@ -85,7 +137,16 @@
         try {
           const values = await validate();
           setDrawerProps({ confirmLoading: true });
-          unref(formType) === FormTypeEnum.Edit ? await updateUser(values) : 
await addUser(values);
+          if (unref(formType) === FormTypeEnum.Edit) {
+            const res: { needTransferResource: Boolean } = await 
updateUser(values)
+            if (res?.needTransferResource) {
+              transferModalVisible.value = true
+              nextTick(resetTransferFields)
+              return
+            }
+          }else{
+            await addUser(values);
+          }
           closeDrawer();
           emit('success');
         } finally {
@@ -93,7 +154,21 @@
         }
       }
 
-      return { t, registerDrawer, registerForm, getTitle, handleSubmit };
+      async function handleTransfer() {
+        try {
+          const values = await transferValidate();
+          transferModalLoading.value = true
+          await transferUserResource({ userId:userInfo.value.userId, 
targetUserId: values.userId })
+          emit('success');
+          transferModalVisible.value = false
+        } catch (e) {
+          console.error(e);
+        } finally {
+          transferModalLoading.value = false
+        }
+      }
+
+      return { t, registerDrawer, registerForm, transferForm, 
transferModalLoading, transferModalVisible, getTitle, handleSubmit, 
handleTransfer, closeDrawer };
     },
   });
 </script>


Reply via email to