소스 검색

Merge branch 'master' of http://47.100.37.243:10080/wutt/manHourHousekeeper into master

seyason 2 년 전
부모
커밋
bb065e4d62

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

@@ -41,4 +41,6 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
     public String syncTranslation(String authCorpid,String mediaId,String outPutFileName,String outputFileFormat) throws Exception;
 
     public String getSyncTranslationResult(String jobId) throws Exception;
+
+    public HttpRespMsg getUserPunchRecord(int companyId, String userId, LocalDateTime startDateTime, LocalDateTime endDateTime, boolean showLog);
 }

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

@@ -5,6 +5,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.*;
@@ -14,6 +15,7 @@ import com.management.platform.util.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.tomcat.jni.Local;
 import org.json.HTTP;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -22,6 +24,7 @@ import org.springframework.http.*;
 import org.springframework.stereotype.Service;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.util.unit.DataUnit;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 import sun.net.www.http.HttpClient;
@@ -29,6 +32,7 @@ import sun.net.www.http.HttpClient;
 import javax.annotation.Resource;
 import java.io.*;
 import java.lang.reflect.Array;
+import java.math.BigDecimal;
 import java.net.URI;
 import java.text.SimpleDateFormat;
 import java.time.*;
@@ -55,6 +59,10 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
 
     public static final String GET_CHECKIN_DAYDATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token=ACCESS_TOKEN";
 
+    public static final String GET_CHECKIN_DATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=ACCESS_TOKEN";
+
+    public static final String GET_CHECKIN_OPTION = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption?access_token=ACCESS_TOKEN";
+
 
     @Value("${suitId}")
     private String suitId;
@@ -452,6 +460,153 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         return msg;
     }
 
+    @Override
+    public HttpRespMsg getUserPunchRecord(int companyId, String userId, LocalDateTime startDateTime, LocalDateTime endDateTime, boolean showLog) {
+        HttpRespMsg msg = new HttpRespMsg();
+        WxCorpInfo corpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
+        if (corpInfo == null) {
+            //msg.setError("该企业未对接企业微信");
+            msg.setError(MessageUtils.message("wx.dockError"));
+            return msg;
+        }
+        String url = null;
+        try {
+            startDateTime = startDateTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
+            long startTime = startDateTime.toEpochSecond(ZoneOffset.of("+8"));
+            endDateTime = endDateTime.withHour(23).withMinute(59).withSecond(0).withNano(0);
+            long endTime = endDateTime.toEpochSecond(ZoneOffset.of("+8"));
+            System.out.println("startTime=" + startTime + ",endTime=" + endTime);
+
+            int batchCount = 1;
+            int batchSize = 100;
+            int totalLength = 1;
+            List<String> corpwxUserIds = new ArrayList<>();
+            if (userId == null) {
+                //获取企业下的全部员工
+                List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).isNotNull("corpwx_userid").eq("is_active", 1));
+                System.out.println("获取考勤记录users size==" + users.size());
+                corpwxUserIds = users.stream().map(User::getCorpwxUserid).collect(Collectors.toList());
+                totalLength = corpwxUserIds.size();
+                batchCount = totalLength / batchSize + (totalLength % batchSize == 0 ? 0 : 1);
+            } else {
+                //指定获取员工
+                User user = userMapper.selectById(userId);
+                corpwxUserIds.add(user.getCorpwxUserid());
+                System.out.println("获取corpwxuserid==" + user.getCorpwxUserid() + "的考勤记录");
+            }
+            //按批调用
+            for (int i = 0; i < batchCount; i++) {
+                int fromIndex = i * batchSize;
+                int toIndex = (i + 1) * batchSize;
+                if (toIndex > totalLength) toIndex = totalLength;
+                Object[] objects = corpwxUserIds.subList(fromIndex, toIndex).toArray(new String[0]);
+                reqPunchRecord(corpInfo, startTime, endTime, objects, showLog);
+            }
+        } catch (Exception exception) {
+            exception.printStackTrace();
+        }
+
+        return msg;
+    }
+
+    public void reqPunchRecord(WxCorpInfo corpInfo, long startTime, long endTime, Object[] objects, boolean showLog)throws Exception {
+        DateTimeFormatter mdFormat = DateTimeFormatter.ofPattern("yyyy/M/d");
+        LocalDateTime needDataTime = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
+        long dataTime = needDataTime.toEpochSecond(ZoneOffset.of("+8"));
+        String checkinOption = getCheckinOption(corpInfo, dataTime, objects);
+        JSONObject optionObject = JSONObject.parseObject(checkinOption);
+        JSONArray  optionDatas= optionObject.getJSONArray("info");
+        String url = GET_CHECKIN_DATA.replace("ACCESS_TOKEN", getCorpAccessToken(corpInfo));
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        System.out.println("" + objects.toString());
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("starttime", startTime);
+        reqParam.put("endtime", endTime);
+        reqParam.put("useridlist", objects);
+        reqParam.put("opencheckindatatype", 3);
+        HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
+        ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,
+                HttpMethod.POST, requestEntity, String.class);
+
+        if (responseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = responseEntity.getBody();
+            if (showLog) System.out.println(resp);
+            JSONObject json = JSONObject.parseObject(resp);
+            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+            if (json.getIntValue("errcode") == 0) {
+                JSONArray checkindata = json.getJSONArray("checkindata");
+                System.out.println(checkindata);
+                for (int i = 0; i < objects.length; i++) {
+                    List<Integer> upList=new ArrayList<>();
+                    List<Integer> downList=new ArrayList<>();
+                    for (int j = 0; j < checkindata.size(); j++) {
+                        JSONObject jsonObject = checkindata.getJSONObject(j);
+                        if (jsonObject.get("userid").equals(objects[i])) {
+                            //todo: 获取最早上班打卡时间以及最晚下班打卡时间
+                            Integer time = (Integer) jsonObject.get("checkin_time");
+                            if (jsonObject.get("checkin_type").equals("上班打卡")) {
+                                upList.add(time);
+                            } else if(jsonObject.get("checkin_type").equals("下班打卡")) downList.add(time);
+                        }
+                    }
+                    double restTime = 0.0;//小时为单位
+                    for (int k = 0; k < optionDatas.size(); k++) {
+                        if(optionDatas.getJSONObject(k).get("userid").equals(objects[i])){
+                            JSONObject group = optionDatas.getJSONObject(k).getJSONObject("group");
+                            JSONArray workRules = group.getJSONArray("checkindate").getJSONObject(0).getJSONArray("checkintime");
+                            if (workRules.size() <= 1) {
+                                restTime = 1.0;//一个小时午休
+                            } else {
+                                restTime = 1.0 * (workRules.getJSONObject(1).getIntValue("work_sec") - workRules.getJSONObject(0).getIntValue("off_work_sec")) / 3600;
+                            }
+                        }
+                    }
+                    UserCorpwxTime userCorpwxTime=new UserCorpwxTime();
+                    userCorpwxTime.setCorpwxUserid((String) objects[i]);
+                    userCorpwxTime.setCompanyId(corpInfo.getCompanyId());
+                    for (Integer integer : upList) {
+                        if(objects[i].equals("woy9TkCAAArkpTq76GOJYsbYGgzk1g1w")){
+                            System.out.println("上班"+DateTimeUtil.getTimeFromSeconds(integer));
+                        }
+                    }
+                    for (Integer integer : downList) {
+                        if(objects[i].equals("woy9TkCAAArkpTq76GOJYsbYGgzk1g1w")){
+                            System.out.println("下班"+DateTimeUtil.getTimeFromSeconds(integer));
+                        }
+                    }
+                    if(upList.isEmpty()||downList.isEmpty()){
+                        continue;
+                    }
+                    Integer min = Collections.min(upList);
+                    Integer max = Collections.max(downList);
+                    String minTime = DateTimeUtil.getTimeFromSeconds(min);
+                    String maxTime = DateTimeUtil.getTimeFromSeconds(max);
+                    DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm");
+                    userCorpwxTime.setStartTime(LocalTime.parse(minTime,df).plusHours(8).format(df));
+                    userCorpwxTime.setEndTime(LocalTime.parse(maxTime,df).plusHours(8).format(df));
+                    userCorpwxTime.setCreateDate(LocalDate.now());
+                    userCorpwxTime.setWxCorpid(corpInfo.getCorpid());
+                    userCorpwxTime.setWeekDay(LocalDate.now().getDayOfWeek().getValue());
+                    userCorpwxTime.setWeekDayTxt(DateTimeUtil.getWeekDayTxt(userCorpwxTime.getWeekDay()));
+                    BigDecimal bigDecimal=new BigDecimal(Duration.between(LocalTime.parse(minTime,df).plusHours(8),LocalTime.parse(maxTime,df).plusHours(8)).toMinutes());
+                    bigDecimal=bigDecimal.divide(BigDecimal.valueOf(60),1,BigDecimal.ROUND_HALF_UP).subtract(new BigDecimal(restTime));
+                    userCorpwxTime.setWorkHours(bigDecimal.doubleValue());
+                    System.out.println(userCorpwxTime);
+                    UserCorpwxTime item = userCorpwxTimeMapper.selectOne(new QueryWrapper<UserCorpwxTime>().eq("corpwx_userid", (String) objects[i])
+                            .eq("create_date", LocalDate.now()));
+                    if (item != null) {
+                        userCorpwxTime.setId(item.getId());
+                        //已存在记录,进行更新
+                        userCorpwxTimeMapper.updateById(userCorpwxTime);
+                    } else {
+                        userCorpwxTimeMapper.insert(userCorpwxTime);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public HttpRespMsg syncMembByCardTime(WxCorpInfo wxCorpInfo) {
         HttpRespMsg msg = new HttpRespMsg();
@@ -527,6 +682,25 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         return msg;
     }
 
+    private String getCheckinOption(WxCorpInfo corpInfo,long dataTime,Object[] objects) throws  Exception{
+        String url = GET_CHECKIN_OPTION.replace("ACCESS_TOKEN", getCorpAccessToken(corpInfo));
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        System.out.println("" + objects.toString());
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("datetime", dataTime);
+        reqParam.put("useridlist", objects);
+        HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
+        ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,
+                HttpMethod.POST, requestEntity, String.class);
+
+        if (responseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = responseEntity.getBody();
+            return resp;
+        }
+        return "";
+    }
+
 
     private void reqOnceCardTime(WxCorpInfo corpInfo, long startTime, long endTime, Object[] objects, boolean showLog) throws Exception {
         DateTimeFormatter mdFormat = DateTimeFormatter.ofPattern("yyyy/M/d");

+ 18 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -472,8 +472,21 @@ public class TimingTask {
         }
     }
 
+    @Scheduled(cron = "0 30,0/5 17-19 * * ?")
+    public void  getClockRecordWithCorpWx(){
+        /*if(isDev) return;*/
+        //todo: 有限制无考勤不填报的情况才获取
+        LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX).withSecond(0).withNano(0);
+        List<TimeType> typeList = timeTypeMapper.selectList(new QueryWrapper<TimeType>().eq("not_allowed_no_attendance", 1));
+        for (TimeType type : typeList) {
+            Integer companyId = type.getCompanyId();
+            wxCorpInfoService.getUserPunchRecord(companyId, null, start, end, false);
+        }
+    }
+
     public static void main(String[] args) {
-        int passwordLength = 30;
+        /*int passwordLength = 30;
         List<String> stringList=new ArrayList<>();
         new SecureRandom().ints(passwordLength, 0, VALID_TOKEN_CHARS.size())
                 .map(VALID_TOKEN_CHARS::get).forEach(v->stringList.add(String.valueOf((char) v)));
@@ -481,7 +494,10 @@ public class TimingTask {
         for (String s : stringList) {
             token+=s;
         }
-        System.out.println(token);
+        System.out.println(token);*/
+        LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
+        System.out.println(start+"  "+end);
     }
 
     //发送上周填写的工时统计

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 49545 - 8815
fhKeeper/formulahousekeeper/management-platform/workTime.log


+ 8 - 1
fhKeeper/formulahousekeeper/octopus/src/views/customer/list.vue

@@ -191,7 +191,7 @@
         </el-dialog>
         <!-- 其他设置 -->
         <el-dialog v-if="editDialogG" :visible.sync="editDialogG" title="其他设置">
-            <el-form label-width="100px">
+            <el-form label-width="100px" class="otherForm">
                 <el-form-item><el-checkbox v-model="dialogData.reportWorkflow">是否开启审批流设置</el-checkbox></el-form-item>
                 <el-form-item><el-checkbox v-model="dialogData.needEvaluate">审核通过需输入评价</el-checkbox></el-form-item>
                 <el-form-item><el-checkbox v-model="dialogData.mainProjectState">是否启用主项目模式</el-checkbox></el-form-item>
@@ -803,4 +803,11 @@
     margin-left: 10px;
     margin-bottom: 5px;
 }
+</style>
+<style>
+.otherForm .el-form-item{
+    float: left;
+    width: 50%;
+    margin: 0;
+}
 </style>

+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue

@@ -417,7 +417,7 @@
                 </el-form-item>
                 <el-form-item :label="$t('projectclassification')" v-if="user.timeType.mainProjectState != '1'">
                     <!-- <el-select v-model="addForm.category"  style="width:32%;" clearable :disabled="!permissions.projectManagement && addForm.creatorId != user.id"> -->
-                    <el-select v-model="addForm.category"  style="width:32%;" clearable>
+                    <el-select v-model="addForm.category"  style="width:32%;" clearable filterable>
                         <el-option v-for="(item) in baseClfList" :key="item.id" :value="item.id" :label="item.name"></el-option>
                     </el-select>
                 </el-form-item>

+ 3 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue

@@ -961,6 +961,7 @@ export default {
       insertFormPlates: [],
       saveBtnLoading: false,
       onlyDirect: false,
+      nextCursor: ''
     };
   },
   filters: {
@@ -2117,12 +2118,14 @@ export default {
           // role: this.role
           roleId: this.roleId,
           onlyDirect: this.onlyDirect ? "1" : "0",
+          cursor: this.nextCursor, // 游标
         },
         (res) => {
           this.listLoading = false;
           if (res.code == "ok") {
             this.list = res.data.records;
             this.total = res.data.total;
+            this.nextCursor = this.data.nextCursor
           } else {
             this.$message({
               message: res.msg,

+ 38 - 20
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/weekEdit.vue

@@ -12,7 +12,7 @@
                     </div>
                 </van-grid-item>
             </van-grid>
-            <van-grid :column-num="weekIndex" :border="false" style="position:relative">
+            <van-grid :column-num="weekIndex == 7 ? weekIndex : weekIndex + 1" :border="false" style="position:relative">
                 <van-grid-item v-for="item,index in dateRange" :key="index" :class="index == inbtn ? 'inbtn' : ''">
                     <van-button
                     class="selectgxbtn"
@@ -21,6 +21,9 @@
                     @click="switchWeek(item,index)"
                     :disabled="canSelect(item)">{{weekArr[index]}}</van-button>
                 </van-grid-item>
+                <van-grid-item v-if="weekIndex != 7">
+                    <van-button type="default" size="mini" class="selectgxbtn" @click="addWeekIndex()" icon="plus"></van-button>
+                </van-grid-item>
                 <div class="kaoqin" v-if="kaoqinText"><span>当日考勤记录:</span><span>{{kaoqinText}}</span></div>
                 <div class="kaoqin" v-if="workTimeText"><span>已填报工时:</span><span>{{workTimeText}}小时</span></div>
                 <div class="submitClear">
@@ -429,7 +432,7 @@
 
                 dateRange: [],  //周时间数组
                 dateText: [],   //时间段字符串
-                weekArr: ['周一','周二','周三','周四','周五','周六'],
+                weekArr: ['周一','周二','周三','周四','周五','周六','周日'],
                 inbtn: 0,
                 weekIndex: 5,
                 weekSwitchIndex: 1,
@@ -524,23 +527,6 @@
             },
             // 切换星期
             switchWeek(item,index){
-                // if(this.user.timeType.notAllowedNoAttendance == 1){
-                //     let havework = false
-                //     for(let i in this.currentForm.domains){
-                //         if(this.currentForm.domains[i].projectId){
-                //             havework = true
-                //         }
-                //     }
-                //     if(havework){
-                //         if(this.kaoqinText){
-                //             if(this.currentForm.cardtime == 0){
-                //                 this.$toast.fail('无考勤记录' + this.weekArr[this.inbtn] +'不可填报')
-                //             }
-                //         }else{
-                //             this.$toast.fail('无考勤记录' + this.weekArr[this.inbtn] +'不可填报')
-                //         }
-                //     }
-                // }
                 this.form[this.inbtn] = this.currentForm
                 this.inbtn = index
                 this.currentForm = this.form[this.inbtn]
@@ -552,6 +538,37 @@
                 this.getKaoqin()
                 this.getWorkTime()
             },
+            addWeekIndex(){
+                console.log(this.weekIndex, this.dateRange);
+                if(this.dateRange.length < 7){
+                    this.weekIndex += 1
+                    let time = this.dateRange[this.dateRange.length - 1]
+                    this.dateRange.push(new Date(time.getFullYear(),time.getMonth(),time.getDate()+1))
+                    let time2 = new Date(this.dateText[1])
+                    let time3 = new Date(time2.getFullYear(),time2.getMonth(),time2.getDate()+1)
+                    this.dateText[1] = this.format(time3,'yyyy-MM-dd')
+                    this.form.push({
+                            createDate: this.format(this.dateRange[this.dateRange.length - 1],"yyyy-MM-dd"),
+                            domains: [{
+                                id: null,
+                                projectId: "",
+                                projectName: "",
+                                workingTime: this.user.timeType.allday,
+                                content: "",
+                                progress: 100,
+                                state: 2,
+                                multiWorktime:0,
+                                worktimeList:[{}],
+                                degreeId: '',
+
+                                auditorFirst: {name:'',id:''},
+                                auditorSec: {name:'',id:''},
+                                auditorThird: {name:'',id:''},
+                                ccUserid: {name:'',id:''}
+                            }],
+                        })
+                }
+            },
             
             // 获取日考勤记录
             getKaoqin(){
@@ -602,6 +619,8 @@
             getDateRange(){
                 if(this.user.companyId == 817){
                     this.weekIndex = 6
+                }else{
+                    this.weekIndex = 5
                 }
                 let nowDate = new Date()
                 let nowWeekday = nowDate.getDay()
@@ -1926,7 +1945,6 @@
         },
         
         mounted() {
-            this.user.timeType.notAllowedNoAttendance = 1
             this.timeRange = []
             for(let i=0.5; i<=20; i+=0.5){
                 this.timeRange.push(i)

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/projectInside.vue

@@ -400,6 +400,7 @@ export default {
         }
     }
     .addtaskicon{
+        opacity: 0.5;
         position: fixed;
         z-index: 1000;
         font-size: 50px;