Преглед изворни кода

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	xzl-admin/src/main/java/com/xzl/web/controller/system/SysLoginController.java
#	xzl-admin/src/main/java/com/xzl/web/mapper/UserPortraitMapper.java
#	xzl-admin/src/main/resources/mapper/UserPortraitMapper.xml
ZHOUTD пре 1 година
родитељ
комит
2a0b184177
23 измењених фајлова са 1640 додато и 706 уклоњено
  1. 5 0
      xzl-admin/pom.xml
  2. 9 0
      xzl-admin/src/main/java/com/xzl/web/controller/system/SysLoginController.java
  3. 134 99
      xzl-admin/src/main/java/com/xzl/web/controller/userPortrait/ViewController.java
  4. 4 0
      xzl-admin/src/main/java/com/xzl/web/mapper/UserPortraitMapper.java
  5. 10 1
      xzl-admin/src/main/java/com/xzl/web/service/UserPortraitService.java
  6. 347 5
      xzl-admin/src/main/java/com/xzl/web/service/impl/UserPortraitServiceImpl.java
  7. 56 0
      xzl-admin/src/main/java/com/xzl/web/utils/RequestUtils.java
  8. 62 0
      xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkDept.java
  9. 70 0
      xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkUser.java
  10. 159 0
      xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkUtils.java
  11. 1 1
      xzl-admin/src/main/resources/application.yml
  12. 20 0
      xzl-admin/src/main/resources/mapper/UserPortraitMapper.xml
  13. 19 0
      xzl-common/src/main/java/com/xzl/common/core/domain/entity/SysDept.java
  14. 336 302
      xzl-common/src/main/java/com/xzl/common/core/domain/entity/SysUser.java
  15. 250 281
      xzl-system/src/main/java/com/xzl/system/service/impl/SysDeptServiceImpl.java
  16. 10 1
      xzl-system/src/main/resources/mapper/system/SysDeptMapper.xml
  17. 22 4
      xzl-system/src/main/resources/mapper/system/SysUserMapper.xml
  18. 8 0
      xzl-ui/src/api/system/user.js
  19. 14 3
      xzl-ui/src/store/modules/user.js
  20. 12 0
      xzl-ui/src/utils/auth.js
  21. 28 6
      xzl-ui/src/views/index.vue
  22. 32 0
      xzl-ui/src/views/nlp/index.vue
  23. 32 3
      xzl-ui/src/views/system/user/index.vue

+ 5 - 0
xzl-admin/pom.xml

@@ -107,6 +107,11 @@
         </dependency>
         -->
 
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>alibaba-dingtalk-service-sdk</artifactId>
+            <version>2.0.0</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 9 - 0
xzl-admin/src/main/java/com/xzl/web/controller/system/SysLoginController.java

@@ -1,5 +1,9 @@
 package com.xzl.web.controller.system;
 
+import java.util.List;
+import java.util.Set;
+
+import com.xzl.web.service.UserPortraitService;
 import java.util.*;
 
 import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
@@ -40,6 +44,9 @@ public class SysLoginController
     @Autowired
     private UserPortraitMapper userPortraitMapper;
 
+    @Autowired
+    private UserPortraitService userPortraitService;
+
     /**
      * 登录方法
      * 
@@ -54,6 +61,8 @@ public class SysLoginController
         String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                 loginBody.getUuid());
         ajax.put(Constants.TOKEN, token);
+        // 登录NLP系统, 能执行到这一步,表示登录成功
+        ajax.put("NLPAuthData", userPortraitService.loginNLP(loginBody));
         return ajax;
     }
 

+ 134 - 99
xzl-admin/src/main/java/com/xzl/web/controller/userPortrait/ViewController.java

@@ -1,6 +1,7 @@
 package com.xzl.web.controller.userPortrait;
 
 import com.xzl.common.utils.DateUtils;
+import com.xzl.common.utils.StringUtils;
 import com.xzl.web.service.UserPortraitService;
 import org.aspectj.util.FileUtil;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,113 +30,147 @@ import java.util.Map;
 @RequestMapping("/user-portait")
 public class ViewController {
 
-    @Autowired
-    private UserPortraitService userPortraitService;
-
-    @Value("${pythonFilePath}")
-    String pythonFilePath;
-
-    @Value("${pythonPath}")
-    String pythonPath;
-
-    @GetMapping("/show")
-    public void show(HttpServletResponse response) throws Exception {
-        String wordcloudImageFileName = "wordcloud.png";
-        File wordcloudImageFile = new File(pythonFilePath, wordcloudImageFileName);
-        if (wordcloudImageFile.exists()) {
-            InputStream inputStream = null;
-            ServletOutputStream outputStream = null;
-            try {
-                inputStream = new FileInputStream(wordcloudImageFile);
-                outputStream = response.getOutputStream();
-                response.setHeader("Content-Disposition", String.format(
-                        "attachment; filename=\"%s\"",
-                        java.net.URLEncoder.encode(wordcloudImageFile.getName(), "UTF-8")));
-                response.setContentType("application/octet-stream;charset=UTF-8");
-                int count = 0;
-                byte[] buffer = new byte[1024 * 1024];
-                while ((count = inputStream.read(buffer)) != -1) {
-                    outputStream.write(buffer, 0, count);
-                }
-                outputStream.flush();
-            } catch (Exception e) {
-                e.printStackTrace();
-            } finally {
-                if (inputStream != null) {
-                    inputStream.close();
-                }
-                if (outputStream != null) {
-                    outputStream.close();
-                }
-            }
+  @Autowired
+  private UserPortraitService userPortraitService;
+
+  @Value("${pythonFilePath}")
+  String pythonFilePath;
+
+  @Value("${pythonPath}")
+  String pythonPath;
+
+  @GetMapping("/show")
+  public void show(HttpServletResponse response) throws Exception {
+    String wordcloudImageFileName = "wordcloud.png";
+    File wordcloudImageFile = new File(pythonFilePath, wordcloudImageFileName);
+    if (wordcloudImageFile.exists()) {
+      InputStream inputStream = null;
+      ServletOutputStream outputStream = null;
+      try {
+        inputStream = new FileInputStream(wordcloudImageFile);
+        outputStream = response.getOutputStream();
+        response.setHeader("Content-Disposition", String.format(
+          "attachment; filename=\"%s\"",
+          java.net.URLEncoder.encode(wordcloudImageFile.getName(), "UTF-8")));
+        response.setContentType("application/octet-stream;charset=UTF-8");
+        int count = 0;
+        byte[] buffer = new byte[1024 * 1024];
+        while ((count = inputStream.read(buffer)) != -1) {
+          outputStream.write(buffer, 0, count);
         }
-    }
-
-    @PostMapping("/generate")
-    public Map generate() throws Exception {
-        Map rs = new HashMap();
-        // 先判断有没有 wordcloud.txt, 没有就生成一个,有就备份一个,然后重新生成新的内容
-        String wordcloudFileName = "wordcloud.txt";
-        File wordcloudFile = new File(pythonFilePath, wordcloudFileName);
-
-        String wordcloudImageFileName = "wordcloud.png";
-        File wordcloudImageFile = new File(pythonFilePath, wordcloudImageFileName);
-
-        // 如果词云文件存在,就先都备份一下,然后再生成新的
-        String timePrefix = DateUtils.dateTimeNow();
-        if (wordcloudFile.exists()) {
-            FileUtil.copyFile(wordcloudFile, new File(pythonFilePath, timePrefix + "-" + wordcloudFileName));
+        outputStream.flush();
+      } catch (Exception e) {
+        e.printStackTrace();
+      } finally {
+        if (inputStream != null) {
+          inputStream.close();
         }
-        if (wordcloudImageFile.exists()) {
-            FileUtil.copyFile(wordcloudImageFile, new File(pythonFilePath, timePrefix + "-" + wordcloudImageFileName));
+        if (outputStream != null) {
+          outputStream.close();
         }
+      }
+    }
+  }
+
+  @PostMapping("/generate")
+  public Map generate() throws Exception {
+    Map rs = new HashMap();
+    // 先判断有没有 wordcloud.txt, 没有就生成一个,有就备份一个,然后重新生成新的内容
+    String wordcloudFileName = "wordcloud.txt";
+    File wordcloudFile = new File(pythonFilePath, wordcloudFileName);
+
+    String wordcloudImageFileName = "wordcloud.png";
+    File wordcloudImageFile = new File(pythonFilePath, wordcloudImageFileName);
+
+    // 如果词云文件存在,就先都备份一下,然后再生成新的
+    String timePrefix = DateUtils.dateTimeNow();
+    if (wordcloudFile.exists()) {
+      FileUtil.copyFile(wordcloudFile, new File(pythonFilePath, timePrefix + "-" + wordcloudFileName));
+    }
+    if (wordcloudImageFile.exists()) {
+      FileUtil.copyFile(wordcloudImageFile, new File(pythonFilePath, timePrefix + "-" + wordcloudImageFileName));
+    }
 
-        //获取新的内容,写入 wordcloud.txt
-        List<String> wordCloudInfo = userPortraitService.getWordCloudInfo();
-        FileWriter out = new FileWriter(wordcloudFile);
-        BufferedWriter bw= new BufferedWriter(out);
-        for (String info : wordCloudInfo) {
-            bw.write(info + "\t");
-            bw.newLine();
-        }
-        bw.close();
-        out.close();
-
-        // 调用python脚本, 生成新的词云图片
-        String[] commands = {pythonPath, pythonFilePath + "word-cloud.py"};
-        ProcessBuilder processBuilder = new ProcessBuilder(commands);
-        Process process = processBuilder.start();
-        // 等待命令执行完成
-        int exitCode = process.waitFor();
-        System.out.println("命令执行结果:" + exitCode);
-        rs.put("exitCode", exitCode);
-        return rs;
+    //获取新的内容,写入 wordcloud.txt
+    List<String> wordCloudInfo = userPortraitService.getWordCloudInfo();
+    FileWriter out = new FileWriter(wordcloudFile);
+    BufferedWriter bw = new BufferedWriter(out);
+    for (String info : wordCloudInfo) {
+      bw.write(info + "\t");
+      bw.newLine();
+    }
+    bw.close();
+    out.close();
+
+    // 调用python脚本, 生成新的词云图片
+    String[] commands = {pythonPath, pythonFilePath + "word-cloud.py"};
+    ProcessBuilder processBuilder = new ProcessBuilder(commands);
+    Process process = processBuilder.start();
+    // 等待命令执行完成
+    int exitCode = process.waitFor();
+    System.out.println("命令执行结果:" + exitCode);
+    rs.put("exitCode", exitCode);
+    return rs;
+  }
+
+
+  /**
+   * 执行Linux命令
+   *
+   * @param command 需要执行的Linux命令
+   * @return 执行结果
+   */
+  public String executeCommand(String command) throws IOException {
+    // 创建一个新进程
+    Process process = Runtime.getRuntime().exec(command);
+
+    // 获取进程的输入流并转换为字符串
+    InputStream inputStream = process.getInputStream();
+    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+    StringBuilder result = new StringBuilder();
+    String line;
+    while ((line = reader.readLine()) != null) {
+      result.append(line).append("\n");
     }
 
+    // 关闭输入流和进程
+    reader.close();
+    process.destroy();
 
-    /**
-     * 执行Linux命令
-     *
-     * @param command 需要执行的Linux命令
-     * @return 执行结果
-     */
-    public String executeCommand(String command) throws IOException {
-        // 创建一个新进程
-        Process process = Runtime.getRuntime().exec(command);
-
-        // 获取进程的输入流并转换为字符串
-        InputStream inputStream = process.getInputStream();
-        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
-        StringBuilder result = new StringBuilder();
-        String line;
-        while ((line = reader.readLine()) != null) {
-            result.append(line).append("\n");
-        }
+    return result.toString();
+  }
+
+
+  @GetMapping("/initDingtalk")
+  public Map initDingtalk() throws Exception {
+    return userPortraitService.initByDingtalk();
+  }
 
-        // 关闭输入流和进程
-        reader.close();
-        process.destroy();
 
-        return result.toString();
+  @PostMapping("/update-nlp")
+  public Map updateNlp(String username, String nlpName, String nlpPwd) throws Exception {
+    Map rs = new HashMap();
+    rs.put("success", 0);
+    if (StringUtils.isBlank(username)) {
+      rs.put("msg", "用户名不能为空");
+      return rs;
+    }
+    if (StringUtils.isBlank(nlpName)) {
+      rs.put("msg", "NLP用户名不能为空");
+      return rs;
+    }
+    if (nlpName.length() > 32) {
+      rs.put("msg", "NLP用户名长度不能超过32");
+      return rs;
+    }
+    if (StringUtils.isBlank(nlpPwd)) {
+      rs.put("msg", "NLP密码不能为空");
+      return rs;
+    }
+    if (nlpPwd.length() > 32) {
+      rs.put("msg", "NLP密码长度不能超过32");
+      return rs;
     }
+    return userPortraitService.updateNlp(username, nlpName, nlpPwd);
+  }
 }

+ 4 - 0
xzl-admin/src/main/java/com/xzl/web/mapper/UserPortraitMapper.java

@@ -11,4 +11,8 @@ public interface UserPortraitMapper {
 
     SysUser getUserByDingUnionId(String unionId);
     SysUser getUserByDingUsername(String username);
+
+    void syncParentForDingtalk();
+
+    void syncDeptForDingtalk();
 }

+ 10 - 1
xzl-admin/src/main/java/com/xzl/web/service/UserPortraitService.java

@@ -1,7 +1,16 @@
 package com.xzl.web.service;
 
+import com.xzl.common.core.domain.model.LoginBody;
+
 import java.util.List;
+import java.util.Map;
 
 public interface UserPortraitService {
-    List<String> getWordCloudInfo();
+  List<String> getWordCloudInfo();
+
+  String loginNLP(LoginBody loginBody);
+
+  Map initByDingtalk() throws Exception;
+
+  Map updateNlp(String username, String nlpUserName, String nlpPassword);
 }

+ 347 - 5
xzl-admin/src/main/java/com/xzl/web/service/impl/UserPortraitServiceImpl.java

@@ -1,21 +1,363 @@
 package com.xzl.web.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.xzl.common.constant.UserConstants;
+import com.xzl.common.core.domain.entity.SysDept;
+import com.xzl.common.core.domain.entity.SysDictData;
+import com.xzl.common.core.domain.entity.SysUser;
+import com.xzl.common.core.domain.model.LoginBody;
+import com.xzl.common.utils.SecurityUtils;
+import com.xzl.common.utils.StringUtils;
+import com.xzl.system.service.ISysConfigService;
+import com.xzl.system.service.ISysDeptService;
+import com.xzl.system.service.ISysDictDataService;
+import com.xzl.system.service.ISysUserService;
 import com.xzl.web.mapper.UserPortraitMapper;
 import com.xzl.web.service.UserPortraitService;
+import com.xzl.web.utils.RequestUtils;
+import com.xzl.web.utils.ali.DingTalkDept;
+import com.xzl.web.utils.ali.DingTalkUser;
+import com.xzl.web.utils.ali.DingTalkUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.MapUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+@Slf4j
 @Service
 public class UserPortraitServiceImpl implements UserPortraitService {
 
-    @Autowired
-    private UserPortraitMapper userPortraitMapper;
+  @Autowired
+  private UserPortraitMapper userPortraitMapper;
 
+  @Autowired
+  private ISysDictDataService dictDataService;
 
-    @Override
-    public List<String> getWordCloudInfo() {
-        return userPortraitMapper.getWordCloudInfo();
+  @Autowired
+  private ISysDeptService deptService;
+
+  @Autowired
+  private ISysUserService userService;
+
+  @Autowired
+  private ISysConfigService configService;
+
+  @Override
+  public List<String> getWordCloudInfo() {
+    return userPortraitMapper.getWordCloudInfo();
+  }
+
+
+  public String loginNLP(LoginBody loginBody) {
+    SysUser sysUser = userService.selectUserByUserName(loginBody.getUsername());
+    String username = sysUser.getNlpName();
+    String password = sysUser.getNlpPwd();
+    // 调用登录
+    Map loginForm = new HashMap();
+    loginForm.put("username", username);
+    loginForm.put("password", password);
+    loginForm.put("userAgent", 1);
+    loginForm.put("client", "zdwxxtyc");
+    loginForm.put("saveUsername", true);
+    JSONObject json = RequestUtils.httpRequest2("http://10.70.192.135:8000/api/v2/auth/login/", "post", JSON.toJSONString(loginForm), null);
+    if ("SUCCESS".equals(MapUtils.getString(json, "status"))) {
+      JSONObject data = json.getJSONObject("data");
+      Map rs = new HashMap();
+      rs.put("uid", data.getString("uid"));
+      rs.put("nickname", data.getString("nickname"));
+      rs.put("status", data.getIntValue("status"));
+      rs.put("token", data.getString("token"));
+      rs.put("role", data.getIntValue("role"));
+      rs.put("language", "zh-CN");
+      rs.put("tier", 1);
+      return JSON.toJSONString(rs);
+    }
+    return null;
+  }
+
+
+  @Override
+  public Map initByDingtalk() throws Exception {
+    log.info("准备从钉钉接口调取部门及人员数据 ...");
+    Map rs = new HashMap();
+    // 查询钉钉所有部门跟用户
+    List<DingTalkDept> dingTalkDeptList = DingTalkUtils.getAll();
+    if (dingTalkDeptList == null || dingTalkDeptList.size() == 0) {
+      throw new RuntimeException("获取钉钉部门跟用户失败");
+    }
+    List<DingTalkUser> dingTalkUserList = new ArrayList<>();
+    dingTalkDeptList.stream().forEach(o -> {
+      dingTalkUserList.addAll(o.getUserList());
+    });
+    log.info("取到钉钉数据,总部门数量: {}, 总人员数量: {}", dingTalkDeptList.size(), dingTalkUserList.size());
+    rs.putAll(syncDingtalkDept(dingTalkDeptList));
+    rs.putAll(syncDingtalkUser(dingTalkUserList));
+    return rs;
+  }
+
+
+  private SysDept toDept(DingTalkDept dingTalkDept) {
+    SysDept dept = new SysDept();
+    dept.setDeptName(dingTalkDept.getName());
+    dept.setDingId(dingTalkDept.getId());
+    dept.setDingParentId(dingTalkDept.getParentId());
+    dept.setOrderNum(dingTalkDept.getOrderNum());
+    dept.setCreateTime(new Timestamp(System.currentTimeMillis()));
+    dept.setStatus(UserConstants.DEPT_NORMAL);
+    return dept;
+  }
+
+
+  /**
+   * 父部门,名称, 顺序 没变就认为没变
+   *
+   * @param dingTalkDept
+   * @param dept
+   * @return
+   */
+  private boolean isSame(DingTalkDept dingTalkDept, SysDept dept) {
+    return dept.getDeptName().equals(dingTalkDept.getName()) && dept.getParentId().equals(dingTalkDept.getParentId()) && dingTalkDept.getOrderNum().equals(dept.getOrderNum());
+  }
+
+  /**
+   * 同步部门
+   *
+   * @param dingTalkDeptList
+   * @return
+   */
+  private Map syncDingtalkDept(List<DingTalkDept> dingTalkDeptList) {
+    // 查询所有部门
+    SysDept deptParam = new SysDept();
+    List<SysDept> deptList = deptService.selectDeptList(deptParam);
+    if (deptList == null) {
+      deptList = new ArrayList<>();
+    }
+    List<SysDept> newList = new ArrayList<>();
+    List<SysDept> updateList = new ArrayList<>();
+    List<SysDept> delList = new ArrayList<>();
+    for (SysDept dept : deptList) {
+      // 非钉钉同步过来的数据,就忽略掉
+      if (dept.getDingId() == null) {
+        continue;
+      }
+      boolean isExist = false;
+      for (DingTalkDept dingTalkDept : dingTalkDeptList) {
+        // 如果存在,判断是否有修改
+        if (dept.getDingId().equals(dingTalkDept.getId())) {
+          isExist = true;
+          break;
+        }
+      }
+      if (isExist) {
+        DingTalkDept dingTalkDept = dingTalkDeptList.stream().filter(o -> o.getId().equals(dept.getDingId())).findFirst().get();
+        if (isSame(dingTalkDept, dept)) {
+          log.info("{}:{}未发生改变 ...", dept.getDeptName(), dept.getDingId());
+        } else {
+          log.info("{}:{}发生改变,更新 ...", dept.getDeptName(), dept.getDingId());
+          dept.setDeptName(dingTalkDept.getName());
+          dept.setDingParentId(dingTalkDept.getParentId());
+          dept.setOrderNum(dingTalkDept.getOrderNum());
+          dept.setUpdateTime(new Timestamp(System.currentTimeMillis()));
+          updateList.add(dept);
+        }
+      } else {// 如果不存在,就删掉数据
+        log.info("{}:{}已经不存在,删除 ...", dept.getDeptName(), dept.getDingId());
+        delList.add(dept);
+      }
+    }
+
+    for (DingTalkDept dingTalkDept : dingTalkDeptList) {
+      boolean isExist = false;
+      // 如果sys_dept中已经存在该部门,就忽略,否则新增
+      for (SysDept dept : deptList) {
+        if (dingTalkDept.getId().equals(dept.getDingId())) {
+          isExist = true;
+          break;
+        }
+      }
+      if (!isExist) {
+        log.info("{}:{}不存在,新增 ...", dingTalkDept.getName(), dingTalkDept.getId());
+        newList.add(toDept(dingTalkDept));
+      }
+    }
+
+    if (newList.size() > 0) {
+      log.info("新增部门 ...");
+      for (SysDept dept : newList) {
+        deptService.insertDept(dept);
+      }
+    }
+
+    if (updateList.size() > 0) {
+      log.info("更新部门 ...");
+      for (SysDept dept : updateList) {
+        deptService.updateDept(dept);
+      }
+    }
+
+    if (delList.size() > 0) {
+      log.info("删除部门 ...");
+      for (SysDept dept : delList) {
+        deptService.deleteDeptById(dept.getDeptId());
+      }
+    }
+
+    // 将parentId 等于 dingId 的 数据进行修复
+    //根据dingId, dingParentId 更新 parentId 的数据
+    log.info("同步钉钉部门数据的父子关系 ...");
+    userPortraitMapper.syncParentForDingtalk();
+
+    Map rs = new HashMap();
+    rs.put("deptNewCount", newList.size());
+    rs.put("deptUpdateCount", updateList.size());
+    rs.put("deptDelCount", delList.size());
+    return rs;
+  }
+
+
+  private SysUser toUser(DingTalkUser dingTalkUser) {
+    SysUser user = new SysUser();
+    user.setNickName(dingTalkUser.getName());
+    user.setUserName(dingTalkUser.getId());
+    user.setPhonenumber(dingTalkUser.getPhone());
+    user.setDingDeptId(dingTalkUser.getDeptId());
+    user.setDingUnionId(dingTalkUser.getUnionId());
+    user.setCreateTime(new Timestamp(System.currentTimeMillis()));
+    user.setStatus(UserConstants.DEPT_NORMAL);
+    return user;
+  }
+
+
+  /**
+   * 名称、部门、排序号没变就认为没变
+   *
+   * @param dingTalkUser
+   * @param sysUser
+   * @return
+   */
+  private boolean isSame(DingTalkUser dingTalkUser, SysUser sysUser) {
+    return sysUser.getNickName().equals(dingTalkUser.getName()) && sysUser.getDingDeptId().equals(dingTalkUser.getDeptId());
+  }
+
+  /**
+   * 同步人员
+   *
+   * @param dingTalkUserList
+   * @return
+   */
+  private Map syncDingtalkUser(List<DingTalkUser> dingTalkUserList) {
+    SysUser userParam = new SysUser();
+    List<SysUser> userList = userService.selectUserList(userParam);
+    List<SysUser> newList = new ArrayList<>();
+    List<SysUser> updateList = new ArrayList<>();
+    List<SysUser> delList = new ArrayList<>();
+    for (SysUser sysUser : userList) {
+      // 非钉钉同步过来的数据,就忽略掉
+      if (sysUser.getDingDeptId() == null) {
+        continue;
+      }
+      boolean isExist = false;
+      for (DingTalkUser dingTalkUser : dingTalkUserList) {
+        // 如果存在,判断是否有修改
+        if (sysUser.getUserName().equals(dingTalkUser.getId())) {
+          isExist = true;
+          break;
+        }
+      }
+      if (isExist) {
+        DingTalkUser dingTalkUser = dingTalkUserList.stream().filter(o -> o.getId().equals(sysUser.getUserName())).findFirst().get();
+        if (isSame(dingTalkUser, sysUser)) {
+          log.info("{}:{}未发生改变 ...", sysUser.getNickName(), sysUser.getUserId());
+        } else {
+          log.info("{}:{}发生改变,更新 ...", sysUser.getNickName(), sysUser.getUserId());
+          sysUser.setNickName(dingTalkUser.getName());
+          sysUser.setDingDeptId(dingTalkUser.getDeptId());
+          sysUser.setDingUnionId(dingTalkUser.getUnionId());
+          sysUser.setUpdateTime(new Timestamp(System.currentTimeMillis()));
+          updateList.add(sysUser);
+        }
+      } else {// 如果不存在,就删掉数据
+        log.info("{}:{}已经不存在,删除 ...", sysUser.getNickName(), sysUser.getUserId());
+        delList.add(sysUser);
+      }
+    }
+
+    for (DingTalkUser dingTalkUser : dingTalkUserList) {
+      boolean isExist = false;
+      // 如果sys_employee中已经存在该员工,就忽略,否则新增
+      for (SysUser sysUser : userList) {
+        if (dingTalkUser.getId().equals(sysUser.getUserName())) {
+          isExist = true;
+          break;
+        }
+      }
+      if (!isExist) {
+        log.info("{}:{}不存在,新增 ...", dingTalkUser.getName(), dingTalkUser.getId());
+        newList.add(toUser(dingTalkUser));
+      }
+    }
+
+    if (newList.size() > 0) {
+      log.info("新增员工 ...");
+
+      // 获取初始密码
+      String password = configService.selectConfigByKey("sys.user.initPassword");
+
+      for (SysUser sysUser : newList) {
+        sysUser.setPassword(SecurityUtils.encryptPassword(password));
+        userService.insertUser(sysUser);
+      }
+    }
+
+    if (updateList.size() > 0) {
+      log.info("更新员工 ...");
+      for (SysUser sysUser : updateList) {
+        userService.updateUser(sysUser);
+      }
+    }
+
+    if (delList.size() > 0) {
+      log.info("删除员工 ...");
+      for (SysUser sysUser : delList) {
+        userService.deleteUserById(sysUser.getUserId());
+      }
+    }
+
+    // 将parentId 等于 dingId 的 数据进行修复
+    //根据deptDingId 更新 deptId 的数据
+    log.info("同步钉钉员工数据的部门关系 ...");
+    userPortraitMapper.syncDeptForDingtalk();
+
+    Map rs = new HashMap();
+    rs.put("userNewCount", newList.size());
+    rs.put("userUpdateCount", updateList.size());
+    rs.put("userDelCount", delList.size());
+    return rs;
+  }
+
+  @Override
+  public Map updateNlp(String username, String nlpUserName, String nlpPassword) {
+    Map rs = new HashMap();
+    rs.put("success", 0);
+    SysUser sysUser = userService.selectUserByUserName(username);
+    if (sysUser == null) {
+      rs.put("msg", "用户不存在");
+      return rs;
     }
+    SysUser user = new SysUser();
+    user.setUserId(sysUser.getUserId());
+    user.setNlpName(nlpUserName);
+    user.setNlpPwd(nlpPassword);
+    userService.updateUser(user);
+    rs.put("success", 1);
+    rs.put("msg", "密码修改成功");
+    return rs;
+  }
 }

+ 56 - 0
xzl-admin/src/main/java/com/xzl/web/utils/RequestUtils.java

@@ -15,6 +15,7 @@ import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.URL;
 import java.net.UnknownHostException;
@@ -83,6 +84,61 @@ public class RequestUtils {
         return jsonObject;
     }
 
+
+  public static JSONObject httpRequest2(String requestUrl, String requestMethod, String outputStr, Map<String, String> headers) {
+    JSONObject jsonObject = null;
+    StringBuffer buffer = new StringBuffer();
+    try {
+      URL url = new URL(requestUrl);
+      HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
+      httpUrlConn.setDoOutput(true);
+      httpUrlConn.setDoInput(true);
+      httpUrlConn.setUseCaches(false);
+      httpUrlConn.setRequestMethod(requestMethod.toUpperCase());
+
+      if (headers != null) {
+        for (Map.Entry<String, String> entry : headers.entrySet()) {
+          httpUrlConn.setRequestProperty(entry.getKey(), entry.getValue());
+        }
+      }
+
+      if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect();
+      if ("POST".equalsIgnoreCase(requestMethod)) {
+        httpUrlConn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+        httpUrlConn.setRequestProperty("accept", "application/json");
+      }
+
+      if (null != outputStr) {
+        OutputStream outputStream = httpUrlConn.getOutputStream();
+        outputStream.write(outputStr.getBytes("UTF-8"));
+        outputStream.close();
+      }
+      InputStream inputStream = httpUrlConn.getInputStream();
+      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
+      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+      String str = null;
+      while ((str = bufferedReader.readLine()) != null) {
+        buffer.append(str);
+      }
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(buffer.toString());
+      }
+      bufferedReader.close();
+      inputStreamReader.close();
+      inputStream.close();
+      inputStream = null;
+      httpUrlConn.disconnect();
+      jsonObject = JSON.parseObject(buffer.toString());
+    } catch (Exception e) {
+      LOG.error("", e);
+      Object o = JSON.parse(buffer.toString());
+      if (o instanceof JSONArray) {
+        jsonObject = new JSONObject(ConstructUtils.map("items", JSON.parseArray(buffer.toString())));
+      }
+    }
+    return jsonObject;
+  }
+
     /**
      * 方法名:httpRequest</br>
      * 详述:发送http请求</br>

+ 62 - 0
xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkDept.java

@@ -0,0 +1,62 @@
+package com.xzl.web.utils.ali;
+
+import java.util.List;
+
+/**
+ * @ClassName: DingTalkDept
+ * @Description: 用于
+ * Modification History:
+ * Date                  Author                 Version       Description
+ * ---------------------------------------------------------
+ * 2023/10/16             ZhangShuling      v1.0.0
+ */
+public class DingTalkDept {
+
+  private Long id;
+  private Long parentId;
+  private String name;
+  private Integer orderNum;
+
+  private List<DingTalkUser> userList;
+
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public Long getParentId() {
+    return parentId;
+  }
+
+  public void setParentId(Long parentId) {
+    this.parentId = parentId;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Integer getOrderNum() {
+    return orderNum;
+  }
+
+  public void setOrderNum(Integer orderNum) {
+    this.orderNum = orderNum;
+  }
+
+  public List<DingTalkUser> getUserList() {
+    return userList;
+  }
+
+  public void setUserList(List<DingTalkUser> userList) {
+    this.userList = userList;
+  }
+}

+ 70 - 0
xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkUser.java

@@ -0,0 +1,70 @@
+package com.xzl.web.utils.ali;
+
+/**
+ * @ClassName: DingTalkUser
+ * @Description: 用于
+ * Modification History:
+ * Date                  Author                 Version       Description
+ * ---------------------------------------------------------
+ * 2023/10/16             ZhangShuling      v1.0.0
+ */
+public class DingTalkUser {
+
+  private String id;
+  private String name;
+  private String phone;
+
+  private String unionId;
+
+  private Long deptId;
+  private Integer orderNum;
+
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getPhone() {
+    return phone;
+  }
+
+  public void setPhone(String phone) {
+    this.phone = phone;
+  }
+
+  public String getUnionId() {
+    return unionId;
+  }
+
+  public void setUnionId(String unionId) {
+    this.unionId = unionId;
+  }
+
+  public Long getDeptId() {
+    return deptId;
+  }
+
+  public void setDeptId(Long deptId) {
+    this.deptId = deptId;
+  }
+
+  public Integer getOrderNum() {
+    return orderNum;
+  }
+
+  public void setOrderNum(Integer orderNum) {
+    this.orderNum = orderNum;
+  }
+}

+ 159 - 0
xzl-admin/src/main/java/com/xzl/web/utils/ali/DingTalkUtils.java

@@ -0,0 +1,159 @@
+package com.xzl.web.utils.ali;
+
+import com.alibaba.fastjson.JSON;
+import com.dingtalk.api.DefaultDingTalkClient;
+import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.*;
+import com.dingtalk.api.response.*;
+import com.taobao.api.ApiException;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ClassName: DingTalkUtils
+ * @Description: 用于
+ * Modification History:
+ * Date                  Author                 Version       Description
+ * ---------------------------------------------------------
+ * 2023/10/16             ZhangShuling      v1.0.0
+ */
+public class DingTalkUtils {
+
+//  private final static String AGENTID = "2138717300";
+//  private final static String APPID = "dingbtl3gxqdig8qriyg";
+//  private final static String SECRET = "-P01MC0sllA0mPw1QU27gvHLP90LMgtbBfSB9d2_xAqVF4z_ov-Mx5KTkyltSF-q";
+
+
+  private final static String AGENTID = "2942724113";
+  private final static String APPID = "dingr2toeanbqkmhitkx";
+  private final static String SECRET = "IC_jU9Poawrq3TlWrfHhbtVEpsKtWo95J3AeCukKXTCui4bcLr8CYJ290lGsfeqR";
+
+  public static String getAccessToken() throws ApiException {
+    DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+    OapiGettokenRequest req = new OapiGettokenRequest();
+    req.setAppkey(APPID);
+    req.setAppsecret(SECRET);
+    req.setHttpMethod("GET");
+    OapiGettokenResponse rsp = client.execute(req);
+    return rsp.getAccessToken();
+  }
+
+  public static void getDeptList(List<DingTalkDept> deptList, String accessToken, Long parentId, int parentOrderNum) throws ApiException {
+    DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+    OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
+    req.setDeptId(parentId);
+    req.setLanguage("zh_CN");
+    OapiV2DepartmentListsubResponse rsp = client.execute(req, accessToken);
+    List<OapiV2DepartmentListsubResponse.DeptBaseResponse> deptRspList = rsp.getResult();
+    if (deptRspList == null || deptRspList.size() == 0) {
+      return;
+    }
+    int i = 1;
+    for (OapiV2DepartmentListsubResponse.DeptBaseResponse dept : deptRspList) {
+      DingTalkDept d = new DingTalkDept();
+      d.setName(dept.getName());
+      d.setId(dept.getDeptId());
+      d.setParentId(dept.getParentId());
+      d.setOrderNum(parentOrderNum * 100 + i);
+      d.setUserList(getUserList(accessToken, d.getId()));
+      deptList.add(d);
+      i++;
+      getDeptList(deptList, accessToken, d.getId(), d.getOrderNum());
+    }
+  }
+
+  public static List<DingTalkUser> getUserList(String accessToken, Long deptId) throws ApiException {
+    DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
+    OapiV2UserListRequest req = new OapiV2UserListRequest();
+    req.setDeptId(deptId);
+    req.setCursor(0L);
+    // 一个部门不会有100个人,此处就直接查100个人内
+    req.setSize(100L);
+    req.setOrderField("modify_desc");
+    req.setContainAccessLimit(false);
+    req.setLanguage("zh_CN");
+    OapiV2UserListResponse rsp = client.execute(req, accessToken);
+    OapiV2UserListResponse.PageResult userPageResult = rsp.getResult();
+    List<OapiV2UserListResponse.ListUserResponse> userRspList = userPageResult.getList();
+    if (userRspList == null || userRspList.size() == 0) {
+      return null;
+    }
+    List<DingTalkUser> userList = new ArrayList<>();
+    int i = 1;
+    for (OapiV2UserListResponse.ListUserResponse user : userRspList) {
+      DingTalkUser u = new DingTalkUser();
+      // 用工号作为ID
+      u.setId(user.getJobNumber());
+      // 有的用户可能没有录入工号
+      if (StringUtils.isBlank(u.getId())) {
+        u.setId(user.getUserid());
+      }
+      u.setName(user.getName());
+      u.setPhone(user.getMobile());
+      u.setDeptId(deptId);
+      u.setOrderNum(i);
+      userList.add(u);
+      i++;
+    }
+    return userList;
+  }
+
+  public static List<DingTalkDept> getAll() throws Exception {
+    String accessToken = getAccessToken();
+    Long rootDeptId = 1L;
+    List<DingTalkDept> deptList = new ArrayList<>();
+    getDeptList(deptList, accessToken, rootDeptId, 0);
+    return deptList;
+  }
+
+  public static void main(String[] args) throws Exception {
+    List<DingTalkDept> deptList = getAll();
+    System.out.println(JSON.toJSONString(deptList));
+
+//    String accessToken = getAccessToken();
+//    List<String> userIds = new ArrayList<>();
+//    userIds.add("124355663324054060");
+//    sendMessage(accessToken, AGENTID, "测试", userIds);
+  }
+
+  public static OapiSnsGetuserinfoBycodeResponse ddlogin(String code) throws Exception {
+//    DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
+//    OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
+//    req.setCode(code);
+//    String accessToken = getAccessToken();
+//    System.out.println("accessToken : " +accessToken);
+//    OapiV2UserGetuserinfoResponse rsp = client.execute(req, accessToken);
+//    System.out.println(JSON.toJSON(rsp));
+
+
+    DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
+    OapiSnsGetuserinfoBycodeRequest req = new OapiSnsGetuserinfoBycodeRequest();
+    req.setTmpAuthCode(code);
+    OapiSnsGetuserinfoBycodeResponse response = client.execute(req, APPID, SECRET);
+    System.out.println(JSON.toJSON(response));
+    return response;
+  }
+
+  public static void sendMessage(String accessToken, String agentId, String message, List<String> userIds) throws ApiException {
+    DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
+    OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
+    request.setAgentId(Long.valueOf(agentId));
+    request.setUseridList(StringUtils.join(userIds, ","));
+    request.setToAllUser(false);
+
+    OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
+    msg.setMsgtype("text");
+    msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
+    msg.getText().setContent(message);
+
+    request.setMsg(msg);
+    OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(request, accessToken);
+    System.out.println(rsp.getBody());
+  }
+
+}

+ 1 - 1
xzl-admin/src/main/resources/application.yml

@@ -97,7 +97,7 @@ token:
   # 令牌密钥
   secret: abcdefghijklmnopqrstuvwxyz
   # 令牌有效期(默认30分钟)
-  expireTime: 30
+  expireTime: 240
 
 # MyBatis配置
 mybatis:

+ 20 - 0
xzl-admin/src/main/resources/mapper/UserPortraitMapper.xml

@@ -15,4 +15,24 @@
     </select>
 
 
+
+
+    <!-- 同步钉钉部门数据的父子关系-->
+    <update id="syncParentForDingtalk">
+    update sys_dept d1,
+    ( select t1.dept_id,
+      coalesce((select t2.dept_id from sys_dept t2 where t2.ding_id = t1.ding_parent_id),'0') as parent_id,
+      t1.ding_id,
+      t1.ding_parent_id  from sys_dept t1
+      where t1.ding_id is not null
+    ) d2
+    set d1.parent_id =  d2.parent_id
+    where d1.dept_id =  d2.dept_id
+  </update>
+
+    <update id="syncDeptForDingtalk">
+    update sys_user e, sys_dept d
+    set e.dept_id = d.dept_id
+    where e.ding_dept_id = d.ding_id
+  </update>
 </mapper>

+ 19 - 0
xzl-common/src/main/java/com/xzl/common/core/domain/entity/SysDept.java

@@ -51,6 +51,9 @@ public class SysDept extends BaseEntity
 
     /** 父部门名称 */
     private String parentName;
+
+    private Long dingId;
+    private Long dingParentId;
     
     /** 子部门 */
     private List<SysDept> children = new ArrayList<SysDept>();
@@ -181,6 +184,22 @@ public class SysDept extends BaseEntity
         this.children = children;
     }
 
+    public Long getDingId() {
+        return dingId;
+    }
+
+    public void setDingId(Long dingId) {
+        this.dingId = dingId;
+    }
+
+    public Long getDingParentId() {
+        return dingParentId;
+    }
+
+    public void setDingParentId(Long dingParentId) {
+        this.dingParentId = dingParentId;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

+ 336 - 302
xzl-common/src/main/java/com/xzl/common/core/domain/entity/SysUser.java

@@ -3,6 +3,7 @@ package com.xzl.common.core.domain.entity;
 import java.util.Date;
 import java.util.List;
 import javax.validation.constraints.*;
+
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.xzl.common.annotation.Excel;
@@ -14,311 +15,344 @@ import com.xzl.common.xss.Xss;
 
 /**
  * 用户对象 sys_user
- * 
+ *
  * @author xzl
  */
-public class SysUser extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
+public class SysUser extends BaseEntity {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * 用户ID
+   */
+  @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
+  private Long userId;
+
+  /**
+   * 部门ID
+   */
+  @Excel(name = "部门编号", type = Type.IMPORT)
+  private Long deptId;
+
+  /**
+   * 用户账号
+   */
+  @Excel(name = "登录名称")
+  private String userName;
+
+  /**
+   * 用户昵称
+   */
+  @Excel(name = "用户名称")
+  private String nickName;
+
+  /**
+   * 用户邮箱
+   */
+  @Excel(name = "用户邮箱")
+  private String email;
+
+  /**
+   * 手机号码
+   */
+  @Excel(name = "手机号码")
+  private String phonenumber;
+
+  /**
+   * 用户性别
+   */
+  @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+  private String sex;
+
+  /**
+   * 用户头像
+   */
+  private String avatar;
+
+  /**
+   * 密码
+   */
+  private String password;
+
+  /**
+   * 帐号状态(0正常 1停用)
+   */
+  @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+  private String status;
+
+  /**
+   * 删除标志(0代表存在 2代表删除)
+   */
+  private String delFlag;
+
+  /**
+   * 最后登录IP
+   */
+  @Excel(name = "最后登录IP", type = Type.EXPORT)
+  private String loginIp;
+
+  /**
+   * 最后登录时间
+   */
+  @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
+  private Date loginDate;
+
+  /**
+   * 部门对象
+   */
+  @Excels({
+    @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
+    @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
+  })
+  private SysDept dept;
+
+  /**
+   * 角色对象
+   */
+  private List<SysRole> roles;
+
+  /**
+   * 角色组
+   */
+  private Long[] roleIds;
+
+  /**
+   * 岗位组
+   */
+  private Long[] postIds;
+
+  /**
+   * 角色ID
+   */
+  private Long roleId;
+
+  private Long dingDeptId;
+  private String dingUnionId;
+
+  private String nlpName;
+  private String nlpPwd;
+
+  public SysUser() {
+
+  }
+
+  public SysUser(Long userId) {
+    this.userId = userId;
+  }
+
+  public Long getUserId() {
+    return userId;
+  }
+
+  public void setUserId(Long userId) {
+    this.userId = userId;
+  }
+
+  public boolean isAdmin() {
+    return isAdmin(this.userId);
+  }
+
+  public static boolean isAdmin(Long userId) {
+    return userId != null && 1L == userId;
+  }
+
+  public Long getDeptId() {
+    return deptId;
+  }
+
+  public void setDeptId(Long deptId) {
+    this.deptId = deptId;
+  }
+
+  @Xss(message = "用户昵称不能包含脚本字符")
+  @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+  public String getNickName() {
+    return nickName;
+  }
+
+  public void setNickName(String nickName) {
+    this.nickName = nickName;
+  }
+
+  @Xss(message = "用户账号不能包含脚本字符")
+  @NotBlank(message = "用户账号不能为空")
+  @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+  public String getUserName() {
+    return userName;
+  }
+
+  public void setUserName(String userName) {
+    this.userName = userName;
+  }
+
+  @Email(message = "邮箱格式不正确")
+  @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+  public String getEmail() {
+    return email;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+  @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+  public String getPhonenumber() {
+    return phonenumber;
+  }
+
+  public void setPhonenumber(String phonenumber) {
+    this.phonenumber = phonenumber;
+  }
+
+  public String getSex() {
+    return sex;
+  }
+
+  public void setSex(String sex) {
+    this.sex = sex;
+  }
+
+  public String getAvatar() {
+    return avatar;
+  }
+
+  public void setAvatar(String avatar) {
+    this.avatar = avatar;
+  }
+
+  public String getPassword() {
+    return password;
+  }
 
-    /** 用户ID */
-    @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
-    private Long userId;
+  public void setPassword(String password) {
+    this.password = password;
+  }
 
-    /** 部门ID */
-    @Excel(name = "部门编号", type = Type.IMPORT)
-    private Long deptId;
+  public String getStatus() {
+    return status;
+  }
 
-    /** 用户账号 */
-    @Excel(name = "登录名称")
-    private String userName;
-
-    /** 用户昵称 */
-    @Excel(name = "用户名称")
-    private String nickName;
-
-    /** 用户邮箱 */
-    @Excel(name = "用户邮箱")
-    private String email;
-
-    /** 手机号码 */
-    @Excel(name = "手机号码")
-    private String phonenumber;
-
-    /** 用户性别 */
-    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
-    private String sex;
-
-    /** 用户头像 */
-    private String avatar;
-
-    /** 密码 */
-    private String password;
-
-    /** 帐号状态(0正常 1停用) */
-    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
-    private String status;
-
-    /** 删除标志(0代表存在 2代表删除) */
-    private String delFlag;
-
-    /** 最后登录IP */
-    @Excel(name = "最后登录IP", type = Type.EXPORT)
-    private String loginIp;
-
-    /** 最后登录时间 */
-    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
-    private Date loginDate;
-
-    /** 部门对象 */
-    @Excels({
-        @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
-        @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
-    })
-    private SysDept dept;
-
-    /** 角色对象 */
-    private List<SysRole> roles;
-
-    /** 角色组 */
-    private Long[] roleIds;
-
-    /** 岗位组 */
-    private Long[] postIds;
-
-    /** 角色ID */
-    private Long roleId;
-
-    public SysUser()
-    {
-
-    }
-
-    public SysUser(Long userId)
-    {
-        this.userId = userId;
-    }
-
-    public Long getUserId()
-    {
-        return userId;
-    }
-
-    public void setUserId(Long userId)
-    {
-        this.userId = userId;
-    }
-
-    public boolean isAdmin()
-    {
-        return isAdmin(this.userId);
-    }
-
-    public static boolean isAdmin(Long userId)
-    {
-        return userId != null && 1L == userId;
-    }
-
-    public Long getDeptId()
-    {
-        return deptId;
-    }
-
-    public void setDeptId(Long deptId)
-    {
-        this.deptId = deptId;
-    }
-
-    @Xss(message = "用户昵称不能包含脚本字符")
-    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
-    public String getNickName()
-    {
-        return nickName;
-    }
-
-    public void setNickName(String nickName)
-    {
-        this.nickName = nickName;
-    }
-
-    @Xss(message = "用户账号不能包含脚本字符")
-    @NotBlank(message = "用户账号不能为空")
-    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
-    public String getUserName()
-    {
-        return userName;
-    }
-
-    public void setUserName(String userName)
-    {
-        this.userName = userName;
-    }
-
-    @Email(message = "邮箱格式不正确")
-    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
-    public String getEmail()
-    {
-        return email;
-    }
-
-    public void setEmail(String email)
-    {
-        this.email = email;
-    }
-
-    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
-    public String getPhonenumber()
-    {
-        return phonenumber;
-    }
-
-    public void setPhonenumber(String phonenumber)
-    {
-        this.phonenumber = phonenumber;
-    }
-
-    public String getSex()
-    {
-        return sex;
-    }
-
-    public void setSex(String sex)
-    {
-        this.sex = sex;
-    }
-
-    public String getAvatar()
-    {
-        return avatar;
-    }
-
-    public void setAvatar(String avatar)
-    {
-        this.avatar = avatar;
-    }
-
-    public String getPassword()
-    {
-        return password;
-    }
-
-    public void setPassword(String password)
-    {
-        this.password = password;
-    }
-
-    public String getStatus()
-    {
-        return status;
-    }
-
-    public void setStatus(String status)
-    {
-        this.status = status;
-    }
-
-    public String getDelFlag()
-    {
-        return delFlag;
-    }
-
-    public void setDelFlag(String delFlag)
-    {
-        this.delFlag = delFlag;
-    }
-
-    public String getLoginIp()
-    {
-        return loginIp;
-    }
-
-    public void setLoginIp(String loginIp)
-    {
-        this.loginIp = loginIp;
-    }
-
-    public Date getLoginDate()
-    {
-        return loginDate;
-    }
-
-    public void setLoginDate(Date loginDate)
-    {
-        this.loginDate = loginDate;
-    }
-
-    public SysDept getDept()
-    {
-        return dept;
-    }
-
-    public void setDept(SysDept dept)
-    {
-        this.dept = dept;
-    }
-
-    public List<SysRole> getRoles()
-    {
-        return roles;
-    }
-
-    public void setRoles(List<SysRole> roles)
-    {
-        this.roles = roles;
-    }
-
-    public Long[] getRoleIds()
-    {
-        return roleIds;
-    }
-
-    public void setRoleIds(Long[] roleIds)
-    {
-        this.roleIds = roleIds;
-    }
-
-    public Long[] getPostIds()
-    {
-        return postIds;
-    }
-
-    public void setPostIds(Long[] postIds)
-    {
-        this.postIds = postIds;
-    }
-
-    public Long getRoleId()
-    {
-        return roleId;
-    }
-
-    public void setRoleId(Long roleId)
-    {
-        this.roleId = roleId;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("userId", getUserId())
-            .append("deptId", getDeptId())
-            .append("userName", getUserName())
-            .append("nickName", getNickName())
-            .append("email", getEmail())
-            .append("phonenumber", getPhonenumber())
-            .append("sex", getSex())
-            .append("avatar", getAvatar())
-            .append("password", getPassword())
-            .append("status", getStatus())
-            .append("delFlag", getDelFlag())
-            .append("loginIp", getLoginIp())
-            .append("loginDate", getLoginDate())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .append("dept", getDept())
-            .toString();
-    }
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getDelFlag() {
+    return delFlag;
+  }
+
+  public void setDelFlag(String delFlag) {
+    this.delFlag = delFlag;
+  }
+
+  public String getLoginIp() {
+    return loginIp;
+  }
+
+  public void setLoginIp(String loginIp) {
+    this.loginIp = loginIp;
+  }
+
+  public Date getLoginDate() {
+    return loginDate;
+  }
+
+  public void setLoginDate(Date loginDate) {
+    this.loginDate = loginDate;
+  }
+
+  public SysDept getDept() {
+    return dept;
+  }
+
+  public void setDept(SysDept dept) {
+    this.dept = dept;
+  }
+
+  public List<SysRole> getRoles() {
+    return roles;
+  }
+
+  public void setRoles(List<SysRole> roles) {
+    this.roles = roles;
+  }
+
+  public Long[] getRoleIds() {
+    return roleIds;
+  }
+
+  public void setRoleIds(Long[] roleIds) {
+    this.roleIds = roleIds;
+  }
+
+  public Long[] getPostIds() {
+    return postIds;
+  }
+
+  public void setPostIds(Long[] postIds) {
+    this.postIds = postIds;
+  }
+
+  public Long getRoleId() {
+    return roleId;
+  }
+
+  public void setRoleId(Long roleId) {
+    this.roleId = roleId;
+  }
+
+  public Long getDingDeptId() {
+    return dingDeptId;
+  }
+
+  public void setDingDeptId(Long dingDeptId) {
+    this.dingDeptId = dingDeptId;
+  }
+
+  public String getDingUnionId() {
+    return dingUnionId;
+  }
+
+  public void setDingUnionId(String dingUnionId) {
+    this.dingUnionId = dingUnionId;
+  }
+
+  public String getNlpName() {
+    return nlpName;
+  }
+
+  public void setNlpName(String nlpName) {
+    this.nlpName = nlpName;
+  }
+
+  public String getNlpPwd() {
+    return nlpPwd;
+  }
+
+  public void setNlpPwd(String nlpPwd) {
+    this.nlpPwd = nlpPwd;
+  }
+
+  @Override
+  public String toString() {
+    return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+      .append("userId", getUserId())
+      .append("deptId", getDeptId())
+      .append("userName", getUserName())
+      .append("nickName", getNickName())
+      .append("email", getEmail())
+      .append("phonenumber", getPhonenumber())
+      .append("sex", getSex())
+      .append("avatar", getAvatar())
+      .append("password", getPassword())
+      .append("status", getStatus())
+      .append("delFlag", getDelFlag())
+      .append("loginIp", getLoginIp())
+      .append("loginDate", getLoginDate())
+      .append("createBy", getCreateBy())
+      .append("createTime", getCreateTime())
+      .append("updateBy", getUpdateBy())
+      .append("updateTime", getUpdateTime())
+      .append("remark", getRemark())
+      .append("dept", getDept())
+      .toString();
+  }
 }

+ 250 - 281
xzl-system/src/main/java/com/xzl/system/service/impl/SysDeptServiceImpl.java

@@ -4,6 +4,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.xzl.common.annotation.DataScope;
@@ -23,316 +24,284 @@ import com.xzl.system.service.ISysDeptService;
 
 /**
  * 部门管理 服务实现
- * 
+ *
  * @author xzl
  */
 @Service
-public class SysDeptServiceImpl implements ISysDeptService
-{
-    @Autowired
-    private SysDeptMapper deptMapper;
+public class SysDeptServiceImpl implements ISysDeptService {
+  @Autowired
+  private SysDeptMapper deptMapper;
 
-    @Autowired
-    private SysRoleMapper roleMapper;
+  @Autowired
+  private SysRoleMapper roleMapper;
 
-    /**
-     * 查询部门管理数据
-     * 
-     * @param dept 部门信息
-     * @return 部门信息集合
-     */
-    @Override
-    @DataScope(deptAlias = "d")
-    public List<SysDept> selectDeptList(SysDept dept)
-    {
-        return deptMapper.selectDeptList(dept);
-    }
+  /**
+   * 查询部门管理数据
+   *
+   * @param dept 部门信息
+   * @return 部门信息集合
+   */
+  @Override
+  @DataScope(deptAlias = "d")
+  public List<SysDept> selectDeptList(SysDept dept) {
+    return deptMapper.selectDeptList(dept);
+  }
 
-    /**
-     * 查询部门树结构信息
-     * 
-     * @param dept 部门信息
-     * @return 部门树信息集合
-     */
-    @Override
-    public List<TreeSelect> selectDeptTreeList(SysDept dept)
-    {
-        List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
-        return buildDeptTreeSelect(depts);
-    }
+  /**
+   * 查询部门树结构信息
+   *
+   * @param dept 部门信息
+   * @return 部门树信息集合
+   */
+  @Override
+  public List<TreeSelect> selectDeptTreeList(SysDept dept) {
+    List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
+    return buildDeptTreeSelect(depts);
+  }
 
-    /**
-     * 构建前端所需要树结构
-     * 
-     * @param depts 部门列表
-     * @return 树结构列表
-     */
-    @Override
-    public List<SysDept> buildDeptTree(List<SysDept> depts)
-    {
-        List<SysDept> returnList = new ArrayList<SysDept>();
-        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
-        for (SysDept dept : depts)
-        {
-            // 如果是顶级节点, 遍历该父节点的所有子节点
-            if (!tempList.contains(dept.getParentId()))
-            {
-                recursionFn(depts, dept);
-                returnList.add(dept);
-            }
-        }
-        if (returnList.isEmpty())
-        {
-            returnList = depts;
-        }
-        return returnList;
+  /**
+   * 构建前端所需要树结构
+   *
+   * @param depts 部门列表
+   * @return 树结构列表
+   */
+  @Override
+  public List<SysDept> buildDeptTree(List<SysDept> depts) {
+    List<SysDept> returnList = new ArrayList<SysDept>();
+    List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
+    for (SysDept dept : depts) {
+      // 如果是顶级节点, 遍历该父节点的所有子节点
+      if (!tempList.contains(dept.getParentId())) {
+        recursionFn(depts, dept);
+        returnList.add(dept);
+      }
     }
-
-    /**
-     * 构建前端所需要下拉树结构
-     * 
-     * @param depts 部门列表
-     * @return 下拉树结构列表
-     */
-    @Override
-    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts)
-    {
-        List<SysDept> deptTrees = buildDeptTree(depts);
-        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
+    if (returnList.isEmpty()) {
+      returnList = depts;
     }
+    return returnList;
+  }
 
-    /**
-     * 根据角色ID查询部门树信息
-     * 
-     * @param roleId 角色ID
-     * @return 选中部门列表
-     */
-    @Override
-    public List<Long> selectDeptListByRoleId(Long roleId)
-    {
-        SysRole role = roleMapper.selectRoleById(roleId);
-        return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
-    }
+  /**
+   * 构建前端所需要下拉树结构
+   *
+   * @param depts 部门列表
+   * @return 下拉树结构列表
+   */
+  @Override
+  public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
+    List<SysDept> deptTrees = buildDeptTree(depts);
+    return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
+  }
 
-    /**
-     * 根据部门ID查询信息
-     * 
-     * @param deptId 部门ID
-     * @return 部门信息
-     */
-    @Override
-    public SysDept selectDeptById(Long deptId)
-    {
-        return deptMapper.selectDeptById(deptId);
-    }
+  /**
+   * 根据角色ID查询部门树信息
+   *
+   * @param roleId 角色ID
+   * @return 选中部门列表
+   */
+  @Override
+  public List<Long> selectDeptListByRoleId(Long roleId) {
+    SysRole role = roleMapper.selectRoleById(roleId);
+    return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
+  }
 
-    /**
-     * 根据ID查询所有子部门(正常状态)
-     * 
-     * @param deptId 部门ID
-     * @return 子部门数
-     */
-    @Override
-    public int selectNormalChildrenDeptById(Long deptId)
-    {
-        return deptMapper.selectNormalChildrenDeptById(deptId);
-    }
+  /**
+   * 根据部门ID查询信息
+   *
+   * @param deptId 部门ID
+   * @return 部门信息
+   */
+  @Override
+  public SysDept selectDeptById(Long deptId) {
+    return deptMapper.selectDeptById(deptId);
+  }
 
-    /**
-     * 是否存在子节点
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    @Override
-    public boolean hasChildByDeptId(Long deptId)
-    {
-        int result = deptMapper.hasChildByDeptId(deptId);
-        return result > 0;
-    }
+  /**
+   * 根据ID查询所有子部门(正常状态)
+   *
+   * @param deptId 部门ID
+   * @return 子部门数
+   */
+  @Override
+  public int selectNormalChildrenDeptById(Long deptId) {
+    return deptMapper.selectNormalChildrenDeptById(deptId);
+  }
 
-    /**
-     * 查询部门是否存在用户
-     * 
-     * @param deptId 部门ID
-     * @return 结果 true 存在 false 不存在
-     */
-    @Override
-    public boolean checkDeptExistUser(Long deptId)
-    {
-        int result = deptMapper.checkDeptExistUser(deptId);
-        return result > 0;
-    }
+  /**
+   * 是否存在子节点
+   *
+   * @param deptId 部门ID
+   * @return 结果
+   */
+  @Override
+  public boolean hasChildByDeptId(Long deptId) {
+    int result = deptMapper.hasChildByDeptId(deptId);
+    return result > 0;
+  }
 
-    /**
-     * 校验部门名称是否唯一
-     * 
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public boolean checkDeptNameUnique(SysDept dept)
-    {
-        Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
-        SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
-        if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())
-        {
-            return UserConstants.NOT_UNIQUE;
-        }
-        return UserConstants.UNIQUE;
-    }
+  /**
+   * 查询部门是否存在用户
+   *
+   * @param deptId 部门ID
+   * @return 结果 true 存在 false 不存在
+   */
+  @Override
+  public boolean checkDeptExistUser(Long deptId) {
+    int result = deptMapper.checkDeptExistUser(deptId);
+    return result > 0;
+  }
 
-    /**
-     * 校验部门是否有数据权限
-     * 
-     * @param deptId 部门id
-     */
-    @Override
-    public void checkDeptDataScope(Long deptId)
-    {
-        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
-        {
-            SysDept dept = new SysDept();
-            dept.setDeptId(deptId);
-            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
-            if (StringUtils.isEmpty(depts))
-            {
-                throw new ServiceException("没有权限访问部门数据!");
-            }
-        }
+  /**
+   * 校验部门名称是否唯一
+   *
+   * @param dept 部门信息
+   * @return 结果
+   */
+  @Override
+  public boolean checkDeptNameUnique(SysDept dept) {
+    Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
+    SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
+    if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) {
+      return UserConstants.NOT_UNIQUE;
     }
+    return UserConstants.UNIQUE;
+  }
 
-    /**
-     * 新增保存部门信息
-     * 
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public int insertDept(SysDept dept)
-    {
-        SysDept info = deptMapper.selectDeptById(dept.getParentId());
-        // 如果父节点不为正常状态,则不允许新增子节点
-        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
-        {
-            throw new ServiceException("部门停用,不允许新增");
-        }
-        dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
-        return deptMapper.insertDept(dept);
+  /**
+   * 校验部门是否有数据权限
+   *
+   * @param deptId 部门id
+   */
+  @Override
+  public void checkDeptDataScope(Long deptId) {
+    if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
+      SysDept dept = new SysDept();
+      dept.setDeptId(deptId);
+      List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
+      if (StringUtils.isEmpty(depts)) {
+        throw new ServiceException("没有权限访问部门数据!");
+      }
     }
+  }
 
-    /**
-     * 修改保存部门信息
-     * 
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public int updateDept(SysDept dept)
-    {
-        SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
-        SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
-        if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
-        {
-            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
-            String oldAncestors = oldDept.getAncestors();
-            dept.setAncestors(newAncestors);
-            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
-        }
-        int result = deptMapper.updateDept(dept);
-        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
-                && !StringUtils.equals("0", dept.getAncestors()))
-        {
-            // 如果该部门是启用状态,则启用该部门的所有上级部门
-            updateParentDeptStatusNormal(dept);
-        }
-        return result;
+  /**
+   * 新增保存部门信息
+   *
+   * @param dept 部门信息
+   * @return 结果
+   */
+  @Override
+  public int insertDept(SysDept dept) {
+    if (dept.getParentId() == null) {
+      return deptMapper.insertDept(dept);
     }
-
-    /**
-     * 修改该部门的父级部门状态
-     * 
-     * @param dept 当前部门
-     */
-    private void updateParentDeptStatusNormal(SysDept dept)
-    {
-        String ancestors = dept.getAncestors();
-        Long[] deptIds = Convert.toLongArray(ancestors);
-        deptMapper.updateDeptStatusNormal(deptIds);
+    SysDept info = deptMapper.selectDeptById(dept.getParentId());
+    // 如果父节点不为正常状态,则不允许新增子节点
+    if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
+      throw new ServiceException("部门停用,不允许新增");
     }
+    dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
+    return deptMapper.insertDept(dept);
+  }
 
-    /**
-     * 修改子元素关系
-     * 
-     * @param deptId 被修改的部门ID
-     * @param newAncestors 新的父ID集合
-     * @param oldAncestors 旧的父ID集合
-     */
-    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
-    {
-        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
-        for (SysDept child : children)
-        {
-            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
-        }
-        if (children.size() > 0)
-        {
-            deptMapper.updateDeptChildren(children);
-        }
+  /**
+   * 修改保存部门信息
+   *
+   * @param dept 部门信息
+   * @return 结果
+   */
+  @Override
+  public int updateDept(SysDept dept) {
+    SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
+    SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
+    if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) {
+      String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
+      String oldAncestors = oldDept.getAncestors();
+      dept.setAncestors(newAncestors);
+      updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
     }
-
-    /**
-     * 删除部门管理信息
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    @Override
-    public int deleteDeptById(Long deptId)
-    {
-        return deptMapper.deleteDeptById(deptId);
+    int result = deptMapper.updateDept(dept);
+    if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+      && !StringUtils.equals("0", dept.getAncestors())) {
+      // 如果该部门是启用状态,则启用该部门的所有上级部门
+      updateParentDeptStatusNormal(dept);
     }
+    return result;
+  }
 
-    /**
-     * 递归列表
-     */
-    private void recursionFn(List<SysDept> list, SysDept t)
-    {
-        // 得到子节点列表
-        List<SysDept> childList = getChildList(list, t);
-        t.setChildren(childList);
-        for (SysDept tChild : childList)
-        {
-            if (hasChild(list, tChild))
-            {
-                recursionFn(list, tChild);
-            }
-        }
+  /**
+   * 修改该部门的父级部门状态
+   *
+   * @param dept 当前部门
+   */
+  private void updateParentDeptStatusNormal(SysDept dept) {
+    String ancestors = dept.getAncestors();
+    Long[] deptIds = Convert.toLongArray(ancestors);
+    deptMapper.updateDeptStatusNormal(deptIds);
+  }
+
+  /**
+   * 修改子元素关系
+   *
+   * @param deptId       被修改的部门ID
+   * @param newAncestors 新的父ID集合
+   * @param oldAncestors 旧的父ID集合
+   */
+  public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
+    List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
+    for (SysDept child : children) {
+      child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
+    }
+    if (children.size() > 0) {
+      deptMapper.updateDeptChildren(children);
     }
+  }
 
-    /**
-     * 得到子节点列表
-     */
-    private List<SysDept> getChildList(List<SysDept> list, SysDept t)
-    {
-        List<SysDept> tlist = new ArrayList<SysDept>();
-        Iterator<SysDept> it = list.iterator();
-        while (it.hasNext())
-        {
-            SysDept n = (SysDept) it.next();
-            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue())
-            {
-                tlist.add(n);
-            }
-        }
-        return tlist;
+  /**
+   * 删除部门管理信息
+   *
+   * @param deptId 部门ID
+   * @return 结果
+   */
+  @Override
+  public int deleteDeptById(Long deptId) {
+    return deptMapper.deleteDeptById(deptId);
+  }
+
+  /**
+   * 递归列表
+   */
+  private void recursionFn(List<SysDept> list, SysDept t) {
+    // 得到子节点列表
+    List<SysDept> childList = getChildList(list, t);
+    t.setChildren(childList);
+    for (SysDept tChild : childList) {
+      if (hasChild(list, tChild)) {
+        recursionFn(list, tChild);
+      }
     }
+  }
 
-    /**
-     * 判断是否有子节点
-     */
-    private boolean hasChild(List<SysDept> list, SysDept t)
-    {
-        return getChildList(list, t).size() > 0;
+  /**
+   * 得到子节点列表
+   */
+  private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
+    List<SysDept> tlist = new ArrayList<SysDept>();
+    Iterator<SysDept> it = list.iterator();
+    while (it.hasNext()) {
+      SysDept n = (SysDept) it.next();
+      if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
+        tlist.add(n);
+      }
     }
+    return tlist;
+  }
+
+  /**
+   * 判断是否有子节点
+   */
+  private boolean hasChild(List<SysDept> list, SysDept t) {
+    return getChildList(list, t).size() > 0;
+  }
 }

+ 10 - 1
xzl-system/src/main/resources/mapper/system/SysDeptMapper.xml

@@ -20,10 +20,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<result property="createTime" column="create_time" />
 		<result property="updateBy"   column="update_by"   />
 		<result property="updateTime" column="update_time" />
+		<result property="dingId" column="ding_id" />
+		<result property="dingParentId" column="ding_parent_id" />
 	</resultMap>
 	
 	<sql id="selectDeptVo">
-        select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time 
+        select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time ,
+        d.ding_id, d.ding_parent_id
         from sys_dept d
     </sql>
     
@@ -99,6 +102,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="email != null and email != ''">email,</if>
  			<if test="status != null">status,</if>
  			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			<if test="dingId != null and dingId != ''">ding_id,</if>
+ 			<if test="dingParentId != null and dingParentId != ''">ding_parent_id,</if>
  			create_time
  		)values(
  			<if test="deptId != null and deptId != 0">#{deptId},</if>
@@ -111,6 +116,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="email != null and email != ''">#{email},</if>
  			<if test="status != null">#{status},</if>
  			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			<if test="dingId != null and dingId != ''">#{dingId},</if>
+			<if test="dingParentId != null and dingParentId != ''">#{dingParentId},</if>
  			sysdate()
  		)
 	</insert>
@@ -127,6 +134,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="email != null">email = #{email},</if>
  			<if test="status != null and status != ''">status = #{status},</if>
  			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+			<if test="dingId != null and dingId != ''">ding_id = #{dingId},</if>
+			<if test="dingParentId != null and dingParentId != ''">ding_parent_id = #{dingParentId},</if>
  			update_time = sysdate()
  		</set>
  		where dept_id = #{deptId}

+ 22 - 4
xzl-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -23,6 +23,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="updateBy"     column="update_by"    />
         <result property="updateTime"   column="update_time"  />
         <result property="remark"       column="remark"       />
+        <result property="dingDeptId"   column="ding_dept_id" />
+        <result property="dingUnionId"  column="ding_union_id"/>
+        <result property="nlpName"  column="nlp_name"/>
+        <result property="nlpPwd"  column="nlp_pwd"/>
         <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
     </resultMap>
@@ -49,7 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<sql id="selectUserVo">
         select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, 
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
-        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
+        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status, u.nlp_name, u.nlp_pwd
         from sys_user u
 		    left join sys_dept d on u.dept_id = d.dept_id
 		    left join sys_user_role ur on u.user_id = ur.user_id
@@ -57,7 +61,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
     
     <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
-		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
+		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader ,
+		u.nlp_name, u.nlp_pwd
+		from sys_user u
 		left join sys_dept d on u.dept_id = d.dept_id
 		where u.del_flag = '0'
 		<if test="userId != null and userId != 0">
@@ -156,6 +162,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="status != null and status != ''">status,</if>
  			<if test="createBy != null and createBy != ''">create_by,</if>
  			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="dingDeptId != null and dingDeptId != ''">ding_dept_id,</if>
+ 			<if test="dingUnionId != null and dingUnionId != ''">ding_union_id,</if>
+ 			<if test="nlpName != null and nlpName != ''">nlp_name,</if>
+ 			<if test="nlpPwd != null and nlpPwd != ''">nlp_pwd,</if>
  			create_time
  		)values(
  			<if test="userId != null and userId != ''">#{userId},</if>
@@ -170,7 +180,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="status != null and status != ''">#{status},</if>
  			<if test="createBy != null and createBy != ''">#{createBy},</if>
  			<if test="remark != null and remark != ''">#{remark},</if>
- 			sysdate()
+			<if test="dingDeptId != null and dingDeptId != ''">#{dingDeptId},</if>
+			<if test="dingUnionId != null and dingUnionId != ''">#{dingUnionId},</if>
+		    <if test="nlpName != null and nlpName != ''">#{nlpName},</if>
+		    <if test="nlpPwd != null and nlpPwd != ''">#{nlpPwd},</if>
+		    sysdate()
  		)
 	</insert>
 	
@@ -190,7 +204,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="loginDate != null">login_date = #{loginDate},</if>
  			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
  			<if test="remark != null">remark = #{remark},</if>
- 			update_time = sysdate()
+			<if test="dingDeptId != null and dingDeptId != ''">ding_dept_id = #{dingDeptId},</if>
+			<if test="dingUnionId != null and dingUnionId != ''">ding_union_id = #{dingUnionId},</if>
+			<if test="nlpName != null and nlpName != ''">nlp_name = #{nlpName},</if>
+			<if test="nlpPwd != null and nlpPwd != ''">nlp_pwd = #{nlpPwd},</if>
+			update_time = sysdate()
  		</set>
  		where user_id = #{userId}
 	</update>

+ 8 - 0
xzl-ui/src/api/system/user.js

@@ -133,3 +133,11 @@ export function deptTreeSelect() {
     method: 'get'
   })
 }
+
+
+export function initDingTalk() {
+  return request({
+    url: '/user-portait/initDingtalk',
+    method: 'get'
+  })
+}

+ 14 - 3
xzl-ui/src/store/modules/user.js

@@ -1,5 +1,5 @@
 import { login, logout, getInfo } from '@/api/login'
-import { getToken, setToken, removeToken } from '@/utils/auth'
+import { getToken, setToken, removeToken, setNLPAuthData, getNLPAuthData,removeNLPAuthData } from '@/utils/auth'
 
 const user = {
   state: {
@@ -8,7 +8,8 @@ const user = {
     name: '',
     avatar: '',
     roles: [],
-    permissions: []
+    permissions: [],
+    NLPAuthData: getNLPAuthData()
   },
 
   mutations: {
@@ -29,7 +30,10 @@ const user = {
     },
     SET_PERMISSIONS: (state, permissions) => {
       state.permissions = permissions
-    }
+    },
+    SET_NLPAUTHDATA: (state, authData) => {
+      state.NLPAuthData = authData
+    },
   },
 
   actions: {
@@ -43,6 +47,10 @@ const user = {
         login(username, password, code, uuid).then(res => {
           setToken(res.token)
           commit('SET_TOKEN', res.token)
+          if(res.NLPAuthData) {
+            setNLPAuthData(res.NLPAuthData)
+            commit('SET_NLPAUTHDATA', res.NLPAuthData)
+          }
           resolve()
         }).catch(error => {
           reject(error)
@@ -86,9 +94,11 @@ const user = {
       return new Promise((resolve, reject) => {
         logout(state.token).then(() => {
           commit('SET_TOKEN', '')
+          commit('SET_NLPAUTHDATA', '')
           commit('SET_ROLES', [])
           commit('SET_PERMISSIONS', [])
           removeToken()
+          removeNLPAuthData()
           resolve()
         }).catch(error => {
           reject(error)
@@ -101,6 +111,7 @@ const user = {
       return new Promise(resolve => {
         commit('SET_TOKEN', '')
         removeToken()
+        removeNLPAuthData()
         resolve()
       })
     }

+ 12 - 0
xzl-ui/src/utils/auth.js

@@ -1,6 +1,7 @@
 import Cookies from 'js-cookie'
 
 const TokenKey = 'Admin-Token'
+const NLPKey = 'NLP-AUTH-DATA'
 
 export function getToken() {
   return Cookies.get(TokenKey)
@@ -13,3 +14,14 @@ export function setToken(token) {
 export function removeToken() {
   return Cookies.remove(TokenKey)
 }
+
+export function getNLPAuthData() {
+  return Cookies.get(NLPKey)
+}
+
+export function setNLPAuthData(authData) {
+  return Cookies.set(NLPKey, authData)
+}
+export function removeNLPAuthData() {
+  return Cookies.remove(NLPKey)
+}

+ 28 - 6
xzl-ui/src/views/index.vue

@@ -1,17 +1,30 @@
 <template>
   <div id="screen" >
-    <iframe frameborder="no"  src="http://10.70.192.123/webroot/decision/view/form?viewlet=大屏/营销看板.frm" width="100%" height="100%"></iframe>
+    <div class="hide_menu"></div>
+    <iframe frameborder="no"  width="100%" height="100%" :src="nlpSrc"></iframe>
   </div>
 </template>
+
 <script>
+  import {getNLPAuthData} from "@/utils/auth";
   export default {
     name: "Index",
-    methods: {
-      hideTitle() {
-        alert('ok ...')
+    data() {
+      return {
+        nlpAuthData: getNLPAuthData(),
+        nlpSrc: 'http://10.70.192.135:8000/#/'
+      }
+    },
+    created() {
+      //带上authData 跳转到 nlp 系统
+      if(this.nlpAuthData && this.nlpAuthData.length > 0) {
+        this.nlpSrc = this.nlpSrc + "?authData=" + encodeURI(this.nlpAuthData)
+      } else {
+        // 提示nlp登录失败,请修改nlp系统密码与本系统一致
+        this.$modal.msgError("智能数据搜索系统登录失败,请修改密码与本系统一致");
       }
-    }
-  };
+    },
+  }
 </script>
 
 <style>
@@ -25,4 +38,13 @@
     height:100%;
     border:hidden;
   }
+
+  .hide_menu {
+    width:300px;
+    height: 3.375rem !important;
+    position: absolute;
+    top:0;
+    right: 12px;
+    background: #f5f6f7;
+  }
 </style>

+ 32 - 0
xzl-ui/src/views/nlp/index.vue

@@ -0,0 +1,32 @@
+<template>
+  <div id="screen" >
+    <iframe frameborder="no"  width="100%" height="100%" :src="nlpSrc"></iframe>
+  </div>
+</template>
+
+<script>
+  import {getNLPAuthData} from "@/utils/auth";
+
+  export default {
+    name: "NLP",
+    data() {
+      return {
+        nlpAuthData: getNLPAuthData(),
+        nlpSrc: 'http://10.70.192.135:8000/#/'
+      }
+    },
+    created() {
+        //带上authData 跳转到 nlp 系统
+       if(this.nlpAuthData && this.nlpAuthData.length > 0) {
+           this.nlpSrc = this.nlpSrc + "?authData=" + encodeURI(this.nlpAuthData)
+       } else {
+          // 提示nlp登录失败,请修改nlp系统密码与本系统一致
+         this.$modal.msgError("智能数据搜索系统登录失败,请修改密码与本系统一致");
+       }
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 32 - 3
xzl-ui/src/views/system/user/index.vue

@@ -133,6 +133,15 @@
               v-hasPermi="['system:user:export']"
             >导出</el-button>
           </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="warning"
+              plain
+              icon="el-icon-refresh"
+              size="mini"
+              @click="handleDingtalk"
+            >同步钉钉</el-button>
+          </el-col>
           <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
         </el-row>
 
@@ -301,6 +310,19 @@
             </el-form-item>
           </el-col>
         </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="NLP用户名">
+              <el-input v-model="form.nlpName" placeholder="请输入NLP用户名" maxlength="32" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="NLP密码">
+              <el-input v-model="form.nlpPwd" placeholder="请输入NLP密码" maxlength="32" />
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -341,7 +363,7 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user";
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect, initDingTalk } from "@/api/system/user";
 import { getToken } from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
@@ -522,7 +544,9 @@ export default {
         status: "0",
         remark: undefined,
         postIds: [],
-        roleIds: []
+        roleIds: [],
+        nlpName: undefined,
+        nlpPwd: undefined,
       };
       this.resetForm("form");
     },
@@ -639,6 +663,11 @@ export default {
         ...this.queryParams
       }, `user_${new Date().getTime()}.xlsx`)
     },
+    handleDingtalk() {
+        initDingTalk().then(res=>{
+          this.$modal.msgSuccess("同步成功");
+        })
+    },
     /** 导入按钮操作 */
     handleImport() {
       this.upload.title = "用户导入";
@@ -667,4 +696,4 @@ export default {
     }
   }
 };
-</script>
+</script>