Browse Source

工时导入功能

seyason 3 years ago
parent
commit
ff4a35132c

+ 5 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/CompanyDingdingController.java

@@ -1,6 +1,7 @@
 package com.management.platform.controller;
 
 
+import com.management.platform.entity.CompanyDingding;
 import com.management.platform.mapper.CompanyDingdingMapper;
 import com.management.platform.service.CompanyDingdingService;
 import com.management.platform.util.HttpRespMsg;
@@ -25,11 +26,12 @@ public class CompanyDingdingController {
     private CompanyDingdingService companyDingdingService;
     @Resource
     private CompanyDingdingMapper companyDingdingMapper;
-    
 
-    @RequestMapping("/pushAlertMsg")
-    public HttpRespMsg pushAlertMsg(String userDingId) {
 
+    @RequestMapping("/pushAlertMsg")
+    public HttpRespMsg pushAlertMsg(String corpid, String userDingId) {
+        CompanyDingding companyDingding = companyDingdingMapper.selectById(corpid);
+        companyDingdingService.sendDDMsg(companyDingding, userDingId, "请填写日报哦");
         return new HttpRespMsg();
     }
 }

+ 19 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DingDingController.java

@@ -122,11 +122,22 @@ public class DingDingController {
                                     JSONObject authCorpInfo = biz_data.getJSONObject("auth_corp_info");
                                     String corp_name = authCorpInfo.getString("corp_name");
                                     boolean isAuthenticated = authCorpInfo.getBooleanValue("is_authenticated");
-
+                                    Long agentId = null;
                                     if ("org_suite_auth".equals(syncAction)) {
                                         System.out.println("==Push 推送事件 开通授权应用===" + corp_name);
                                         //此处在授权开通时强制赋值
                                         isAuthenticated = true;
+                                        JSONObject authInfo = biz_data.getJSONObject("auth_info");
+
+                                        if (authInfo != null) {
+                                            JSONArray agents = authInfo.getJSONArray("agent");
+                                            for (int j=0;j<agents.size(); j++) {
+                                                JSONObject item = agents.getJSONObject(j);
+                                                if (item.getString("agent_name").equals("工时管家")) {
+                                                    agentId = item.getLong("agentid");
+                                                }
+                                            }
+                                        }
                                     } else {
                                         System.out.println("==Push 推送事件 授权变更==="+ corp_name+"=="+(isAuthenticated?"启用":"停用"));
                                     }
@@ -134,7 +145,7 @@ public class DingDingController {
                                         String corpid = authCorpInfo.getString("corpid");
                                         String authUserId = biz_data.getJSONObject("auth_user_info").getString("userId");
                                         try {
-                                            dingDingService.corpAuth(corpid, corp_name, authUserId);
+                                            dingDingService.corpAuth(corpid, corp_name, authUserId, agentId);
                                         } catch (ApiException e) {
                                             e.printStackTrace();
                                         }
@@ -210,4 +221,10 @@ public class DingDingController {
         return dingDingService.syncCorpInfo(corpid);
     }
 
+
+    @RequestMapping("/syncCorpAgent")
+    public HttpRespMsg syncCorpAgent(String corpid) {
+        return dingDingService.syncCorpAgent(corpid);
+
+    }
 }

+ 8 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
@@ -660,5 +661,12 @@ public class ReportController {
         msg.data = WorkDayCalculateUtils.getWorkDaysCountInRange(startDate, endDate);
         return msg;
     }
+
+
+    @RequestMapping("/importData")
+    public HttpRespMsg importData(Integer companyId,
+                                  MultipartFile file, HttpServletRequest request) {
+        return reportService.importData(companyId, file, request);
+    }
 }
 

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/DingDingService.java

@@ -4,7 +4,7 @@ import com.management.platform.util.HttpRespMsg;
 import com.taobao.api.ApiException;
 
 public interface DingDingService {
-    public void corpAuth(String corpid, String corpName, String authUserId) throws ApiException;
+    public void corpAuth(String corpid, String corpName, String authUserId, Long agentId) throws ApiException;
 
     public String syncCorpMembs(String corpid) throws ApiException;
 
@@ -15,4 +15,6 @@ public interface DingDingService {
     public HttpRespMsg testAsync();
 
     HttpRespMsg syncCorpInfo(String corpid);
+
+    HttpRespMsg syncCorpAgent(String corpid);
 }

+ 3 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java

@@ -5,6 +5,7 @@ import com.management.platform.entity.Report;
 import com.management.platform.entity.User;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
@@ -57,4 +58,6 @@ public interface ReportService extends IService<Report> {
     HttpRespMsg getUserDailyWorkTime(HttpServletRequest request, String month);
 
     HttpRespMsg exportUserDailyWorkTime(HttpServletRequest request, String month);
+
+    HttpRespMsg importData(Integer companyId, MultipartFile file, HttpServletRequest request);
 }

+ 60 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java

@@ -30,6 +30,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.ArrayList;
@@ -69,7 +70,7 @@ public class DingDingServiceImpl implements DingDingService {
 
     @Override
     @Async
-    public void corpAuth(String corpid, String corpName, String authUserId) throws ApiException {
+    public void corpAuth(String corpid, String corpName, String authUserId, Long agentId) throws ApiException {
         System.out.println("@@@@@@@@@@@@@@@@@进行企业授权@@@@@@@@@@@@@@@@@"+corpid);
         //检查是否已经存在
         CompanyDingding oldD = companyDingdingMapper.selectById(corpid);
@@ -117,6 +118,7 @@ public class DingDingServiceImpl implements DingDingService {
         dingding.setCompanyId(company.getId());
         dingding.setCorpid(corpid);
         dingding.setCorpName(corpName);
+        dingding.setAgentId(agentId);
         dingding.setAuthUserId(authUserId);
 
         if (oldD == null) {
@@ -260,6 +262,7 @@ public class DingDingServiceImpl implements DingDingService {
 
     //获取授权企业的accessToken
     private OapiServiceGetCorpTokenResponse getAuthCorpAccessToken(String corpid, String suiteTicket) throws ApiException {
+        CompanyDingding dingding = companyDingdingMapper.selectById(corpid);
         DefaultDingTalkClient client= new DefaultDingTalkClient("https://oapi.dingtalk.com/service/get_corp_token");
         OapiServiceGetCorpTokenRequest req= new OapiServiceGetCorpTokenRequest();
         req.setAuthCorpid(corpid);
@@ -408,15 +411,69 @@ public class DingDingServiceImpl implements DingDingService {
                 System.out.println("获取授权企业信息,名称=="+rsp.getAuthCorpInfo().getCorpName());
 //
                 OapiServiceGetAuthInfoResponse.AuthCorpInfo authCorpInfo = rsp.getAuthCorpInfo();
-                corpAuth(authCorpInfo.getCorpid(), authCorpInfo.getCorpName(), rsp.getAuthUserInfo().getUserId());
+                List<OapiServiceGetAuthInfoResponse.Agent> agent = rsp.getAuthInfo().getAgent();
+                Long agentid = agent.stream().filter(a -> a.getAgentName().equals("工时管家")).findFirst().get().getAgentid();
+                corpAuth(authCorpInfo.getCorpid(), authCorpInfo.getCorpName(), rsp.getAuthUserInfo().getUserId(), agentid);
             }
+        } catch (ApiException e) {
+            e.printStackTrace();
+        }
 
+        return null;
+    }
+
+    @Override
+    public HttpRespMsg syncCorpAgent(String corpid) {
+        //第一次,查询对方企业的accessToken
+        SysConfig config = sysConfigMapper.selectOne(new QueryWrapper<SysConfig>().eq("param_key", "dingding_suite_ticket"));
+        OapiServiceGetCorpTokenResponse result = null;
+        try {
+            String suiteTicket = config.getParamValue();
+            System.out.println("suiteTicket=="+suiteTicket);
+            CompanyDingding oldDD = companyDingdingMapper.selectById(corpid);
+            if (oldDD == null) {
+                System.err.println("钉钉的corpId不存在,需要先调用syncCorpInfo");
+                return null;
+            }
+            String accessToken = null;
+            LocalDateTime expireDate = null;
+            if (oldDD.getExpireTime().isBefore(LocalDateTime.now())) {
+                result = getAuthCorpAccessToken(corpid, suiteTicket);
+                accessToken = result.getAccessToken();
+                expireDate = LocalDateTime.now().plusSeconds(result.getExpiresIn());
+            } else {
+                accessToken = oldDD.getAccessToken();
+            }
 
+            System.out.println("获取企业AccessToken=="+result.getBody());
+            if (accessToken != null) {
+                //获取授权企业信息
+                DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/service/get_auth_info");
+                OapiServiceGetAuthInfoRequest req = new OapiServiceGetAuthInfoRequest();
+                req.setSuiteKey(suiteKey);
+                req.setAuthCorpid(corpid);
+                // 第三方企业应用的填写应用SuiteKey和SuiteSecret。
+                // 定制应用填写应用的CustomKey和CustomSecret。
+                OapiServiceGetAuthInfoResponse rsp = client.execute(req, suiteKey ,suiteSecret ,suiteTicket);
+                System.out.println("获取授权企业信息,名称=="+rsp.getAuthCorpInfo().getCorpName());
+//
+                OapiServiceGetAuthInfoResponse.AuthCorpInfo authCorpInfo = rsp.getAuthCorpInfo();
+                List<OapiServiceGetAuthInfoResponse.Agent> agent = rsp.getAuthInfo().getAgent();
+                String corpid1 = authCorpInfo.getCorpid();
+
+                Long agentid = agent.stream().filter(a -> a.getAgentName().equals("工时管家")).findFirst().get().getAgentid();
+                CompanyDingding dingding = companyDingdingMapper.selectById(corpid1);
+                if (dingding.getAgentId() == null) {
+                    dingding.setAgentId(agentid);
+                    dingding.setAccessToken(accessToken);
+                    dingding.setExpireTime(expireDate);
+                    companyDingdingMapper.updateById(dingding);
+                }
+            }
         } catch (ApiException e) {
             e.printStackTrace();
         }
 
-
         return null;
     }
 

+ 154 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -23,6 +23,11 @@ import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.core.task.AsyncTaskExecutor;
@@ -31,11 +36,11 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.sql.Timestamp;
@@ -73,6 +78,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     @Value("${wx.app_secret}")
     public String appSecret;
 
+    @Resource
+    private ReportService reportService;
     @Resource
     ReportExtraDegreeMapper reportExtraDegreeMapper;
     @Resource
@@ -1562,6 +1569,151 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return httpRespMsg;
     }
 
+    @Override
+    public HttpRespMsg importData(Integer companyId, MultipartFile multipartFile, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        //然后处理文件
+        String fileName = multipartFile.getOriginalFilename();
+        File file = new File(fileName == null ? "file" : fileName);
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = multipartFile.getInputStream();
+            outputStream = new FileOutputStream(file);
+            byte[] buffer = new byte[4096];
+            int temp = 0;
+            while ((temp = inputStream.read(buffer, 0, 4096)) != -1) {
+                outputStream.write(buffer, 0, temp);
+            }
+            inputStream.close();
+            outputStream.close();
+            //然后解析表格
+            XSSFWorkbook workbook = new XSSFWorkbook(file);
+
+            //导入员工薪资表
+            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/M/d");
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/M/d");
+            //获取公司全部成员
+            List<User> allUserList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
+
+            XSSFSheet sheet = workbook.getSheetAt(0);
+            //由于第一行需要指明列对应的标题
+            int rowNum = sheet.getLastRowNum();
+            List<String> projectList = new ArrayList<>();
+            List<Project> allProjectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", companyId));
+            List<Report> reportList = new ArrayList<>();
+            int projectNameStartIndex = 2;
+
+            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+                XSSFRow row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                if (ExcelUtil.isRowEmpty(row)) {
+                    continue;
+                }
+                if (rowIndex == 0) {
+                    //第一行是标题,获取项目名称
+                    int pIndex = projectNameStartIndex;
+                    boolean projectNotExists = false;
+                    String neProjectName = null;
+                    while(pIndex < row.getLastCellNum() && row.getCell(pIndex).getCellTypeEnum() != CellType._NONE &&  row.getCell(pIndex).getCellTypeEnum() != CellType.BLANK) {
+                        row.getCell(pIndex).setCellType(CellType.STRING);
+                        String stringCellValue = row.getCell(pIndex).getStringCellValue().trim();
+                        projectList.add(stringCellValue);
+                        if (!allProjectList.stream().filter(p->p.getProjectName().equals(stringCellValue)).findAny().isPresent()) {
+                            projectNotExists = true;
+                            neProjectName = stringCellValue;
+                            break;
+                        }
+                        pIndex++;
+                    }
+                    if (projectNotExists) {
+                        //返回错误提示
+                        msg.setError("项目["+neProjectName+"]不存在,请先在项目管理中添加或导入。");
+                        return msg;
+                    }
+                } else {
+                    //数据行
+                    for (int i=1;i<2+projectList.size(); i++) {
+                        row.getCell(i).setCellType(CellType.STRING);
+                    }
+                    String reportDate = sdf.format(row.getCell(0).getDateCellValue());
+                    String username = row.getCell(1).getStringCellValue().trim();
+                    //检查人员是否存在
+                    Optional<User> any = allUserList.stream().filter(u -> u.getName().equals(username)).findAny();
+                    if (!any.isPresent()) {
+                        msg.setError("人员["+username+"]不存在,请先在组织结构中添加或者通过企业微信/钉钉同步导入");
+                        return msg;
+                    }
+                    User reportCreator = any.get();
+                    List<SimpleProjectime> timeCostList = new ArrayList<SimpleProjectime>();
+                    double totalTime = 0;
+                    for (int i=2; i < 2 + projectList.size(); i++) {
+                        String stringCellValue = row.getCell(i).getStringCellValue();
+                        double time = 0;
+                        String pName = projectList.get(i-2);
+                        Project project = allProjectList.stream().filter(p -> p.getProjectName().equals(pName)).findFirst().get();
+
+                        if (!StringUtils.isEmpty(stringCellValue)) {
+                            time = Double.parseDouble(stringCellValue);
+                            totalTime += time;
+                            Report report = new Report();
+                            report.setCompanyId(companyId);
+                            report.setCreatorId(reportCreator.getId());
+                            report.setProjectId(project.getId());
+                            report.setReportTimeType(1);
+                            report.setWorkingTime(time);
+                            report.setState(1);//导入的直接算审核通过
+                            report.setCreateDate(LocalDate.parse(reportDate, dtf));
+                            report.setCost(reportCreator.getCost().multiply(new BigDecimal(time)));
+                            reportList.add(report);
+                        }
+                        //检查个人总工时不能为0
+                        if (totalTime == 0) {
+                            msg.setError(username + "的工时为0,请检查修改");
+                            return msg;
+                        }
+                    }
+                }
+            }
+            //先删除老数据
+            for (Report r : reportList) {
+                reportMapper.delete(new QueryWrapper<Report>().eq("company_id", companyId).eq("creator_id", r.getCreatorId()).eq("create_date", r.getCreateDate()));
+            }
+            //存储
+            reportService.saveBatch(reportList);
+            msg.data = rowNum;
+        } catch (IOException e) {
+            e.printStackTrace();
+            msg.setError("文件处理出错");
+            return msg;
+        } catch (NullPointerException e) {
+            e.printStackTrace();
+            msg.setError("数据格式有误或存在空数据 导入失败");
+            return msg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError("发生其他错误");
+            return msg;
+        } finally {
+            //关闭流
+            try {
+                if (outputStream != null && inputStream != null) {
+                    outputStream.close();
+                    inputStream.close();
+                    System.out.println("流已关闭");
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+//            file.deleteOnExit();//程序退出时删除临时文件
+            System.out.println(file.delete());
+        }
+        return msg;
+    }
+
     private void fillDeptUser(List<DepartmentVO> list, List<HashMap> userList) {
         list.forEach(l->{
             List<HashMap> collect = userList.stream().filter(u -> u.get("departmentId").equals(l.getId())).collect(Collectors.toList());

+ 1 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml

@@ -293,4 +293,5 @@
     SELECT id,creator_id, working_time, cost FROM report WHERE state = 1 AND creator_id IN(SELECT id FROM user WHERE company_id = #{companyId})
     AND create_date BETWEEN #{startDate} and #{endDate}
     </select>
+
 </mapper>

+ 58 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -72,6 +72,8 @@
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="isSubstitude=false;fillInReport(-1,0)">填写日报</el-link>
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="isSubstitude=true; fillInReport(-1,0)">代填日报</el-link>
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="isSubstitude=false;fillInReport(-1,1)">批量填报</el-link>
+                            <el-link type="primary" v-if="user.role==1||user.role==2||user.manageDeptId != 0" style="margin-right:10px;" :underline="false" @click="importDialog=true">工时导入</el-link>
+                            
                             <!-- <el-link type="primary" style="margin-right:10px;" :underline="false" @click="isSubstitude=true; fillInReport(-1,1)">批量代填</el-link> -->
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="showExportDialog">导出日报</el-link>
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="batchApprove" >批量审核</el-link>
@@ -582,6 +584,19 @@
                 <el-button type="primary" @click="deny()" >确定</el-button>
             </div>
         </el-dialog>
+
+        <!--批量导入日报 -->
+        <el-dialog title="工时批量导入" v-if="importDialog" :visible.sync="importDialog" customClass="customWidth" width="500px">
+            <p>1. 下载
+            <el-link type="primary" style="margin-left:5px;" :underline="false" href="./upload/员工工时统计模板2.xlsx" download="员工工时导入模板.xlsx">员工工时统计模板.xlsx</el-link>
+            </p>
+            <p>2. 填写excel模板,请确保模板中的项目和人员已添加到系统中。</p>
+            <p style="display: flex;justify-content: center;">
+                <el-upload ref="upload"  action="#" :limit="1" :http-request="batchImportData" :show-file-list="false">
+                <el-button type="primary" :underline="false" >开始导入</el-button>
+            </el-upload>
+            </p>
+        </el-dialog>
     </section>
 </template>
 
@@ -591,6 +606,7 @@
     export default {
         data() {
             return {
+                importDialog:false,
                 denyForm:null,
                 denyReasonDialog:false,
                 monthWorkTimeDialog: false,
@@ -699,6 +715,48 @@
             };
         },
         methods: {
+            batchImportData(item) {
+                //首先判断文件类型
+                let str = item.file.name.split(".");
+                let format = str[str.length - 1];
+                if (format != "xls" && format != "xlsx") {
+                    this.$message({
+                        message: "请选择.xls或.xlsx文件",
+                        type: "error"
+                    });
+                } else {
+                    this.listLoading = true;
+                    let formData = new FormData();
+                    formData.append("file", item.file);
+                    formData.append("companyId", this.user.companyId);
+                    this.http.uploadFile('/report/importData', formData,
+                    res => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "成功导入"+res.data+"名人员的工时数据",
+                                type: "success"
+                            });
+                            this.getReportList();
+                            this.importDialog = false;
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+                }
+            },
             userssHu() {
                 this.http.post('/time-type/getCompanyTimeSetting',{ 
                     companyId: this.user.companyId