yurk 2 năm trước cách đây
mục cha
commit
5cf437fa61
16 tập tin đã thay đổi với 589 bổ sung132 xóa
  1. 99 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuthRedirectController.java
  2. 27 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java
  3. 40 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  4. 102 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/FeishuInfo.java
  5. 17 8
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java
  6. 6 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java
  7. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/FeishuInfoMapper.java
  8. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java
  9. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java
  10. 59 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java
  11. 82 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  12. 27 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/FeishuInfoMapper.xml
  13. 4 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  14. 3 118
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml
  15. 10 0
      fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue
  16. 77 4
      fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue

+ 99 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuthRedirectController.java

@@ -8,8 +8,10 @@ import com.management.platform.mapper.CompanyMapper;
 import com.management.platform.mapper.SysConfigMapper;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.mapper.WxCorpInfoMapper;
+import com.management.platform.service.FeishuInfoService;
 import com.management.platform.service.UserService;
 import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.service.impl.FeishuInfoServiceImpl;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MessageUtils;
 import com.management.platform.util.UserAgentUtils;
@@ -62,6 +64,8 @@ public class AuthRedirectController {
     CompanyMapper companyMapper;
     @Resource
     WxCorpInfoService wxCorpInfoService;
+    @Resource
+    FeishuInfoServiceImpl feishuInfoService;
 
 
     @RequestMapping("/corpWXAuth")
@@ -151,6 +155,101 @@ public class AuthRedirectController {
         return modelAndView;
     }
 
+
+    @RequestMapping("/corpFeishuAuth")
+    public ModelAndView corpFeishuAuth(String code, String appId) {
+        Map<String,Object> reqParam = new HashMap<String,Object>(16);
+        String userAgent = request.getHeader("User-Agent");
+        //获取设备类型
+        FeishuInfo feishuInfo = feishuInfoService.getOne(new QueryWrapper<FeishuInfo>().eq("app_id", appId));
+        String deviceType = UserAgentUtils.getDeviceType(userAgent);
+        boolean isMobile = "MOBILE".equals(deviceType);
+        String url = FeishuInfoServiceImpl.GET_USER_ACCESS_TOKEN;
+        HttpHeaders headers = new HttpHeaders();
+        RestTemplate restTemplate = new RestTemplate();
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+        headers.setContentType(type);
+        headers.setBearerAuth(feishuInfoService.getAppAccessToken(feishuInfo));
+        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
+        JSONObject ob = new JSONObject();
+        ob.put("grant_type", "authorization_code");
+        ob.put("code", code);
+        HttpEntity<JSONObject> Entity = new HttpEntity<>(ob, headers);
+        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, Entity, String.class);
+        String redirecUrl = null;
+        String openUserId=null;
+        String fsUserId=null;
+        String corpId=null;
+        if (responseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = responseEntity.getBody();
+            System.err.println(resp);
+            JSONObject obj = JSONObject.parseObject(resp);
+            if (obj.getIntValue("code") == 0) {
+                System.out.println(obj.toString());
+                fsUserId = obj.getString("UserId");
+                openUserId = obj.getString("open_id");
+                corpId = obj.getString("tenant_key");
+            }
+        }
+        List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("feishu_userid", openUserId));
+        Integer companyId = 0;
+        if (userList.size() > 0) {
+            //该用户已存在
+            User curUser = userList.get(0);
+            System.out.println("找到用户corpwxUserid=="+curUser.getFeishuUserid());
+            companyId = curUser.getCompanyId();
+            if (curUser.getIsActive() == 1) {
+                reqParam.put("userId", curUser.getId());
+            } else {
+                //提示账号已停用
+                //reqParam.put("errorMsg", "您的账号已停用,无法登录");
+                reqParam.put("errorMsg", MessageUtils.message("user.inactive"));
+            }
+        } else {
+            //使用UserId比对,之前有的老用户存的是UserId
+            if (feishuInfo == null) {
+                reqParam.put("errorMsg", MessageUtils.message("user.accountNoExist"));
+            } else {
+                User curUser = userMapper.selectOne(new QueryWrapper<User>().eq("company_id", feishuInfo.getCompanyId()).eq("feishu_userid", openUserId));
+                if (curUser != null) {
+                    if (curUser.getIsActive() == 1) {
+                        companyId = curUser.getCompanyId();
+                        reqParam.put("userId", curUser.getId());
+                    } else {
+                        //提示账号已停用
+                        //reqParam.put("errorMsg", "您的账号已停用,无法登录");
+                        reqParam.put("errorMsg", MessageUtils.message("user.inactive"));
+                    }
+                } else {
+                    System.err.println("==生成飞书User失败==");
+                    reqParam.put("errorMsg", "尚未绑定飞书,请使用账号密码登录。");
+                }
+
+            }
+        }
+        reqParam.put("hasTriedAutoLogin", 1);
+        String router = "index";
+        if (companyId > 0) {
+            HashMap compExpireInfo = getCompExpireInfo(companyId);
+            if (compExpireInfo != null) {
+                //过期了
+                router = "expire";
+                reqParam.put("expDate", compExpireInfo.get("expDate"));
+                reqParam.put("version", compExpireInfo.get("version"));
+            }
+        }
+        if (isMobile) {
+            redirecUrl = "https://mobworktime.ttkuaiban.com/#/" + router;
+        } else {
+            redirecUrl = "https://worktime.ttkuaiban.com/#/" + router;
+        }
+        ModelAndView modelAndView = new ModelAndView(
+                new RedirectView(redirecUrl), reqParam);
+
+        return modelAndView;
+    }
+
+
     @RequestMapping("/corpWXScanningAuth")
     public ModelAndView scanningAuth(String auth_code, String state)throws Exception {
         Map<String,Object> reqParam = new HashMap<String,Object>(16);

+ 27 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java

@@ -0,0 +1,27 @@
+package com.management.platform.controller;
+
+
+import com.management.platform.service.FeishuInfoService;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-02-27
+ */
+@RestController
+@RequestMapping("/feishu-info")
+public class FeishuInfoController {
+
+    @Resource
+    private FeishuInfoService feishuInfoService;
+
+}
+

+ 40 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java

@@ -23,6 +23,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -924,5 +925,44 @@ public class TaskController {
         httpRespMsg.data=nameList;
         return httpRespMsg;
     }
+
+    @RequestMapping("/operateMeeting")
+    public HttpRespMsg operateMeeting(HttpServletRequest request,Integer taskId,String startTime,String endTime) throws Exception {
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.list(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId())).get(0);
+        Task task = taskMapper.selectById(taskId);
+        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDateTime start = LocalDateTime.parse(startTime, df);
+        LocalDateTime end = LocalDateTime.parse(endTime, df);
+        Duration between = Duration.between(start, end);
+        List<TaskExecutor> taskExecutorList = taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().eq("task_id", task.getId()));
+        if(taskExecutorList.size()>0){
+            List<String> list = taskExecutorList.stream().map(TaskExecutor::getExecutorId).distinct().collect(Collectors.toList());
+            String userIds = userMapper.selectList(new QueryWrapper<User>().in("id", list)).stream().map(User::getCorpwxUserid).distinct().collect(Collectors.joining("|"));
+            String meetingResp;
+            if(!StringUtils.isEmpty(task.getMeetingId())){
+                meetingResp = wxCorpInfoService.operateMeeting(userIds, "工时管家任务", task.getName(), startTime, between.getSeconds(),wxCorpInfo, "update", task.getMeetingId());
+            }else {
+                meetingResp =  wxCorpInfoService.operateMeeting(userIds,"工时管家任务",task.getName(),startTime,between.getSeconds(),wxCorpInfo,"create",null);
+                if(!meetingResp.contains("invalid")){
+                    task.setMeetingId(meetingResp);
+                    taskMapper.updateById(task);
+                }
+            }
+            httpRespMsg.data=meetingResp;
+        }else httpRespMsg.setError("该任务无执行人");
+        return httpRespMsg;
+    }
+    @RequestMapping("/getMeeting")
+    public HttpRespMsg getMeeting(Integer taskId) throws Exception {
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.list(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId())).get(0);
+        Task task = taskMapper.selectById(taskId);
+        String meetingInfo = wxCorpInfoService.operateMeeting(null, null, null, null, 300, wxCorpInfo, "get_info", task.getMeetingId());
+        httpRespMsg.data=meetingInfo;
+        return httpRespMsg;
+    }
 }
 

+ 102 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/FeishuInfo.java

@@ -0,0 +1,102 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-02-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class FeishuInfo extends Model<FeishuInfo> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId("corpid")
+    private String corpid;
+
+    @TableField("corp_name")
+    private String corpName;
+
+    @TableField("location")
+    private String location;
+
+    /**
+     * 企业token
+     */
+    @TableField("access_token")
+    private String accessToken;
+
+    /**
+     * token有效期
+     */
+    @TableField("expire_time")
+    private LocalDateTime expireTime;
+
+    /**
+     * 授权人姓名
+     */
+    @TableField("auth_username")
+    private String authUsername;
+
+    /**
+     * 系统内部的公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 授权企业内应用的id
+     */
+    @TableField("agentid")
+    private Integer agentid;
+
+    /**
+     * 通讯录ApiSecret
+     */
+    @TableField("contact_secret")
+    private String contactSecret;
+
+    /**
+     * 企业通讯录服务器ip和端口
+     */
+    @TableField("contact_server")
+    private String contactServer;
+
+    /**
+     * 开通应用时的授权方式:0-管理员,1-成员授权
+     */
+    @TableField("auth_mode")
+    private Integer authMode;
+
+    /**
+     * 飞书企业自建应用APPID
+     */
+    @TableField("app_id")
+    private String appId;
+
+    /**
+     * 飞书企业自建应用APPSecret
+     */
+    @TableField("app_secret")
+    private String appSecret;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.corpid;
+    }
+
+}

+ 17 - 8
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java

@@ -1,27 +1,27 @@
 package com.management.platform.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import java.util.List;
+
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.List;
-
 /**
  * <p>
  * 
  * </p>
  *
  * @author Seyason
- * @since 2022-03-18
+ * @since 2023-02-27
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -72,6 +72,9 @@ public class Task extends Model<Task> {
     @TableField("executor_name")
     private String executorName;
 
+    /**
+     * 执行人头像颜色,多个
+     */
     @TableField("executor_color")
     private String executorColor;
 
@@ -205,6 +208,12 @@ public class Task extends Model<Task> {
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDate startDate;
 
+    /**
+     * 会议Id
+     */
+    @TableField("meeting_id")
+    private String meetingId;
+
     @TableField(exist = false)
     private List<TaskExecutor> executorList;
 

+ 6 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java

@@ -21,7 +21,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2023-01-16
+ * @since 2023-02-28
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -270,6 +270,11 @@ public class User extends Model<User> {
     @TableField("is_mob_first_login")
     private Integer isMobFirstLogin;
 
+    /**
+     * 飞书人员id
+     */
+    @TableField("feishu_userid")
+    private String feishuUserid;
     /**
      * 是否存在日报
      * 0-否 1-是

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/FeishuInfoMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.FeishuInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-02-27
+ */
+public interface FeishuInfoMapper extends BaseMapper<FeishuInfo> {
+
+}

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java

@@ -0,0 +1,18 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.FeishuInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-02-27
+ */
+public interface FeishuInfoService extends IService<FeishuInfo> {
+
+
+
+}

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java

@@ -65,4 +65,6 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
     HttpRespMsg fixPunchRecord(Integer companyId, LocalDateTime start, LocalDateTime end, boolean b);
 
     HashMap<String, List> getOpenId(String corpId, String keyword, String cursor,Integer queryType,Integer limit) throws Exception;
+
+    String operateMeeting(String userIds, String title, String description, String startTime, long duration, WxCorpInfo wxCorpInfo, String meetingType, String meetingId) throws Exception;
 }

+ 59 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java

@@ -0,0 +1,59 @@
+package com.management.platform.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.management.platform.entity.FeishuInfo;
+import com.management.platform.mapper.FeishuInfoMapper;
+import com.management.platform.service.FeishuInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-02-27
+ */
+@Service
+public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuInfo> implements FeishuInfoService {
+        /*自建应用获取 tenant_access_token*/
+        public static final String  GET_TENANT_ACCESS_TOKEN= "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
+        /*自建应用获取 app_access_token*/
+        public static final String  GET_APP_ACCESS_TOKEN= "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal";
+        /*自建应用获取 user_access_token*/
+        public static final String  GET_USER_ACCESS_TOKEN= "https://open.feishu.cn/open-apis/authen/v1/access_token";
+
+        public String getAppAccessToken(FeishuInfo feishuInfo){
+                String result="";
+                String url = GET_APP_ACCESS_TOKEN;
+                HttpHeaders headers = new HttpHeaders();
+                RestTemplate restTemplate = new RestTemplate();
+                MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+                headers.setContentType(type);
+                headers.add("Accept", MediaType.APPLICATION_JSON.toString());
+                JSONObject requestMap = new JSONObject();
+                requestMap.put("app_id",feishuInfo.getAppId());
+                requestMap.put("app_secret",feishuInfo.getAppSecret());
+                HttpEntity<JSONObject> entity = new HttpEntity<>(requestMap, headers);
+                ResponseEntity<String> ResponseEntity = restTemplate.postForEntity(url, entity, String.class);
+                if (ResponseEntity.getStatusCode() == HttpStatus.OK) {
+                        String resp = ResponseEntity.getBody();
+                        JSONObject respJson = JSONObject.parseObject(resp);
+                        if (respJson.getInteger("code")==0){
+                                result+=respJson.getString("app_access_token");
+                        }
+                }
+                return result;
+        }
+
+}

+ 82 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.management.platform.controller.WeiXinCorpController;
 import com.management.platform.entity.*;
@@ -136,6 +137,8 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
     CompanyMapper companyMapper;
     @Resource
     ContactSyncLogMapper contactSyncLogMapper;
+    @Resource
+    TaskMapper taskMapper;
 
 
     //获取服务商provider_access_token
@@ -1916,4 +1919,83 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         }
         return result;
     }
+    @Override
+    public String operateMeeting(String userIds,String title,String description,String startTime,long duration,WxCorpInfo wxCorpInfo,String meetingType,String meetingId) throws Exception {
+        String result="";
+        String url = "https://qyapi.weixin.qq.com/cgi-bin/meeting/meetingType?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN",getCorpAccessToken(wxCorpInfo)).replace("meetingType",meetingType);
+        HttpHeaders headers = new HttpHeaders();
+        RestTemplate restTemplate = new RestTemplate();
+        headers.setContentType( MediaType.APPLICATION_JSON);
+        JSONObject requestMap = new JSONObject();
+        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        long timestamp=LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();;
+        if(startTime!=null){
+            LocalDateTime dateTime = LocalDateTime.parse(startTime, df);
+            timestamp = dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()/1000;
+        }
+        List<String> userList=new ArrayList<>();
+        JSONObject attendees=new JSONObject();
+        if(userIds!=null){
+            String[] split = userIds.split("\\|");
+            userList = Arrays.asList(split);
+            attendees.put("userid",userList);
+        }
+        switch (meetingType){
+            case "create":
+                requestMap.put("admin_userid",userList.get(0));
+                requestMap.put("title",title);
+                requestMap.put("meeting_start",timestamp);
+                requestMap.put("meeting_duration",duration);
+                requestMap.put("description",description);
+                requestMap.put("agentid",wxCorpInfo.getAgentid());
+                requestMap.put("attendees",attendees);
+                break;
+            case "update":
+                String get_info = operateMeeting(null, null, null, null, 300, wxCorpInfo, "get_info", meetingId);
+                if(StringUtils.isEmpty(get_info)){
+                    result="当前任务相关会议不存在,请重新发起会议";
+                    Task task = taskMapper.selectOne(new QueryWrapper<Task>().eq("meeting_id", meetingId));
+                    task.setMeetingId("");
+                    taskMapper.updateById(task);
+                    return result;
+                }
+                requestMap.put("meetingid",meetingId);
+                requestMap.put("admin_userid",userList.get(0));
+                requestMap.put("title",title);
+                requestMap.put("meeting_start",timestamp);
+                requestMap.put("meeting_duration",duration);
+                requestMap.put("description",description);
+                requestMap.put("agentid",wxCorpInfo.getAgentid());
+                requestMap.put("attendees",attendees);
+                break;
+            case "cancel":
+            case "get_info":
+                requestMap.put("meetingid",meetingId);
+                break;
+        }
+        System.out.println(requestMap);
+        HttpEntity<JSONObject> entity = new HttpEntity<>(requestMap, headers);
+        ResponseEntity<String> ResponseEntity = restTemplate.postForEntity(url, entity, String.class);
+        if (ResponseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = ResponseEntity.getBody();
+            JSONObject respJson = JSONObject.parseObject(resp);
+            if (respJson.getInteger("errcode")==0){
+                switch (meetingType){
+                    case "create":
+                        result=respJson.getString("meetingid");
+                        break;
+                    case "update":
+                        result=respJson.getString("errmsg");
+                        break;
+                    case "cancel":
+                        result=respJson.getString("errmsg");
+                        break;
+                    case "get_info":
+                        result=respJson.getString("title");
+                        break;
+                }
+            }else result=respJson.getString("errmsg");
+        }
+        return result;
+    }
 }

+ 27 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/FeishuInfoMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.FeishuInfoMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.FeishuInfo">
+        <id column="corpid" property="corpid" />
+        <result column="corp_name" property="corpName" />
+        <result column="location" property="location" />
+        <result column="access_token" property="accessToken" />
+        <result column="expire_time" property="expireTime" />
+        <result column="auth_username" property="authUsername" />
+        <result column="company_id" property="companyId" />
+        <result column="agentid" property="agentid" />
+        <result column="contact_secret" property="contactSecret" />
+        <result column="contact_server" property="contactServer" />
+        <result column="auth_mode" property="authMode" />
+        <result column="app_id" property="appId" />
+        <result column="app_secret" property="appSecret" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        corpid, corp_name, location, access_token, expire_time, auth_username, company_id, agentid, contact_secret, contact_server, auth_mode, app_id, app_secret
+    </sql>
+
+</mapper>

+ 4 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml

@@ -29,6 +29,7 @@
         <result column="parent_tname" property="parentTname" />
         <result column="finish_date" property="finishDate" />
         <result column="start_date" property="startDate" />
+        <result column="meeting_id" property="meetingId" />
     </resultMap>
 
     <resultMap id="timeResultMap" type="com.management.platform.entity.TimeTask" >
@@ -57,6 +58,7 @@
         <result column="parent_tname" property="parentTname" />
         <result column="finish_date" property="finishDate" />
         <result column="start_date" property="startDate" />
+        <result column="meeting_id" property="meetingId" />
         <result column="work_hours" property="workHours" />
     </resultMap>
     <resultMap id="RichResultMap" type="com.management.platform.entity.Task">
@@ -86,13 +88,14 @@
         <result column="finish_date" property="finishDate" />
         <result column="project_name" property="projectName" />
         <result column="start_date" property="startDate" />
+        <result column="meeting_id" property="meetingId" />
         <result column="stages_name" property="stagesName" />
         <result column="department_name" property="departmentName" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, task_desc, creater_id, creater_name, creator_color, executor_id, executor_name, executor_color, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours, task_type, parent_tname, finish_date, start_date
+        id, name, task_desc, creater_id, creater_name, creator_color, executor_id, executor_name, executor_color, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours, task_type, parent_tname, finish_date, start_date, meeting_id
     </sql>
     <select id="simpleList" resultMap="BaseResultMap">
         select id, name, creater_id, creater_name, creator_color, executor_id, executor_name, executor_color, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours, task_type, parent_tname, finish_date, start_date

+ 3 - 118
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml

@@ -43,127 +43,12 @@
         <result column="corpwx_real_userid" property="corpwxRealUserid" />
         <result column="is_first_login" property="isFirstLogin" />
         <result column="is_mob_first_login" property="isMobFirstLogin" />
+        <result column="feishu_userid" property="feishuUserid" />
     </resultMap>
-    <resultMap id="BaseResultMap2" type="com.management.platform.entity.User">
-        <id column="id" property="id" />
-        <result column="name" property="name" />
-        <result column="department_id" property="departmentId" />
-        <result column="department_name" property="departmentName" />
-    </resultMap>
+
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost, salary_type, manage_dept_id, color, is_active, wx_openid, role_id, role_name, cost_apply_date, dingding_userid, dingding_unionid, corpwx_userid, induction_date, inactive_date, position, report_status, superior_id, plate1, plate2, plate3, plate4, plate5, is_ops, job_number, corpwx_deptid, corpwx_real_userid, is_first_login, is_mob_first_login
+        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost, salary_type, manage_dept_id, color, is_active, wx_openid, role_id, role_name, cost_apply_date, dingding_userid, dingding_unionid, corpwx_userid, induction_date, inactive_date, position, report_status, superior_id, plate1, plate2, plate3, plate4, plate5, is_ops, job_number, corpwx_deptid, corpwx_real_userid, is_first_login, is_mob_first_login, feishu_userid
     </sql>
-    <!--单独分页获取人员-->
-    <select id="getUserByDepartment" resultType="java.util.Map">
-        SELECT a.id, a.role_id as roleId, a.role_name as roleName, a.name, a.phone, a.portrait_url AS portraitUrl, a.role, a.company_id AS companyId, a.cost,
-        a.department_id AS departmentId, b.department_name AS departmentName, a.department_cascade AS departmentCascade,
-        a.month_cost as monthCost, a.salary_type as salaryType, a.is_active as isActive,date_format(a.`inactive_date`, '%Y-%m-%d') AS inactiveDate, a.cost_apply_date as costApplyDate,a.plate1,a.plate2,a.plate3,a.plate4,a.plate5,
-        a.job_number as jobNumber, DATE_FORMAT(a.create_time, '%Y-%m-%d %H:%m')  as createTime
-        FROM user AS a
-        LEFT JOIN department AS b ON a.department_id = b.department_id
-        WHERE a.company_id = #{companyId}
-        <if test="departmentId != null and companyId != ''">
-            AND a.department_id = #{departmentId}
-        </if>
-        <if test="keyword != null and keyword != ''">
-            AND
-            <choose>
-                <when test="matchingType==0">
-                    a.name like '%${keyword}%'
-                </when>
-                <when test="matchingType==1">
-                    a.phone like '%${keyword}%'
-                </when>
-                <when test="matchingType==2">
-                    a.job_number like '%${keyword}%'
-                </when>
-            </choose>
-        </if>
-        <if test="status != null">
-            AND a.is_active = #{status}
-        </if>
-        <if test="roleId != null">
-            AND a.role_id = #{roleId}
-        </if>
-    </select>
-
-    <!--范围分页获取人员-->
-    <select id="getUserByDepartmentList" resultType="java.util.Map">
-        SELECT a.id,  a.role_id as roleId, a.role_name as roleName,  a.name, a.phone, a.portrait_url AS portraitUrl, a.role, a.company_id AS companyId, a.cost,
-        a.department_id AS departmentId, b.department_name AS departmentName, a.department_cascade AS departmentCascade,
-        a.month_cost as monthCost, a.salary_type as salaryType, a.is_active as isActive,date_format(a.`inactive_date`, '%Y-%m-%d') AS inactiveDate, a.cost_apply_date as costApplyDate,a.plate1,a.plate2,a.plate3,a.plate4,a.plate5,
-        a.job_number as jobNumber, DATE_FORMAT(a.create_time, '%Y-%m-%d %H:%m')  as createTime
-        FROM user AS a
-        LEFT JOIN department AS b ON a.department_id = b.department_id
-        WHERE a.company_id = #{companyId} AND a.department_id IN
-        <foreach collection="departmentIds" item="departmentId" index="index" open="(" close=")" separator=",">
-            #{departmentId}
-        </foreach>
-        <if test="keyword != null and keyword != ''">
-            AND a.name like '%${keyword}%'
-        </if>
-        <if test="status != null">
-            AND a.is_active = #{status}
-        </if>
-        <if test="roleId != null">
-            AND a.role_id = #{roleId}
-        </if>
-    </select>
-
-
-    <select id="getPushUserList" resultType="java.util.Map">
-        SELECT a.id, a.wx_openid as wxOpenid, a.corpwx_userid as corpwxUserid, a.name, a.phone, b.department_name AS departmentName
-        FROM user AS a LEFT JOIN  department b ON a.department_id = b.department_id
-        WHERE a.company_id = #{companyId}
-        AND (a.wx_openid IS NOT NULL or corpwx_userid is not null)
-        AND a.is_active = 1
-        AND a.report_status =0
-        <choose>
-            <when test="alertType!=null and alertType==1">
-                AND NOT EXISTS(SELECT 1 FROM report WHERE report.`creator_id` = a.id AND report.`create_date` = DATE_FORMAT(date_sub(NOW(),interval 1 day), '%Y-%m-%d'))
-            </when>
-            <otherwise>
-                AND NOT EXISTS(SELECT 1 FROM report WHERE report.`creator_id` = a.id AND report.`create_date` = DATE_FORMAT(NOW(), '%Y-%m-%d'))
-            </otherwise>
-        </choose>
-        <if test="date != null">
-            and not exists (select 1 from leave_sheet where owner_id = a.id and start_date &lt;= #{date} and end_date &gt;= #{date} and leave_sheet.status = 0)
-        </if>
-
-    </select>
-
-
-    <select id="getPushDingdingUserList" resultType="java.util.Map">
-        SELECT a.company_id as companyId, a.dingding_userid as dingdingUserid
-        FROM user AS a left join time_type on time_type.company_id = a.company_id
-        left join company on a.company_id = company.id
-        WHERE a.dingding_userid is not null and time_type.alert_time = #{alertTime}
-        AND a.is_active = 1
-        AND a.report_status=0
-        AND company.expiration_date >= NOW()
-        AND NOT EXISTS(SELECT 1 FROM report WHERE report.`creator_id` = a.id AND ((report.`create_date` = DATE_FORMAT(date_sub(NOW(),interval 1 day), '%Y-%m-%d') and time_type.alert_type=1)or(report.`create_date` = DATE_FORMAT(NOW(), '%Y-%m-%d') and time_type.alert_type=0)))
-        <if test="date != null">
-            and not exists (select 1 from leave_sheet where owner_id = a.id and start_date &lt;= #{date} and end_date &gt;= #{date} and leave_sheet.status = 0)
-        </if>
-        order by a.company_id
-    </select>
-    <!--获取项目的参与人的推送id -->
-    <select id="getProjectPushUserList" resultType="java.util.Map">
-        SELECT a.id, a.wx_openid as wxOpenid, a.corpwx_userid as corpwxUserid
-        FROM user AS a
-        WHERE a.wx_openid IS NOT NULL
-        AND a.is_active = 1
-        AND a.id in (select user_id from participation where project_id = #{projectId})
-    </select>
-    <select id="getSimpleNameList" resultType="java.util.HashMap">
-        select id, name, job_number as jobNumber from user
-        ${ew.customSqlSegment}
-    </select>
-
-    <select id="getUserWithDept" resultMap="BaseResultMap2">
-        select user.id, name, department.department_name from user left join department on department.department_id = user.department_id
-        ${ew.customSqlSegment}
-    </select>
 
 </mapper>

+ 10 - 0
fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue

@@ -367,9 +367,11 @@
     </div>
     <div slot="footer" class="dialog-footer foooot">
         <el-button v-if="(user.id == addForm.createrId || currentProject.inchargerId == user.id || currentProject.creatorId == user.id || permissions.projectManagement) && canAddTask" @click.native="deleteTask()" style="float:left;">{{ $t('btn.delete') }}</el-button>
+        <el-button type="primary" v-if="user.userNameNeedTranslate == 1 && !meetingId" @click="meetingCli()">发起会议</el-button>
         <el-button @click.native="closeBounceds()">{{ $t('btn.cancel') }}</el-button>
         <el-button type="primary" @click="submitInsert" :loading="addLoading">{{ $t('btn.submit') }}</el-button>
     </div>
+    
     <!-- <div slot="title" v-if="addForm.parentTid != null || isRelationItem" >
         <el-page-header  @back="backToParentTask" :title="timelabel ? $t('returnmilestone') : $t('parenttask')" :content="timelabel ? relationPar.name : addForm.parentTname"></el-page-header>
     </div> -->
@@ -616,6 +618,7 @@ export default {
   },
   data() {
     return {
+        meeting: false,
         numnnumnum: 2,
         componentFlg: false,
         mileageCup: false,
@@ -814,6 +817,7 @@ export default {
         taskListTotal: 0,
         dynamicTab: true,
         dailyList: [],
+        meetingId: ''
     };
   },
   computed: {},
@@ -828,6 +832,10 @@ export default {
     this.timess()
   },
   methods: {
+    // 触发外层的会议
+    meetingCli() {
+        this.$parent.$parent.parentMeetingCli(this.integrationTask.id)
+    },
     // 触发事件
     triggerEvent(obj) {
         console.log(obj, '触发事件')
@@ -972,6 +980,8 @@ export default {
         this.http.post('/task/getTask',{id: id},
         res => {
             if (res.code == "ok") {
+                this.meetingId = res.data.meetingId
+                console.log(this.meetingId, '看看打印纸')
                 if(this.user.userNameNeedTranslate == 1) {
                     for(var i in res.data.subTaskList) {
                         if(res.data.subTaskList[i].executorName) {

+ 77 - 4
fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue

@@ -663,6 +663,38 @@
             </div>
         </el-dialog>
 
+        <!-- 发起会议 -->
+            <el-dialog title="发起会议" :visible.sync="meeting" width="500px" :before-close="handleClose" style="z-index: 2020 !important ">
+                <div class="block">
+                    <div>
+                        <span class="demonstration">会议开始时间</span>
+                        <el-date-picker
+                        v-model="meetingStartValue"
+                        type="datetime"
+                        placeholder="选择日期时间"
+                        value-format="yyyy-MM-dd HH:mm:ss"
+                        clearable
+                        default-time="10:00:00">
+                        </el-date-picker>
+                    </div>
+                    <div style="margin-top: 20px">
+                        <span class="demonstration">会议结束时间</span>
+                        <el-date-picker
+                        v-model="meetingEndValue"
+                        type="datetime"
+                        placeholder="选择日期时间"
+                        value-format="yyyy-MM-dd HH:mm:ss"
+                        clearable.
+                        default-time="11:00:00">
+                        </el-date-picker>
+                    </div>
+                </div>
+                <span slot="footer" class="dialog-footer">
+                    <el-button @click="meeting = false">取 消</el-button>
+                    <el-button type="primary" @click="confirmMeeting()">确 定</el-button>
+                </span>
+            </el-dialog>
+
     </section>
 </template>
 <style scoped>
@@ -862,6 +894,7 @@ import { error } from 'dingtalk-jsapi';
         },
         data() {
             return {
+                meeting: false,
                 causeRejectionDialog: false,
                 causeRejectionForm: {
                     cause: '',
@@ -993,10 +1026,48 @@ import { error } from 'dingtalk-jsapi';
 
                 askComponentFlg: false,
                 integrationTask: {},
-                integrationTaskNingwai: {}
+                integrationTaskNingwai: {},
+
+                // 会议时间
+                meetingStartValue: '',
+                meetingEndValue: '',
+                toMeetTaskId:'',
             };
         },
         methods: {
+            parentMeetingCli(id) {
+                this.meeting = true
+                if(id) {
+                 this.toMeetTaskId = id
+                }
+                console.log(id)
+            },
+            confirmMeeting() {
+                var date = new Date();
+                let startTime = this.meetingStartValue
+                let endTime = this.meetingEndValue
+                this.http.post('/task//operateMeeting',{taskId:this.toMeetTaskId,startTime:startTime,endTime:endTime},
+                res => {
+                    if (res.code == "ok") {
+                        this.meeting=false,
+                        this.$message({
+                        message: "成功发起会议",
+                        type: "success"
+                        });
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             closeBounced(obj) {
                 if(!obj.backToParentTaskSub) {
                     this.addFormVisible = false
@@ -1521,7 +1592,7 @@ import { error } from 'dingtalk-jsapi';
             },
             // 点击任务事件
             editTask(task) {
-                // console.log(task)
+                console.log(task, 12345, this.addForm)
                 this.addFormVisible = true;
                 // this.addLoading = false;
                 this.title = this.$t('editingtasks');
@@ -1536,7 +1607,8 @@ import { error } from 'dingtalk-jsapi';
                     curProjectId: this.curProjectId,
                     create: false,
                     integrationTaskNingwai: this.integrationTaskNingwai,
-                    taskVue: true
+                    taskVue: true,
+                    meetingId: this.addForm.meetingId
                 }
                 this.taskComponentFlg = true
 
@@ -1842,7 +1914,8 @@ import { error } from 'dingtalk-jsapi';
                     executorListFront: [{executorId:null, planHours:8}],
                     stage: this.addForm,
                     integrationTaskNingwai: this.integrationTaskNingwai,
-                    taskVue: true,               
+                    taskVue: true,         
+                    meetingId: this.addForm.meetingId
                 }
                 this.integrationTask = obj