Przeglądaj źródła

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

wutt 5 lat temu
rodzic
commit
2bb3e49890
22 zmienionych plików z 434 dodań i 160 usunięć
  1. 3 3
      fhKeeper/formulahousekeeper/inva_4_tivo/index.html
  2. 4 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ImageProcessingController.java
  3. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TimeCalculationShowController.java
  4. 8 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeCalculation.java
  5. 71 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeCalculationShow.java
  6. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TimeCalculationShowMapper.java
  7. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ScreenshotService.java
  8. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TimeCalculationShowService.java
  9. 177 90
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ScreenshotServiceImpl.java
  10. 20 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TimeCalculationServiceImpl.java
  11. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TimeCalculationShowServiceImpl.java
  12. 9 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CheckPicUtil.java
  13. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CodeGenerator.java
  14. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ImageCompare.java
  15. 13 29
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ImageReconizeUtil.java
  16. 10 9
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeCalculationMapper.xml
  17. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeCalculationShowMapper.xml
  18. 2 1
      fhKeeper/formulahousekeeper/mywork/home.cpp
  19. 4 0
      fhKeeper/formulahousekeeper/mywork/mainwindow.cpp
  20. 1 2
      fhKeeper/formulahousekeeper/mywork/mainwindow.h
  21. 13 0
      fhKeeper/formulahousekeeper/mywork/mainwindow.ui
  22. 2 1
      fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue

+ 3 - 3
fhKeeper/formulahousekeeper/inva_4_tivo/index.html

@@ -71,7 +71,7 @@
                         <div class="text-container">
                             <h1>最贴心的工时管理工具</h1>
                             <p class="p-large">工时管家利用图像识别技术,精准判断员工桌面运行软件,可统计员工每天工时分配情况,如工作、娱乐等;领导可通过后台查看员工实时桌面,并对员工异常工作状态做出提醒。</p>
-                            <a class="btn-solid-lg page-scroll" href="./download/WorkTime.exe" download="工时管家">免费下载试用</a>
+                            <a class="btn-solid-lg page-scroll" href="http://worktime.ttkuaiban.com/#/login" download="工时管家">免费试用</a>
                         </div>
                     </div>
                     <div class="col-lg-6 col-xl-7">
@@ -97,7 +97,7 @@
                         <p>工时管家客户端会截取保存员工当前桌面, 通过图像分析, 精准判断员工正在操作的软件,
                             获知该员工当前的工作状态, 如编程、设计、查阅资料、处理文档、玩游戏、听音乐等; 员工通过客户端可查看自己每天的工作时间段,
                             填写工作日报。</p>
-                        <a class="btn-solid-reg page-scroll" href="./download/WorkTime.exe" download="工时管家">去下载</a>
+                        <a class="btn-solid-reg page-scroll" href="http://worktime.ttkuaiban.com/#/login" download="工时管家">免费试用</a>
                     </div>
                 </div>
                 <div class="col-lg-6">
@@ -122,7 +122,7 @@
                         <h3>工时管家管理后台</h3>
                         <p>领导通过后台可查看客户端所截取的员工电脑桌面图像, 通过图像识别技术可对员工异常工作状态进行提醒,如玩游戏、听音乐、看影视剧等;
                             并对每个员工的工时进行分类统计,支持导出报表;支持项目管理,领导可根据项目,查看每个员工在该项目花费的工时;领导可查看员工通过客户端所填写的工作日报及异常申请。</p>
-                        <a class="btn-solid-reg page-scroll" href="http://worktime.ttkuaiban.com/#/login" target="_blank">去登录</a>
+                        <a class="btn-solid-reg page-scroll" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费试用</a>
                     </div>
                 </div>
             </div>

+ 4 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ImageProcessingController.java

@@ -33,6 +33,10 @@ public class ImageProcessingController {
         return screenshotService.saveAndProcessImage(screenshotvo);
     }
 
+    @RequestMapping("/reTestPic")
+    public HttpRespMsg reTestPic(Integer id) {
+        return screenshotService.reTestPicMatch(id);
+    }
     /**
      * 初始化redis图片搜索的关键词,
      * 防止数据库初始添加了其他字段导致redis里的数据不是最新的,

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TimeCalculationShowController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author 吴涛涛
+ * @since 2020-02-05
+ */
+@RestController
+@RequestMapping("/time-calculation-show")
+public class TimeCalculationShowController {
+
+}
+

+ 8 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeCalculation.java

@@ -17,7 +17,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author 吴涛涛
- * @since 2020-01-16
+ * @since 2020-02-06
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -39,7 +39,7 @@ public class TimeCalculation extends Model<TimeCalculation> {
     private String userId;
 
     /**
-     * 行为代码 等价于screenshot表中的pic_type
+     * 行为代码 -1-其他 0-编程 1-上网 2-文档 3-设计 4-美工 5-运营 6-小说 7-娱乐 8-音乐
      */
     @TableField("action_type")
     private Integer actionType;
@@ -68,6 +68,12 @@ public class TimeCalculation extends Model<TimeCalculation> {
     @TableField("duration")
     private Integer duration;
 
+    /**
+     * 开始时的第一张截图
+     */
+    @TableField("pic_url")
+    private String picUrl;
+
 
     @Override
     protected Serializable pkVal() {

+ 71 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeCalculationShow.java

@@ -0,0 +1,71 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author 吴涛涛
+ * @since 2020-02-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class TimeCalculationShow extends Model<TimeCalculationShow> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 时间记录表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 用户表主键
+     */
+    @TableField("user_id")
+    private String userId;
+
+    /**
+     * 日期
+     */
+    @TableField("date")
+    private LocalDate date;
+
+    /**
+     * 开始时间
+     */
+    @TableField("start_time")
+    private LocalTime startTime;
+
+    /**
+     * 结束时间
+     */
+    @TableField("end_time")
+    private LocalTime endTime;
+
+    /**
+     * 持续时间 秒
+     */
+    @TableField("duration")
+    private Integer duration;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.TimeCalculationShow;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author 吴涛涛
+ * @since 2020-02-05
+ */
+public interface TimeCalculationShowMapper extends BaseMapper<TimeCalculationShow> {
+
+}

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

@@ -22,5 +22,7 @@ public interface ScreenshotService extends IService<Screenshot> {
 
     HttpRespMsg saveAndProcessImage(ScreenshotVO screenshotvo);
 
+    HttpRespMsg reTestPicMatch(int id);
+
     HttpRespMsg updateRedisPicContentKeywords();
 }

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TimeCalculationShowService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.TimeCalculationShow;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author 吴涛涛
+ * @since 2020-02-05
+ */
+public interface TimeCalculationShowService extends IService<TimeCalculationShow> {
+
+}

+ 177 - 90
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ScreenshotServiceImpl.java

@@ -1,22 +1,17 @@
 package com.management.platform.service.impl;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.constant.Constant;
 import com.management.platform.constant.Parameter;
 import com.management.platform.entity.PicContentKeywords;
 import com.management.platform.entity.Screenshot;
 import com.management.platform.entity.TimeCalculation;
-import com.management.platform.entity.User;
+import com.management.platform.entity.TimeCalculationShow;
 import com.management.platform.entity.vo.ScreenshotVO;
 import com.management.platform.mapper.*;
-import com.management.platform.mapper.PicContentKeywordsMapper;
 import com.management.platform.service.ScreenshotService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.util.*;
-import net.sourceforge.tess4j.Word;
 import org.apache.log4j.Logger;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -68,15 +63,150 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
 
     @Resource
     private ScreenshotMapper screenshotMapper;
-
     @Resource
     private PicContentKeywordsMapper picContentKeywordsMapper;
-
     @Resource
     private TimeCalculationMapper timeCalculationMapper;
-
     @Resource
     private UserMapper userMapper;
+    @Resource
+    private TimeCalculationShowMapper timeCalculationShowMapper;
+
+    //每次获取到截屏后计算并处理
+    private void calculateTime(Screenshot screenshot) {
+        try {
+            //首先拿去处理show表
+            calculateShowTime(screenshot);
+
+            //如果图片类型为空 则认为是 -1 - 其他
+            if (null == screenshot.getPicType()) {
+                screenshot.setPicType(-1);
+            }
+            //默认状态为不连续 如果下面判断是连续才会修改为true
+            Boolean isConsecutive = false,
+                    isSameType = false;
+            //获取本人当天结束时间为准的最后一条记录
+            TimeCalculation latestRecord = timeCalculationMapper.selectOne(new QueryWrapper<TimeCalculation>()
+                    .eq("user_id", screenshot.getUid())
+                    .eq("date", screenshot.getIndate().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
+                    .orderByDesc("id")
+                    .last("LIMIT 1"));
+            //截图时间
+            LocalTime currentTime = screenshot.getIndate().toLocalTime();
+            //如果有上一条记录
+            if (latestRecord != null) {
+                //前后两张是否相同类型
+                isSameType = latestRecord.getActionType().equals(screenshot.getPicType());
+                //前后两张时间是否连续 这个目前为600秒
+                LocalTime estimatedTime = latestRecord.getEndTime();
+                Integer durationSecond = ((currentTime.getHour() - estimatedTime.getHour()) * 3600
+                        + (currentTime.getMinute() - estimatedTime.getMinute()) * 60
+                        + (currentTime.getSecond() - estimatedTime.getSecond()));
+                //断层不大于一定时间的话  用来判断是否连续
+                isConsecutive = durationSecond <= DETECTION_INTERVAL;
+            }
+            if (isConsecutive && isSameType) {
+                //如果时间连续 且是同一类型的话 修改上一条记录的最后时间和持续时间
+                LocalTime startTime = latestRecord.getStartTime();
+                //计算新的间隔
+                Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
+                        + (currentTime.getMinute() - startTime.getMinute()) * 60
+                        + (currentTime.getSecond() - startTime.getSecond()));
+                //设置新的结束时间和持续时间 保存记录
+                latestRecord.setEndTime(currentTime).setDuration(duration);
+                timeCalculationMapper.updateById(latestRecord);
+            } else {
+                //如果不是连续的话 新增一个记录
+                TimeCalculation timeCalculation = new TimeCalculation();
+                timeCalculation
+                        .setUserId(screenshot.getUid())
+                        //根据截图种类设置行为代号
+                        .setActionType(screenshot.getPicType())
+                        .setDate(screenshot.getIndate().toLocalDate())
+                        //设置开始时间和结束时间都为当前时间
+                        .setStartTime(currentTime)
+                        .setEndTime(currentTime)
+                        //第一次的持续时间默认为最少单位1秒
+                        .setDuration(1)
+                        .setPicUrl(screenshot.getPicUrl());
+                timeCalculationMapper.insert(timeCalculation);
+                if (isConsecutive) {
+                    //然后如果只是类型不同但是能连上的话
+                    LocalTime startTime = latestRecord.getStartTime();
+                    //计算新的间隔
+                    Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
+                            + (currentTime.getMinute() - startTime.getMinute()) * 60
+                            + (currentTime.getSecond() - startTime.getSecond()));
+                    //设置新的结束时间和持续时间 保存记录
+                    latestRecord.setEndTime(currentTime).setDuration(duration);
+                    timeCalculationMapper.updateById(latestRecord);
+                }
+            }
+            /*之后可能还需要处理跨越一天的情况*/
+        } catch (NullPointerException e) {
+            //凡是有空指针说明缺少用户id或者时间数据
+            log.info("工作时长统计失败 缺少用户或时间数据");
+        }
+    }
+
+    //每次获取到截屏后计算并处理
+    private void calculateShowTime(Screenshot screenshot) {
+        try {
+            //如果图片类型为空 则认为是 -1 - 其他
+            if (null == screenshot.getPicType()) {
+                screenshot.setPicType(-1);
+            }
+            //默认状态为不连续 如果下面判断是连续才会修改为true
+            Boolean isConsecutive = false;
+            //获取本人当天结束时间为准的最后一条记录
+            TimeCalculationShow latestRecord = timeCalculationShowMapper.selectOne(
+                    new QueryWrapper<TimeCalculationShow>()
+                            .eq("user_id", screenshot.getUid())
+                            .eq("date", screenshot.getIndate().toLocalDate())
+                            .orderByDesc("end_time")
+                            .last("LIMIT 1"));
+            //截图时间
+            LocalTime currentTime = screenshot.getIndate().toLocalTime();
+            //如果有上一条记录
+            if (latestRecord != null) {
+                //前后两张时间是否连续 这个目前为600秒
+                LocalTime estimatedTime = latestRecord.getEndTime();
+                Integer durationSecond = ((currentTime.getHour() - estimatedTime.getHour()) * 3600
+                        + (currentTime.getMinute() - estimatedTime.getMinute()) * 60
+                        + (currentTime.getSecond() - estimatedTime.getSecond()));
+                //断层不大于一定时间的话  用来判断是否连续
+                isConsecutive = durationSecond <= DETECTION_INTERVAL;
+            }
+
+            if (isConsecutive) {
+                //如果是连续的话 修改上一条记录的最后时间和持续时间
+                LocalTime startTime = latestRecord.getStartTime();
+                //计算新的间隔
+                Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
+                        + (currentTime.getMinute() - startTime.getMinute()) * 60
+                        + (currentTime.getSecond() - startTime.getSecond()));
+                //设置新的结束时间和持续时间 保存记录
+                latestRecord.setEndTime(currentTime).setDuration(duration);
+                timeCalculationShowMapper.updateById(latestRecord);
+            } else {
+                //如果不是连续的话 新增一个记录
+                TimeCalculationShow timeCalculationShow = new TimeCalculationShow();
+                timeCalculationShow
+                        .setUserId(screenshot.getUid())
+                        .setDate(screenshot.getIndate().toLocalDate())
+                        //设置开始时间和结束时间都为当前时间
+                        .setStartTime(currentTime)
+                        .setEndTime(currentTime)
+                        //第一次的持续时间默认为最少单位1秒
+                        .setDuration(1);
+                timeCalculationShowMapper.insert(timeCalculationShow);
+            }
+            /*之后可能还需要处理跨越一天的情况*/
+        } catch (NullPointerException e) {
+            //凡是有空指针说明缺少用户id或者时间数据
+            log.info("工作时长统计失败 缺少用户或时间数据");
+        }
+    }
 
     //获取所有人最新的截图
     @Override
@@ -126,7 +256,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
     @Override
     public HttpRespMsg saveAndProcessImage(ScreenshotVO screenshotvo) {
         Map<String, Object> fileMap = UploadFileToFileNameUtil.uploadFile(screenshotvo.getFile(), path);
-        String filePath = (String)fileMap.get("sqlFilePath");
+        String filePath = (String) fileMap.get("sqlFilePath");
         Screenshot screenshot = new Screenshot();
         BeanUtils.copyProperties(screenshotvo, screenshot);
         screenshot.setPicUrl(filePath);
@@ -162,7 +292,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
 //            //由于存入数据库的对象被序列化成了json字符串,所以从redis里拿方便
 //            members = redisUtil.members(Constant.COMMON_SOFTWARE_KEYWORDS);
 //        }
-        File picFile = new File((String)fileMap.get("newFile"));
+        File picFile = new File((String) fileMap.get("newFile"));
         if (isNovel(textContents)) {
             screenshot.setPicType(6);
         } else if (isDocument(textContents)) {
@@ -180,7 +310,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
                 File f = new File(prePath);
                 if (f.exists()) {
                     ImageCompare comp = new ImageCompare();
-                    if (comp.isMoviePlay((String)fileMap.get("newFile"), prePath)) {
+                    if (comp.isMoviePlay((String) fileMap.get("newFile"), prePath)) {
                         screenshot.setPicType(7);
                         //前面那条也更新
                         if (preShot.getPicType() != null && preShot.getPicType() != 7) {
@@ -194,7 +324,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
         if (screenshot.getPicType() == null) {
             //默认设置为查资料
             try {
-                String browserName = isBrowser(new File((String)fileMap.get("newFile")));
+                String browserName = isBrowser(new File((String) fileMap.get("newFile")));
                 System.out.println(
                         "找到浏览器==" + browserName
                 );
@@ -212,11 +342,34 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
         return new HttpRespMsg();
     }
 
+    @Override
+    public HttpRespMsg reTestPicMatch(int id) {
+        Screenshot item = screenshotMapper.selectById(id);
+        String fileName = item.getPicUrl().replaceAll("/upload/", "");
+        String filePath = path + fileName;
+        File pic = new File(filePath);
+        String devName = isDevelop(pic);
+        HttpRespMsg msg = new HttpRespMsg();
+        if (devName != null) {
+            msg.data = devName;
+        } else {
+            try {
+                String browserName = isBrowser(pic);
+                if (browserName != null) {
+                    msg.data = browserName;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return msg;
+    }
+
     @Override
     public HttpRespMsg updateRedisPicContentKeywords() {
         List<PicContentKeywords> picContentKeywords = picContentKeywordsMapper.selectList(null);
-        for (PicContentKeywords  keyWord : picContentKeywords) {
-            redisUtil.sSetJsonString("keyWords",keyWord);
+        for (PicContentKeywords keyWord : picContentKeywords) {
+            redisUtil.sSetJsonString("keyWords", keyWord);
         }
         HttpRespMsg msg = new HttpRespMsg();
         msg.data = redisUtil.members("keyWords");
@@ -250,7 +403,6 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
             return false;
         }
 
-
         //第二步,匹配小说常见词汇,超过5次,认为是小说
         try {
             //填充小说关键字到内存,减少重复读取
@@ -299,6 +451,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
 //        System.out.println("结果:"+b);
     }
 
+
     private static boolean isPureColor(BufferedImage img, int colorPixel) {
         int with = img.getWidth();
         int height = img.getHeight();
@@ -318,7 +471,6 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
         return !hasDifferent;
     }
 
-
     /**
      * 是否全是汉字<br>
      * 根据汉字编码范围进行判断<br>
@@ -335,71 +487,6 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
         return pattern.matcher(str).matches();
     }
 
-
-    //每次获取到截屏后计算并处理
-    private void calculateTime(Screenshot screenshot) {
-        try {
-            //如果图片类型为空 则认为是-1-其他
-            if(null == screenshot.getPicType()){
-                screenshot.setPicType(-1);
-            }
-            //默认状态为不连续 如果下面判断是连续才会修改为true
-            Boolean isConsecutive = false;
-            //获取本人当天结束时间为准的最后一条记录
-            TimeCalculation latestRecord = timeCalculationMapper.selectOne(new QueryWrapper<TimeCalculation>()
-                    .eq("user_id", screenshot.getUid())
-                    .eq("date", screenshot.getIndate().toLocalDate())
-                    .orderByDesc("end_time")
-                    .last("LIMIT 1"));
-            //单独记录当前的时间以便使用
-            LocalTime currentTime = screenshot.getIndate().toLocalTime();
-            if (latestRecord != null) {
-                //首先对比类型 同一种行为才有可能合并
-                if (latestRecord.getActionType().equals(screenshot.getPicType())) {
-                    //如果有记录的话 计算上次结束和新的开始的时间差
-                    LocalTime estimatedTime = latestRecord.getEndTime();
-                    Integer durationSecond = ((currentTime.getHour() - estimatedTime.getHour()) * 3600
-                            + (currentTime.getMinute() - estimatedTime.getMinute()) * 60
-                            + (currentTime.getSecond() - estimatedTime.getSecond()));
-                    //断层不大于一定时间的话 这个定义目前为600秒
-                    if (durationSecond <= DETECTION_INTERVAL) {
-                        //确认连续 将状态改为连续
-                        isConsecutive = true;
-                    }
-                }
-            }
-            if (isConsecutive) {
-                //如果是连续的话 修改上一条记录的最后时间和持续时间
-                LocalTime startTime = latestRecord.getStartTime();
-                //计算新的间隔
-                Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
-                        + (currentTime.getMinute() - startTime.getMinute()) * 60
-                        + (currentTime.getSecond() - startTime.getSecond()));
-                //设置新的结束时间和持续时间 保存记录
-                latestRecord.setEndTime(currentTime).setDuration(duration);
-                timeCalculationMapper.updateById(latestRecord);
-            } else {
-                //如果不是连续的话 新增一个记录
-                TimeCalculation timeCalculation = new TimeCalculation();
-                timeCalculation
-                        .setUserId(screenshot.getUid())
-                        //根据截图种类设置行为代号
-                        .setActionType(screenshot.getPicType())
-                        .setDate(screenshot.getIndate().toLocalDate())
-                        //设置开始时间和结束时间都为当前时间
-                        .setStartTime(currentTime)
-                        .setEndTime(currentTime)
-                        //第一次的持续时间默认为最少单位1秒 不然我看一眼就成了0秒了
-                        .setDuration(1);
-                timeCalculationMapper.insert(timeCalculation);
-            }
-            /*之后可能还需要处理跨越一天的情况*/
-        } catch (NullPointerException e) {
-            //凡是有空指针说明缺少用户id或者时间数据
-            log.info("工作时长统计失败 缺少用户或时间数据");
-        }
-    }
-
     //判断是否是浏览器
     private String isBrowser(File pic) throws Exception {
 //        System.out.println("picrecongnizeFolder=="+browserFolder);
@@ -414,7 +501,6 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
                 File[] targetFile = subFolder.listFiles();
                 boolean isMatch = false;
                 for (File targetPic : targetFile) {
-//                    System.out.println("targetPic==" + targetPic.getAbsolutePath());
                     boolean matchPic = ImageReconizeUtil.isTemplateMatch(pic.getAbsolutePath(), targetPic.getAbsolutePath());
                     if (matchPic) {
                         isMatch = true;
@@ -466,11 +552,12 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
     public static boolean isDocument(List<String> textContents) {
         boolean find = false;
         for (int i = 0; i < textContents.size() && i <= 2; i++) {//出现在前三行
-            String text = textContents.get(i);
-            if (text.endsWith("Word")
-                    || text.endsWith("Excel")
-                    || text.endsWith("Power Point")
-                    || text.endsWith("Adobe Reader")) {
+            String text = textContents.get(i).trim();
+            if (text.contains("Word")
+                    || text.contains("Excel")
+                    || text.contains("Ecel")
+                    || text.contains("Power Point")
+                    || text.contains("Adobe Reader")) {
                 find = true;
                 break;
             }
@@ -485,7 +572,7 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
             if (!pic.exists()) {
                 System.err.println("文件不存在" + pic.getAbsolutePath());
             } else {
-                System.out.println("找到文件"  + pic.getAbsolutePath());
+                System.out.println("找到文件" + pic.getAbsolutePath());
             }
             BufferedImage img = ImageIO.read(pic);
             int width = img.getWidth();

+ 20 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TimeCalculationServiceImpl.java

@@ -2,11 +2,13 @@ package com.management.platform.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.entity.TimeCalculation;
+import com.management.platform.entity.TimeCalculationShow;
 import com.management.platform.mapper.TimeCalculationMapper;
+import com.management.platform.mapper.TimeCalculationShowMapper;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.TimeCalculationService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.stereotype.Service;
 
@@ -17,7 +19,10 @@ import java.time.LocalDate;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -32,9 +37,10 @@ public class TimeCalculationServiceImpl extends ServiceImpl<TimeCalculationMappe
 
     @Resource
     private UserMapper userMapper;
-
     @Resource
     private TimeCalculationMapper timeCalculationMapper;
+    @Resource
+    private TimeCalculationShowMapper timeCalculationShowMapper;
 
     //根据id获取用户名 日期 时间分布
     @Override
@@ -49,9 +55,10 @@ public class TimeCalculationServiceImpl extends ServiceImpl<TimeCalculationMappe
         //时间占比 预先定义好长度为10的数组再向里面添加
         Integer[] timeArray = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
         //把当天所有行为分别加在一起装进数组
-        for (TimeCalculation timeCalculation : timeCalculationMapper.selectList(new QueryWrapper<TimeCalculation>()
+        List<TimeCalculation> list = timeCalculationMapper.selectList(new QueryWrapper<TimeCalculation>()
                 .eq("user_id", userId)
-                .eq("date", todayDate))) {
+                .eq("date", todayDate));
+        for (TimeCalculation timeCalculation : list) {
             timeArray[timeCalculation.getActionType() + 1] += timeCalculation.getDuration();
         }
         resultMap.put("timeDistribution", timeArray);
@@ -133,20 +140,18 @@ public class TimeCalculationServiceImpl extends ServiceImpl<TimeCalculationMappe
         return httpRespMsg;
     }
 
-    //根据日期段获取本人的工作时间段
+    //修改后的计算时长方法 使用TimeCalculationShow
     @Override
     public HttpRespMsg getDuration(String startDate, String endDate, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             LocalDate start = LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
             LocalDate end = LocalDate.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-            //获取时间段内本人全部的工作记录 娱乐6 7 8不计入
-            Integer[] workType = {-1, 0, 1, 2, 3, 4, 5};
-            List<TimeCalculation> dataList = timeCalculationMapper.selectList(new QueryWrapper<TimeCalculation>()
-                    .eq("user_id", request.getHeader("Token"))
-                    .in("action_type", workType)
-                    .between("date", start, end)
-                    .orderByAsc("start_time"));
+            List<TimeCalculationShow> dataList = timeCalculationShowMapper.selectList(
+                    new QueryWrapper<TimeCalculationShow>()
+                            .eq("user_id", request.getHeader("Token"))
+                            .between("date", start, end)
+                            .orderByAsc("start_time"));
             //先把所有的日期搞到一个list里面
             ArrayList<String> dateList = new ArrayList<>();
             LocalDate currentDate = start;
@@ -164,7 +169,7 @@ public class TimeCalculationServiceImpl extends ServiceImpl<TimeCalculationMappe
                 dataMap.put("date", date);
                 List<Map<String, Object>> list = new ArrayList<>();
                 //遍历所有时间记录
-                for (TimeCalculation timeCalculation : dataList) {
+                for (TimeCalculationShow timeCalculation : dataList) {
                     //如果这一天就是我们需要的那天的话
                     if (timeCalculation.getDate().toString().equals(date)) {
                         Map<String, Object> map = new HashMap<>();
@@ -176,7 +181,7 @@ public class TimeCalculationServiceImpl extends ServiceImpl<TimeCalculationMappe
                         total += todayTime;
                         list.add(map);
                     }
-                    /*这个时间复杂度巨几把高的for循环可以用某种算法优化 至少计算过的应该排除才对*/
+                    /*后续可以用迭代器把重复数据删掉*/
                 }
                 dataMap.put("time", list);
                 //这里检查如果只需要一天记录的话 说明是pc端界面那个地方 那就再多计算一个当天总工作时间

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TimeCalculationShowServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.TimeCalculationShow;
+import com.management.platform.mapper.TimeCalculationShowMapper;
+import com.management.platform.service.TimeCalculationShowService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author 吴涛涛
+ * @since 2020-02-05
+ */
+@Service
+public class TimeCalculationShowServiceImpl extends ServiceImpl<TimeCalculationShowMapper, TimeCalculationShow> implements TimeCalculationShowService {
+
+}

+ 9 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CheckPicUtil.java

@@ -92,7 +92,7 @@ public class CheckPicUtil {
      */
     public static Map<String,Object>  generalPicTextContentMap (String path,String token) {
         // 请求url
-        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general";
+        String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic";
         try {
             // 本地文件路径
             String filePath = path;
@@ -109,12 +109,15 @@ public class CheckPicUtil {
             List<String> wordsList = new ArrayList<>();
             JSONObject object = JSONArray.parseObject(result);
             JSONArray resultArray = object.getJSONArray("words_result");
-            for (int i = 0; i < resultArray.size(); i++) {
-                JSONObject json  = resultArray.getJSONObject(i);
-                String words = (String)json.get("words");
-                System.out.println("words"+i+":"+words);
-                wordsList.add(words);
+            if (resultArray != null) {//超过上限会返回错误json数据,{"error_code":17,"error_msg":"Open api daily request limit reached"}
+                for (int i = 0; i < resultArray.size(); i++) {
+                    JSONObject json  = resultArray.getJSONObject(i);
+                    String words = (String)json.get("words");
+                    System.out.println("words"+i+":"+words);
+                    wordsList.add(words);
+                }
             }
+
             System.out.println(wordsList);
             Map<String,Object> map = new HashMap<>();
             map.put("wordsList",wordsList);

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CodeGenerator.java

@@ -204,7 +204,7 @@ public class CodeGenerator {
         //若想要生成的实体类继承某个Controller,则可打开下面注释。写上需要继承的Controller的位置即可
 //        strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
         //此处user是表名,多个英文逗号分割
-        strategy.setInclude("company");
+        strategy.setInclude("time_calculation");
 //        strategy.setExclude();//数据库表全生成
 //        strategy.setInclude(scanner("user").split(","));//表名,多个英文逗号分割
         strategy.setControllerMappingHyphenStyle(true);

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ImageCompare.java

@@ -83,7 +83,7 @@ public class ImageCompare {
         for (MatOfPoint matOfPoint : mat2_list)
         {
             Rect rect = Imgproc.boundingRect(matOfPoint);
-            if (rect.width >= 280 && rect.height >= 280) {
+            if ((rect.width >= 640 && rect.height >= 480) || (rect.width >= 480 && rect.height >= 640)) {
 //                System.out.println("位置==["+rect.x +","+ rect.y+"], 大小=" +rect.width+"x"+rect.height+", 包含点=" + matOfPoint.toList().size());
                 Imgproc.rectangle(mat_result1, rect.tl(), rect.br(), new Scalar(0, 0, 255),2);
                 Imgproc.rectangle(mat_result2, rect.tl(), rect.br(), new Scalar(0, 0, 255),2);

+ 13 - 29
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ImageReconizeUtil.java

@@ -5,21 +5,24 @@ import org.opencv.highgui.HighGui;
 import org.opencv.imgcodecs.Imgcodecs;
 import org.opencv.imgproc.Imgproc;
 
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
 import java.io.File;
+import java.io.IOException;
 
 import static java.lang.Math.E;
 import static org.opencv.imgproc.Imgproc.*;
 
 public class ImageReconizeUtil {
-    public static final double YUZHI = 1*Math.pow(0.1, 10);
+    public static final double YUZHI = 2*Math.pow(0.1, 10);
     static {
         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
         //注意程序运行的时候需要在VM option添加该行 指明opencv的dll文件所在路径
         //-Djava.library.path=$PROJECT_DIR$\opencv\x64
     }
     public static void main(String[] args) {
-        boolean match = isTemplateMatch("C:\\upload\\c6889ab6dea949a8a8d5d89fb677a421.jpg",
-                "C:\\picrecongnize\\browser\\360\\2.jpg");
+        boolean match = isTemplateMatch("C:\\Users\\seya\\Desktop\\my.jpg",
+                "C:\\picrecongnize\\develop\\idea_black.jpg");
 //        match = isTemplateMatch("C:\\Users\\seya\\Desktop\\chrome_gray.jpg",
 //                "C:\\\\picrecongnize\\\\Chrome\\\\4-125.jpg");
 //        match = isTemplateMatch("C:\\Users\\seya\\Desktop\\chrome_gray.jpg",
@@ -58,7 +61,13 @@ public class ImageReconizeUtil {
      */
     public static double templete(int method, String sourcePic, String targetPic) {
         // 1 获取待匹配图片
+//        System.out.println("sourcePic="+sourcePic+", targetPic="+targetPic);
         Mat templete=Imgcodecs.imread(sourcePic);
+        //先裁减,左上角1/4的截图,提高比对速度。
+        Rect rect = new Rect(0,0,templete.width()/4, templete.height()/4);
+        Mat subMat = new Mat(templete, rect);
+        subMat.copyTo(templete);
+
         //将rgb灰化处理
 //        Imgproc.cvtColor(templete, templete,Imgproc.COLOR_BGR2GRAY);
 //
@@ -79,35 +88,10 @@ public class ImageReconizeUtil {
             y = mmr.maxLoc.y;
             matchVal = mmr.maxVal;
         }
-        //if not match , resize the targetPic and try to match again!
-//        if (Math.abs(matchVal) > YUZHI) {
-//            System.out.println("第一次没匹配上, 尝试125%尺寸再次匹配~~");
-//            Mat demoResize = demo.clone();
-//            float scale=1.25f;
-//            float widthT=demo.width();
-//            float heightT=demo.height();
-//            Imgproc.resize(demo, demoResize, new Size(widthT*scale,heightT*scale));
-//            demo = demoResize;
-//            mmr = getLocResult(method, templete, demo);
-//            // 7 绘制匹配到的结果
-//            matchVal = 0;
-//            if (method==Imgproc.TM_SQDIFF_NORMED || method==Imgproc.TM_SQDIFF) {
-//                x = mmr.minLoc.x;
-//                y = mmr.minLoc.y;
-//                matchVal = mmr.minVal;
-//            } else {
-//                x = mmr.maxLoc.x;
-//                y = mmr.maxLoc.y;
-//                matchVal = mmr.maxVal;
-//            }
-//        }
+
         System.out.println("匹配度=="+matchVal);
         System.out.println("x="+x+", y=" + y);
         //我们匹配的图像在左上角,考虑到用户可能拖动窗口,但是不应该偏差很大。 这里增加判断标准:坐标处在左上方。
-        if (x > templete.width()/4 || y > templete.height()/4) {
-            System.out.println("坐标非第一象限");
-            return 1;
-        }
 
 //        if (Math.abs(matchVal) < YUZHI) {
 //            Imgproc.rectangle(templete,new Point(x,y),new Point(x+demo.cols(),y+demo.rows()),new Scalar( 0, 0, 255),2,Imgproc.LINE_AA);

+ 10 - 9
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeCalculationMapper.xml

@@ -4,23 +4,24 @@
 
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.management.platform.entity.TimeCalculation">
-        <id column="id" property="id"/>
-        <result column="user_id" property="userId"/>
-        <result column="action_type" property="actionType"/>
-        <result column="date" property="date"/>
-        <result column="start_time" property="startTime"/>
-        <result column="end_time" property="endTime"/>
-        <result column="duration" property="duration"/>
+        <id column="id" property="id" />
+        <result column="user_id" property="userId" />
+        <result column="action_type" property="actionType" />
+        <result column="date" property="date" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="duration" property="duration" />
+        <result column="pic_url" property="picUrl" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, user_id, action_type, date, start_time, end_time, duration
+        id, user_id, action_type, date, start_time, end_time, duration, pic_url
     </sql>
 
     <!--分页获取异常记录-->
     <select id="getDevianceList" resultType="java.util.Map">
-        SELECT a.start_time AS time, b.name, a.action_type AS type, a.date
+        SELECT a.start_time AS time, b.name, a.action_type AS type, a.date, a.pic_url AS picUrl
         FROM time_calculation AS a
         LEFT JOIN user AS b ON a.user_id = b.id
         WHERE 1=1

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeCalculationShowMapper.xml

@@ -0,0 +1,20 @@
+<?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.TimeCalculationShowMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.TimeCalculationShow">
+        <id column="id" property="id" />
+        <result column="user_id" property="userId" />
+        <result column="date" property="date" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="duration" property="duration" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, user_id, date, start_time, end_time, duration
+    </sql>
+
+</mapper>

+ 2 - 1
fhKeeper/formulahousekeeper/mywork/home.cpp

@@ -53,7 +53,8 @@ Home::Home(QWidget *parent) :
   qDebug() << "id=="<<id<<", phone="<<qs->value("name").toString();
   QString str = HOME_PAGE_URL + id;
   loadNavigate(str);
-
+  //首次登陆时立即截图
+    captureScreen();
 }
 
 

+ 4 - 0
fhKeeper/formulahousekeeper/mywork/mainwindow.cpp

@@ -16,6 +16,9 @@ MainWindow::MainWindow(QWidget *parent)
     m_setting = new QSettings("MyManager",QSettings::IniFormat,this);
     ui->setupUi(this);
     connect(ui->loginBtn,SIGNAL(clicked()),this,SLOT(login_in()));
+    ui->reg->setOpenExternalLinks(true);
+    ui->reg->setText("<a href=\"http://worktime.ttkuaiban.com\">暂无账号?快来点击注册企业账号");
+
 //    connect(ui->loginBtn, &QAction::triggered, this, &MainWindow::login_in);
     // 设置窗体标题
     setWindowTitle(tr("智能工时管家"));
@@ -73,6 +76,7 @@ void MainWindow::login_in(void){//登陆
 void MainWindow::login_out(void){//退出
 
 }
+
 MainWindow::~MainWindow()
 {
     delete ui;

+ 1 - 2
fhKeeper/formulahousekeeper/mywork/mainwindow.h

@@ -1,4 +1,4 @@
-#ifndef MAINWINDOW_H
+#ifndef MAINWINDOW_H
 #define MAINWINDOW_H
 #include "home.h"
 #include <QMainWindow>
@@ -19,7 +19,6 @@ public:
 public slots:                   //新增
     void login_in(void);	//新增
     void login_out(void);	//新增
-
 private:
     Ui::MainWindow *ui;
     QSettings *m_setting;

+ 13 - 0
fhKeeper/formulahousekeeper/mywork/mainwindow.ui

@@ -95,6 +95,19 @@
      <string>密码</string>
     </property>
    </widget>
+   <widget class="QLabel" name="reg">
+    <property name="geometry">
+     <rect>
+      <x>390</x>
+      <y>510</y>
+      <width>231</width>
+      <height>16</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>暂无账号?快来点击注册企业账号</string>
+    </property>
+   </widget>
   </widget>
   <widget class="QMenuBar" name="menubar">
    <property name="geometry">

+ 2 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue

@@ -16,7 +16,8 @@
                     <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit" :loading="logining">登录</el-button>
                 </el-form-item>
                 <div class="toRegister">
-                    <el-link type="primary" @click="jumpTo">立即注册</el-link>
+                    <el-link type="primary" style="margin-right:5px;" :underline="false"><a style="color:#409EFF;text-decoration:none" href="http://gsgj.ttkuaiban.com/download/WorkTime.exe" download="工时管家">客户端下载</a></el-link>
+                    <el-link type="primary" @click="jumpTo" :underline="false">立即注册</el-link>
                 </div>
             </el-form>
         </div>