Bläddra i källkod

优化修改,支持企业微信登录

seyason 3 år sedan
förälder
incheckning
6f66f83180
30 ändrade filer med 695 tillägg och 73 borttagningar
  1. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/qr_dingding.png
  2. 8 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/aop/AopLogConfiguration.java
  3. 1 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpenseSheetController.java
  4. 16 16
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectDocumentController.java
  5. 10 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  6. 7 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java
  7. 13 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WxCorpInfoController.java
  8. 16 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Report.java
  9. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java
  10. 4 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java
  11. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java
  12. 124 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  13. 61 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  14. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml
  15. 8 6
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  16. 2 0
      fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue
  17. 59 6
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  18. 8 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list.vue
  19. 8 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list_department.vue
  20. 8 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list_profession.vue
  21. 6 1
      fhKeeper/formulahousekeeper/timesheet_h5/package-lock.json
  22. 2 1
      fhKeeper/formulahousekeeper/timesheet_h5/package.json
  23. 33 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/assets/app.js
  24. 2 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/main.js
  25. 219 18
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue
  26. 4 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/index/index.vue
  27. 18 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/department_list.vue
  28. 18 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/index.vue
  29. 18 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/profession_list.vue
  30. 19 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/view/index.vue

BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/qr_dingding.png


+ 8 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/aop/AopLogConfiguration.java

@@ -38,10 +38,14 @@ public class AopLogConfiguration {
             return;
         }
         //打印请求内容
-        log.info("---------------请求内容---------------");
-        log.info("请求类方法:"+joinPoint.getSignature().getName());
-        log.info("请求类方法参数:"+ Arrays.toString(joinPoint.getArgs()));
-        log.info("---------------请求内容---------------");
+
+        String methodName = joinPoint.getSignature().getName();
+        if (!"loginAdmin".equals(methodName)) {
+            log.info("---------------请求内容---------------");
+            log.info("请求类方法:"+methodName);
+            log.info("请求类方法参数:"+ Arrays.toString(joinPoint.getArgs()));
+            log.info("---------------请求内容---------------");
+        }
     }
 
     /**

+ 1 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpenseSheetController.java

@@ -60,6 +60,7 @@ public class ExpenseSheetController {
             //普通员工只能看自己的
             sheet.setOwnerId(user.getId());
         }
+        sheet.setCompanyId(user.getCompanyId());
         return expenseSheetService.queryList(sheet, pageIndex, pageSize);
     }
 

+ 16 - 16
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectDocumentController.java

@@ -82,9 +82,9 @@ public class ProjectDocumentController {
         HttpRespMsg msg = new HttpRespMsg();
         User user = (User) userMapper.selectById(request.getHeader("Token"));
 
-        OpenOfficeService openOfficeService = new OpenOfficeService();
+//        OpenOfficeService openOfficeService = new OpenOfficeService();
 //        List<Part> partLists = partMapper.selectList(new QueryWrapper<Part>().eq("mould_id", userVO.getMouldId()));
-        openOfficeService.start();
+//        openOfficeService.start();
         ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
         for (MultipartFile file : files) {
             ProjectDocument record = new ProjectDocument();
@@ -129,20 +129,20 @@ public class ProjectDocumentController {
 //                        record.setUrl(url);
                         projectDocumentMapper.insert(record);
                         String path = uploadPath;
-                        if (OpenOfficeService.canTransferToPdf(suffix)) {
-                            //上传完,需要生成pdf
-                            String dFile1 = path + UUID.randomUUID().toString().replaceAll("-", "") + ".pdf";
-                            File newFile = new File(dFile1);
-                            if (!newFile.exists()) {
-                                openOfficeService.office2PDF(path + fileName, dFile1);
-                                PdfFile pdfFile = new PdfFile();
-                                pdfFile.setPdfUrl(pathPrefix + dFile1.substring(path.length()));
-                                pdfFile.setFileId(record.getId());
-                                pdfFile.setType(1);
-                                pdfFile.setSourceFileUrl(record.getUrl());
-                                pdfFileMapper.insert(pdfFile);
-                            }
-                        }
+//                        if (OpenOfficeService.canTransferToPdf(suffix)) {
+//                            //上传完,需要生成pdf
+//                            String dFile1 = path + UUID.randomUUID().toString().replaceAll("-", "") + ".pdf";
+//                            File newFile = new File(dFile1);
+//                            if (!newFile.exists()) {
+//                                openOfficeService.office2PDF(path + fileName, dFile1);
+//                                PdfFile pdfFile = new PdfFile();
+//                                pdfFile.setPdfUrl(pathPrefix + dFile1.substring(path.length()));
+//                                pdfFile.setFileId(record.getId());
+//                                pdfFile.setType(1);
+//                                pdfFile.setSourceFileUrl(record.getUrl());
+//                                pdfFileMapper.insert(pdfFile);
+//                            }
+//                        }
 
                         //生成原文件名称与服务器文件名称对应
                         msg.data = record;

+ 10 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -103,6 +103,8 @@ public class ReportController {
             report.setProfessionProgressList(list);
         }
     }
+
+
     /**
      * 新增或编辑报告
      * id 报告id 数组
@@ -126,7 +128,8 @@ public class ReportController {
                                   Integer[] progress,
                                   String[] targetUids,
                                   String[] professionProgress,
-                                  String[] stage
+                                  String[] stage,
+                                  String[] pics
                                     ) {
         List<Report> reportList = new ArrayList<>();
         String token = request.getHeader("Token");
@@ -242,6 +245,7 @@ public class ReportController {
                                         .setReportTimeType(reportTimeType[i])
                                         .setContent(content[i])
                                         .setState(0)
+                                        .setPicAdd(pics!=null?pics[i]:null)
                                         .setStage(stage != null && stage.length > 0 && !StringUtil.isEmpty(stage[i])?stage[i]:null)
                                         .setCreateDate(localStartDate)
                                         .setCreatorId(token);
@@ -292,6 +296,7 @@ public class ReportController {
                                             .setContent(content[i])
                                             .setStage(stage!=null && stage.length > 0  && !StringUtil.isEmpty(stage[i])?stage[i]:null)
                                             .setState(1)//代填,直接是审核通过状态
+                                            .setPicAdd(pics!=null?pics[i]:null)
                                             .setCreateDate(localStartDate)
                                             .setCreatorId(subsUser.getId());
                                     if (taskId != null && taskId[i] != null && taskId[i] != 0) {
@@ -351,6 +356,7 @@ public class ReportController {
                                 .setContent(content[i])
                                 .setStage(stage!=null && stage.length > 0  && !StringUtil.isEmpty(stage[i])?stage[i]:null)
                                 .setState(0)
+                                .setPicAdd(pics!=null?pics[i]:null)
                                 .setCreateDate(LocalDate.parse(createDate[i], DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                                 .setCreatorId(token);
                         if (taskId != null && taskId[i] != null && taskId[i] != 0) {
@@ -406,6 +412,7 @@ public class ReportController {
                                     .setContent(content[i])
                                     .setStage(stage!=null && stage.length > 0  && !StringUtil.isEmpty(stage[i])?stage[i]:null)
                                     .setState(1)//代填的就直接审核通过了
+                                    .setPicAdd(pics!=null?pics[i]:null)
                                     .setCreateDate(LocalDate.parse(createDate[i], DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                                     .setCreatorId(subsUser.getId());
                             if (taskId != null && taskId[i] != null && taskId[i] != 0) {
@@ -460,7 +467,8 @@ public class ReportController {
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
         }
-        return reportService.editReport(reportList, createDate.length > 0 ? createDate[0] : null, targetUserList, hourCost);
+
+        return reportService.editReport(reportList, createDate.length > 0 ? createDate[0] : null, targetUserList, hourCost, user.getCompanyId());
     }
 
     /**

+ 7 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java

@@ -76,10 +76,10 @@ public class WeiXinCorpController {
     public static String PRE_AUTH_CODE = null;
     public static long expireTime = 0L;
 
-    public Map<String, Item> corpTicketMap = new HashMap<String,Item>();
-    class Item {
-        String jsTicket = null;
-        LocalDateTime expireTime = null;
+    public static Map<String, Item> corpTicketMap = new HashMap<String,Item>();
+    public class Item {
+        public String jsTicket = null;
+        public LocalDateTime expireTime = null;
     }
 
     @Resource
@@ -98,13 +98,14 @@ public class WeiXinCorpController {
     UserService userService;
 
 
+
+
     //"获取企业微信jssdk初始化配置参数"
     @RequestMapping("/getCorpWXConfig")
-    @ResponseBody
     public HttpRespMsg getCorpWXConfig(String url, String token) {
         HttpRespMsg msg = new HttpRespMsg();
         try {
-            User user = userMapper.selectOne(new QueryWrapper<User>().eq("head_imgurl", token));
+            User user = userMapper.selectById(token);
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId()));
 
             Date now = new Date();

+ 13 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WxCorpInfoController.java

@@ -1,10 +1,14 @@
 package com.management.platform.controller;
 
 
+import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+
 /**
  * <p>
  *  前端控制器
@@ -17,5 +21,14 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping("/wx-corp-info")
 public class WxCorpInfoController {
 
+    @Resource
+    WxCorpInfoService wxCorpInfoService;
+
+    @RequestMapping("/testDownload")
+    public HttpRespMsg testDownload() {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = wxCorpInfoService.testDownloadFile();
+        return msg;
+    }
 }
 

+ 16 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Report.java

@@ -20,7 +20,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-10-18
+ * @since 2021-10-28
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -154,6 +154,21 @@ public class Report extends Model<Report> {
     private String stage;
 
 
+    /**
+     * 图片的数组字符串
+     */
+    @TableField("pic_str")
+    private String picStr;
+
+
+    @TableField(exist = false)
+    private String picAdd;
+
+    /**
+     * 传给客户端的图片数组
+     */
+    @TableField(exist = false)
+    private List<String> pics;
     @Override
     protected Serializable pkVal() {
         return this.id;

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

@@ -25,7 +25,7 @@ public interface ReportService extends IService<Report> {
 
     HttpRespMsg getReport(String date, HttpServletRequest request);
 
-    HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost);
+    HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId);
 
     HttpRespMsg deleteReport(String userId, String date);
 

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

@@ -14,4 +14,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 public interface WxCorpInfoService extends IService<WxCorpInfo> {
 
     public void sendWXCorpMsg(WxCorpInfo corpInfo, String corpUserid, String msg);
+
+    public String downloadFile(WxCorpInfo corpInfo, String mediaId);
+
+    public String testDownloadFile();
 }

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java

@@ -106,7 +106,7 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
     public HttpRespMsg queryList(ExpenseSheet sheet, Integer pageIndex, Integer pageSize) {
         QueryWrapper<ExpenseSheet> queryWrapper = new QueryWrapper<ExpenseSheet>();
         HttpRespMsg httpRespMsg = new HttpRespMsg();
-        queryWrapper.orderByDesc("id");
+        queryWrapper.eq("company_id", sheet.getCompanyId()).orderByDesc("id");
 
         if (!StringUtils.isEmpty(sheet.getCode())) {
             queryWrapper.eq("code", sheet.getCode());

+ 124 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -1,7 +1,10 @@
 package com.management.platform.service.impl;
 
+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.management.platform.controller.WeiXinCorpController;
 import com.management.platform.entity.*;
 import com.management.platform.entity.vo.DepartmentVO;
 import com.management.platform.entity.vo.UserMonthWork;
@@ -19,7 +22,10 @@ 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.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -51,6 +57,8 @@ import java.util.stream.Collectors;
  */
 @Service
 public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {
+//    @Resource
+//    AsyncTaskExecutor asyncTaskExecutor;//注入线程池对象
 
     @Value("${wx.template_report_pass}")
     public String TEMPLATE_REPORT_PASS;
@@ -273,6 +281,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                 list.add(report);
                                 total = total.add((BigDecimal) report.get("cost"));
                             }
+
                         }
                         map.put("data", list);
                         map.put("cost", total);
@@ -310,6 +319,23 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     }
                 }
             }
+            //设置照片
+            for (Map map : nameList) {
+                List<Map<String, Object>> reportList = (List<Map<String, Object>>)map.get("data");
+                for (Map<String, Object> report : reportList) {
+                    String picStr = (String)report.get("picStr");
+                    if (picStr != null) {
+                        JSONArray array = JSONArray.parseArray(picStr.replaceAll("@", ","));
+                        List<String> picList = new ArrayList<>();
+                        for (int i=0;i<array.size(); i++) {
+                            String string = array.getString(i);
+                            string = "/upload/" + string + ".jpg";
+                            picList.add(string);
+                        }
+                        report.put("pics", picList);
+                    }
+                }
+            }
             httpRespMsg.data = nameList;
         } catch (NullPointerException e) {
             e.printStackTrace();
@@ -365,6 +391,15 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 if (company.getPackageProject() == 1) {
                     r.setStages(stagesMapper.getProjectStages(r.getProjectId()));
                 }
+                //处理图片
+                if (!StringUtils.isEmpty(r.getPicStr())) {
+                    JSONArray array = JSONArray.parseArray(r.getPicStr().replaceAll("@", ","));
+                    List<String> list = new ArrayList<>();
+                    for (int i=0;i<array.size(); i++) {
+                        list.add("/upload/"+array.getString(i)+".jpg");
+                    }
+                    r.setPics(list);
+                }
             });
             resultMap.put("report", reports);
             //顺便再获取一下可分配时间
@@ -401,11 +436,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     //新增或编辑报告
     @Override
-    public HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost) {
+    public HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         List<Integer> idList = new ArrayList<>();
 
-        Integer companyId = userMapper.selectById(reportList.get(0).getCreatorId()).getCompanyId();
         TimeType timeType = timeTypeMapper.selectById(companyId);
         double totalWorkTime = 0;
         for (Report report : reportList) {
@@ -496,9 +530,43 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
         }
 
+        //异步下载图片
+
+        loadPicFromCorpWXServer(companyId, reportList);
+
         return httpRespMsg;
     }
 
+
+    private void loadPicFromCorpWXServer(Integer companyId, List<Report> reportList) {
+        List<Report> batchUpdateList = new ArrayList<>();
+        if (wxCorpInfoMapper.selectCount(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId)) > 0) {
+            WxCorpInfo corpInfo = wxCorpInfoMapper.selectList(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId)).get(0);
+            for (Report report : reportList) {
+                if (!StringUtils.isEmpty(report.getPicAdd()) && !report.getPicAdd().equals("@")) {
+                    report.setPicStr(report.getPicStr());
+                    Report item = new Report();
+                    item.setId(report.getId());
+                    item.setPicStr(report.getPicAdd());
+                    batchUpdateList.add(item);
+
+                    String s = item.getPicStr().replaceAll("@", ",");
+                    JSONArray array = JSONArray.parseArray(s);
+                    for (int i = 0; i < array.size(); i++) {
+                        String string = array.getString(i);
+                        wxCorpInfoService.downloadFile(corpInfo, string);
+                    }
+                }
+            }
+            if (batchUpdateList.size() > 0) {
+                updateBatchById(batchUpdateList);
+
+            }
+        }
+
+    }
+
+
     //删除报告
     @Override
     public HttpRespMsg deleteReport(String userId, String date) {
@@ -598,6 +666,24 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     map2.put("state", list2.get(0).get("state"));
                 }
             }
+
+            //设置照片显示
+            for (Map map : nameList) {
+                List<Map<String, Object>> reportList = (List<Map<String, Object>>)map.get("data");
+                for (Map<String, Object> report : reportList) {
+                    String picStr = (String)report.get("picStr");
+                    if (picStr != null) {
+                        JSONArray array = JSONArray.parseArray(picStr.replaceAll("@", ","));
+                        List<String> picList = new ArrayList<>();
+                        for (int i=0;i<array.size(); i++) {
+                            String string = array.getString(i);
+                            string = "/upload/" + string + ".jpg";
+                            picList.add(string);
+                        }
+                        report.put("pics", picList);
+                    }
+                }
+            }
             httpRespMsg.data = nameList;
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
@@ -1116,6 +1202,23 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     map2.put("state", list2.get(0).get("state"));
                 }
             }
+            //设置照片
+            for (Map map : nameList) {
+                List<Map<String, Object>> reportList = (List<Map<String, Object>>)map.get("data");
+                for (Map<String, Object> report : reportList) {
+                    String picStr = (String)report.get("picStr");
+                    if (picStr != null) {
+                        JSONArray array = JSONArray.parseArray(picStr.replaceAll("@", ","));
+                        List<String> picList = new ArrayList<>();
+                        for (int i=0;i<array.size(); i++) {
+                            String string = array.getString(i);
+                            string = "/upload/" + string + ".jpg";
+                            picList.add(string);
+                        }
+                        report.put("pics", picList);
+                    }
+                }
+            }
             httpRespMsg.data = nameList;
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
@@ -1187,6 +1290,24 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     map2.put("state", list2.get(0).get("state"));
                 }
             }
+
+            //设置照片
+            for (Map map : nameList) {
+                List<Map<String, Object>> reportList = (List<Map<String, Object>>)map.get("data");
+                for (Map<String, Object> report : reportList) {
+                    String picStr = (String)report.get("picStr");
+                    if (picStr != null) {
+                        JSONArray array = JSONArray.parseArray(picStr.replaceAll("@", ","));
+                        List<String> picList = new ArrayList<>();
+                        for (int i=0;i<array.size(); i++) {
+                            String string = array.getString(i);
+                            string = "/upload/" + string + ".jpg";
+                            picList.add(string);
+                        }
+                        report.put("pics", picList);
+                    }
+                }
+            }
             httpRespMsg.data = nameList;
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
@@ -1326,7 +1447,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             dataList.add(dataItem);
         }
         //生成excel文件导出
-        String fileName = "人员每日工时统计_"+month+"月"+System.currentTimeMillis();
+        String fileName = "人员每日工时统计_"+month.split("-")[1]+"月"+System.currentTimeMillis();
         String resp = ExcelUtil.exportGeneralExcelByTitleAndList(fileName , dataList, path);
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         httpRespMsg.data = resp;

+ 61 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -17,6 +17,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.time.LocalDateTime;
 
 /**
@@ -31,11 +33,16 @@ import java.time.LocalDateTime;
 @Slf4j
 public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpInfo> implements WxCorpInfoService {
     public static String URL_SEND_WXCORP_MSG = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
-
+    //获取临时素材url
+    public static String URL_GET_MEDIA = "https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
     @Value("${suitId}")
     private String suitId;
     @Value("${suitSecret}")
     private String suitSecret;
+
+    @Value(value = "${upload.path}")
+    private String path;
+
     @Autowired
     RestTemplate restTemplate;
 
@@ -87,6 +94,59 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
 
     }
 
+    @Override
+    public String downloadFile(WxCorpInfo corpInfo, String mediaId) {
+        try {
+            String corpAccessToken = getCorpAccessToken(corpInfo);
+            String url = URL_GET_MEDIA.replaceAll("ACCESS_TOKEN", corpAccessToken).replaceAll("MEDIA_ID", mediaId);
+            HttpHeaders headers = new HttpHeaders();
+            ResponseEntity<byte[]> entity = restTemplate.exchange(url, HttpMethod.GET,new HttpEntity<>(headers), byte[].class);
+            byte[] body = entity.getBody();
+            HttpHeaders respHeader = entity.getHeaders();
+            System.out.println("================开始处理文件==========body size="+body.length);
+            System.out.println(respHeader.getContentType());
+            System.out.println(respHeader.getContentLength());
+            System.out.println(respHeader.getContentDisposition().getName());
+            ContentDisposition contentDisposition = respHeader.getContentDisposition();
+            System.out.println("文件名=="+contentDisposition.getFilename());
+            //写入文件
+            String fileName = mediaId+".jpg";
+            FileOutputStream fileOutputStream = new FileOutputStream(new File(path+fileName));
+            fileOutputStream.write(body);
+            fileOutputStream.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    @Override
+    public String testDownloadFile() {
+        try {
+            String url = "http://worktime.ttkuaiban.com/upload/bc4df504fa724e6cab69872e2c1cfb35.png";
+            HttpHeaders headers = new HttpHeaders();
+            ResponseEntity<byte[]> entity = restTemplate.exchange(url, HttpMethod.GET,new HttpEntity<>(headers), byte[].class);
+            byte[] body = entity.getBody();
+            HttpHeaders respHeader = entity.getHeaders();
+            System.out.println(respHeader.getContentType());
+            System.out.println(respHeader.getContentLength());
+            System.out.println(respHeader.getContentDisposition().getName());
+            ContentDisposition contentDisposition = respHeader.getContentDisposition();
+            System.out.println("文件名=="+contentDisposition.getFilename());
+            //写入文件
+            String fileName = "downloadFile.jpg";
+            FileOutputStream fileOutputStream = new FileOutputStream(new File(path+fileName));
+            fileOutputStream.write(body);
+            fileOutputStream.close();
+
+            return contentDisposition.getFilename();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
 
     //获取第三方应用临时凭证
     private String getSuiteAccessToken() {

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml

@@ -114,7 +114,7 @@ referer:
     - www.ttkuaiban.com
     - mobworktime.ttkuaiban.com
     - worktime.ttkuaiban.com
-excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/error,/testClient,/corpWXAuth
+excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/error,/testClient,/corpWXAuth,/wx-corp-info/*
 
 #企业微信相关参数
 suitId: ww4e237fd6abb635af

+ 8 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml

@@ -23,18 +23,19 @@
         <result column="progress" property="progress" />
         <result column="department_audit_state" property="departmentAuditState" />
         <result column="stage" property="stage" />
+        <result column="pic_str" property="picStr" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, creator_id, project_id, create_date, working_time, content, state, create_time, time_type, cost, start_time, end_time, report_time_type, sub_project_id, task_id, is_overtime, progress, department_audit_state, stage
+        id, creator_id, project_id, create_date, working_time, content, state, create_time, time_type, cost, start_time, end_time, report_time_type, sub_project_id, task_id, is_overtime, progress, department_audit_state, stage, pic_str
     </sql>
     <!--根据日期获取全部报告信息-->
     <select id="getAllReportByDate" resultType="java.util.Map">
         SELECT c.name, b.project_name AS project, a.working_time AS duration, a.content, a.create_time AS time, a.create_date as createDate,
         a.state, a.time_type as timeType, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime,a.progress as progress,
-        a.department_audit_state as departmentAuditState
+        a.department_audit_state as departmentAuditState, a.pic_str as picStr
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN user AS c ON a.creator_id=c.id
@@ -61,7 +62,7 @@
         SELECT a.id, a.project_id as projectId,b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, b.incharger_id as inchargerId,
         a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime,a.progress as progress,
-        a.department_audit_state as departmentAuditState, a.stage
+        a.department_audit_state as departmentAuditState, a.stage, a.pic_str as picStr
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         left join sub_project as d on d.id = a.sub_project_id
@@ -80,7 +81,7 @@
         a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, b.incharger_id as inchargerId,
         a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime,a.progress as progress,
-        a.department_audit_state as departmentAuditState, a.stage
+        a.department_audit_state as departmentAuditState, a.stage, a.pic_str as picStr
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         left join sub_project as d on d.id = a.sub_project_id
@@ -101,7 +102,8 @@
         SELECT a.id, a.project_id as projectId, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType,
         a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, b.incharger_id as inchargerId,
-        a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime,a.progress as progress, a.stage
+        a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName,
+        a.is_overtime as isOvertime,a.progress as progress, a.stage, a.pic_str as picStr
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         left join sub_project as d on d.id = a.sub_project_id
@@ -123,7 +125,7 @@
         a.end_time as endTime, d.name as subProjectName,a.task_id as taskId, task.name as taskName,
         b.incharger_id as inchargerId,
         a.is_overtime as isOvertime,a.progress as progress,
-        a.department_audit_state as departmentAuditState, a.stage
+        a.department_audit_state as departmentAuditState, a.stage, a.pic_str as picStr
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         left join sub_project as d on d.id = a.sub_project_id

+ 2 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue

@@ -60,6 +60,7 @@
                         {{sysUserName}}
                     </span>
                     <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item disabled ><span style="font-size:12px;"><i class="el-icon-view" ></i>{{roleArray[user.role]}}</span></el-dropdown-item>
                         <el-dropdown-item @click.native="reset">修改密码</el-dropdown-item>
                         <!-- <el-dropdown-item @click.native="editInfoOpen">修改信息</el-dropdown-item> -->
                         <el-dropdown-item divided @click.native="logout">退出登录</el-dropdown-item>
@@ -164,6 +165,7 @@
     export default {
         data() {
             return {
+                roleArray:["普通员工","超级管理员", "系统管理员", "公司高层","人事管理员", "项目管理员","公司领导"],
                 helpImg: '../assets/image/userHead.png',
                 user: sessionStorage.getItem("user"),
                 sysName: "工时管家",

+ 59 - 6
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -78,8 +78,8 @@
                         </span>
                     </div>
                     <!--普通员工,含项目经理 -->
-                    <div class="report_title" v-if="(user.role==0||user.role==5) && user.manageDeptId == 0"><span>日报列表</span>
-                    <span style="float:right;" v-if="(user.role==0||user.role==5) && user.manageDeptId == 0">
+                    <div class="report_title" v-if="(user.role==0||user.role==3||user.role==5) && user.manageDeptId == 0"><span>日报列表</span>
+                    <span style="float:right;" v-if="(user.role==0||user.role==3||user.role==5) && user.manageDeptId == 0">
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="isSubstitude=false;fillInReport(-1,0)">填写日报</el-link>
                             <el-link type="primary" v-if="user.leader" 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>
@@ -156,6 +156,14 @@
                                             
                                             <p>事项:<span v-html="item2.content"></span></p>
                                             
+                                            <!--照片的显示 -->
+                                            <p v-if="item2.pics != null && item2.pics.length > 0"> 
+                                                <el-image v-for="(pic, index) in item2.pics" :key="index"
+                                                    style="width: 100px; height: 100px; margin-right:10px;"
+                                                    :src="pic" 
+                                                    :preview-src-list="item2.pics">
+                                                </el-image>
+                                            </p>
                                         </el-card>
                                     </el-timeline-item>
                                 </el-timeline>
@@ -266,6 +274,8 @@
                             :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
                             <i class="fa fa-trash" style="color: red;;font-size:18px;"></i>
                         </el-link>
+                        <el-link type="primary" v-if="workForm.domains[index].state == 0 || workForm.domains[index].state == 2"
+                             :underline="false" style="margin-left:5px;" @click="copyProject(index)">复制</el-link>
                     </el-form-item>
 
                     <el-form-item v-if="reportTimeType.type == 3" label="用时占比" :prop="'domains.' + index + '.'+timeFields[reportTimeType.type]"
@@ -296,6 +306,14 @@
                         <el-input v-model="domain.content" type="textarea" :rows="4" placeholder="请填写工作事项" clearable
                          :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"></el-input>
                     </el-form-item>
+                    <!--照片的显示 -->
+                    <p v-if="domain.pics != null && domain.pics.length > 0" style="text-align:center;"> 
+                        <el-image v-for="(pic, index) in domain.pics" :key="index"
+                            style="width: 100px; height: 100px; margin-right:10px;"
+                            :src="pic" 
+                            :preview-src-list="domain.pics">
+                        </el-image>
+                    </p>
                     <el-divider v-if="workForm.domains.length>1" style="margin-bottom:10px;"></el-divider>
                 </div>
                 <el-link v-if="showAddMore"  :disabled="!canEdit" type="primary" :underline="false" @click="addDomain" style="margin-left:40px">添加更多</el-link>
@@ -533,6 +551,40 @@
             };
         },
         methods: {
+            //复制项目
+            copyProject(index) {
+                var leftProgress = 10;
+                if (this.reportTimeType.type == 3) {
+                    //计算已经待分配工时比例
+                    let array = this.workForm.domains;
+                    let totalProgress = 0;
+                    for (var i=0;i<array.length; i++) {
+                        totalProgress += array[i].progress;
+                    }
+                    if (totalProgress < 100) {
+                        leftProgress = 100 - totalProgress;
+                    }
+                }
+                var newIndex = index+1;
+                var itemDomain = {
+                        projectId: this.workForm.domains[index].projectId,
+                        workingTime: this.reportTimeType.type == 3?(leftProgress*this.reportTimeType.allday/100).toFixed(1):"",
+                        content: "",
+                        progress:leftProgress,
+                        state:2,//2-表示待提交
+                };
+                this.workForm.domains.splice(newIndex, 0,itemDomain);
+                
+                if (this.reportTimeType.type == 0) {
+                    //全天上下午模式下,检测时间段数量,达到2个,不能再加了
+                    var length = this.workForm.domains.length;
+                    if (length == 2) {
+                        this.showAddMore = false;
+                    }
+                }
+
+                this.selectProject(itemDomain, newIndex);
+            },
             //导出员工每日填报工时数
             exportMembWorkHours() {
                 this.http.post('/report/exportUserDailyWorkTime',{ 
@@ -540,8 +592,8 @@
                     },
                     res => {
                         if (res.code == "ok") {
-                            var url = '/upload/'+res.data;
-                            this.downloadByA("人员每日工时统计.xlxs", url);
+                            var url = res.data;
+                            this.downloadByA("人员每日工时统计.xls", url);
                         } 
                     },
                     error => {
@@ -567,7 +619,7 @@
                     res => {
                         if (res.code == "ok") {
                             this.monthWorkData = res.data.list;
-                            console.log('获取到数据:'+this.monthWorkData[0].name+', daytime='+this.reportTimeType.allday);
+                            // console.log('获取到数据:'+this.monthWorkData[0].name+', daytime='+this.reportTimeType.allday);
                             this.$forceUpdate();
                         } 
                     },
@@ -1514,7 +1566,8 @@
                                     progress:list.report[i].progress,
                                     professionProgress: list.report[i].professionProgressList,
                                     stages:list.report[i].stages,
-                                    stage:list.report[i].stage
+                                    stage:list.report[i].stage,
+                                    pics: list.report[i].pics,
                                 })
                                 if (list.report[i].state >= 2) {
                                     this.canEdit = true;

+ 8 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list.vue

@@ -58,6 +58,14 @@
                                 </p>
                                 <p v-if="user.role>=1&&user.role<=3">成本:{{item.cost}}元</p>
                                 <p>事项:<span v-html="item.content"></span></p>
+                                <!--照片的显示 -->
+                                <p v-if="item.pics != null && item.pics.length > 0"> 
+                                    <el-image v-for="(pic, index) in item.pics" :key="index"
+                                        style="width: 100px; height: 100px; margin-right:10px;"
+                                        :src="pic" 
+                                        :preview-src-list="item.pics">
+                                    </el-image>
+                                </p>
                             </el-card>
                         </el-timeline-item>
                     </el-timeline>

+ 8 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list_department.vue

@@ -51,6 +51,14 @@
                                 </p>
                                 <p v-if="user.role>=1&&user.role<=3">成本:{{item.cost}}元</p>
                                 <p>事项:<span v-html="item.content"></span></p>
+                                <!--照片的显示 -->
+                                <p v-if="item.pics != null && item.pics.length > 0"> 
+                                    <el-image v-for="(pic, index) in item.pics" :key="index"
+                                        style="width: 100px; height: 100px; margin-right:10px;"
+                                        :src="pic" 
+                                        :preview-src-list="item.pics">
+                                    </el-image>
+                                </p>
                             </el-card>
                         </el-timeline-item>
                     </el-timeline>

+ 8 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list_profession.vue

@@ -57,6 +57,14 @@
                                 </p>
                                 <p v-if="user.role>=1&&user.role<=3">成本:{{item.cost}}元</p>
                                 <p>事项:<span v-html="item.content"></span></p>
+                                <!--照片的显示 -->
+                                <p v-if="item.pics != null && item.pics.length > 0"> 
+                                    <el-image v-for="(pic, index) in item.pics" :key="index"
+                                        style="width: 100px; height: 100px; margin-right:10px;"
+                                        :src="pic" 
+                                        :preview-src-list="item.pics">
+                                    </el-image>
+                                </p>
                             </el-card>
                         </el-timeline-item>
                     </el-timeline>

+ 6 - 1
fhKeeper/formulahousekeeper/timesheet_h5/package-lock.json

@@ -12037,7 +12037,7 @@
         },
         "supports-color": {
           "version": "7.2.0",
-          "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1622293579301&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
+          "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1618847145907&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
           "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
           "dev": true,
           "optional": true,
@@ -12809,6 +12809,11 @@
       "integrity": "sha1-f4RzvIOd/YdgituV1+sHUhFXikI=",
       "dev": true
     },
+    "weixin-js-sdk": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npm.taobao.org/weixin-js-sdk/download/weixin-js-sdk-1.6.0.tgz",
+      "integrity": "sha1-/1BITYEYzhII8RJIz0ocCDFXdRQ="
+    },
     "which": {
       "version": "1.3.1",
       "resolved": "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz",

+ 2 - 1
fhKeeper/formulahousekeeper/timesheet_h5/package.json

@@ -19,7 +19,8 @@
     "echarts": "^4.9.0",
     "style-loader": "^1.3.0",
     "vue": "^2.6.12",
-    "vuex-persistedstate": "^2.7.1"
+    "vuex-persistedstate": "^2.7.1",
+    "weixin-js-sdk": "^1.6.0"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "^3.12.1",

+ 33 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/assets/app.js

@@ -0,0 +1,33 @@
+export function  initWxConfig(vm){
+    var url="/api" + "/wxcorp/getCorpWXConfig";
+    var curUrl=location.href.split("#")[0];
+    var user = JSON.parse(localStorage.userInfo);
+    var params="url="+curUrl+"&token="+user.id;
+    
+    
+    vm.$ajax.post(url,params).then(res=>{
+        var data=res.data;
+        wx.config({ 
+          beta: true,
+          debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+          appId: data.appid, // 必填,公众号的唯一标识 
+          timestamp: data.timestamp, // 必填,生成签名的时间戳 
+          nonceStr: data.noncestr, // 必填,生成签名的随机串 
+          signature: data.signature, // 必填,签名,见附录1 
+          jsApiList: [
+              'chooseImage',
+              'previewImage',
+              'uploadImage',
+              'downloadImage',
+              'previewFile',
+              'getLocation',
+         ] 
+        });
+        wx.error(function (res) {
+            console.log("调用微信jsapi返回的状态:"+res.errMsg);
+        });
+    }).catch(function(error) {
+        //vm.errorToast(error,1000);
+        console.info(error);
+    })
+}

+ 2 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/main.js

@@ -29,6 +29,8 @@ axios.defaults.baseURL="http://localhost:10010"
 Vue.prototype.$axios = $axios;
 
 Vue.mixin(mixin);
+// import wx from 'weixin-js-sdk'
+// Vue.prototype.$wx = wx
 
 Vue.config.productionTip = false;
 

+ 219 - 18
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -17,10 +17,16 @@
             <!-- <van-cell title="待分配时长" :value="report.time + 'h'" size="large"></van-cell> -->
 
             <div class="form_domains" v-for="(item,index) in form.domains" :key="item.id">
-                <van-tag v-if="index == 0 && canEdit" 
-                :disabled="!canEdit" @click="addNewPro" 
-                class="form_addNew" icon="plus" type="primary" >+ 新增项目</van-tag>
-                <van-icon v-if="index>0&&canEdit" class="form_del" name="delete" @click="delPro(index)" />
+                <div style="float:right;margin-top:10px;margin-right:10px;">
+                <van-tag v-if="canEdit&&item.projectName.length>0" color="#fff"
+                @click="copyProject(index)" style="border: 1px solid #20a0ff;padding:5px;"
+                 icon="plus" type="default" ><span style="color:#666;padding: 0 5px;">复制项目</span></van-tag>
+                
+                <van-tag v-if="index>0&&canEdit" color="#fff" 
+                @click="delPro(index)" style="border: 1px solid #ff0000;padding:5px;margin-left:10px;"
+                 icon="plus" type="default" ><span style="color:#666;padding: 0 5px;">删除项目</span></van-tag>
+                </div>
+                <!-- <van-icon v-if="index>0&&canEdit" class="form_del" name="delete" @click="delPro(index)" /> -->
 
                 <van-cell-group :title="'项目' + (index+1)">
                     <van-field  readonly  name="projectId" clickable :value="item.projectName" label="投入项目" placeholder="请选择投入项目" @click="clickPicker(index)"
@@ -104,6 +110,7 @@
                     <van-field class="form_input" :disabled = "!canEdit"
                     v-model="item.content" name="content" type="textarea" label="工作事项" placeholder="请输入工作事项" 
                     rows="3" autosize  />
+                    
                     <!-- 单选按钮 -->
                     <!-- <van-radio-group v-model="isOvertime" direction="horizontal" class="overtime">
                         <van-radio name="0">不加班</van-radio>
@@ -111,27 +118,59 @@
                     </van-radio-group> -->
                     <div class="overtime">
                         <van-checkbox :disabled="!canEdit" v-model="item.isOvertime">加班</van-checkbox>
+                        <van-tag style="position:absolute;right:10px;" v-if="isCorpWX&&canEdit" type="primary" size="large" @click="takePhoto(index)">拍照上传</van-tag>
                     </div>
+                    <div style="padding:5px;text-align:center;" v-if="!isIOSystem">
+                        <span v-for="(p, index) in item.pics"  :key="p" style="margin-right:15px;">
+                        <img  :src="p" style="width:100px; height:100px;" @click="showLargeImg(item.pics, index)"/>
+                        </span>
+                    </div>
+                    <div style="padding:5px;text-align:center;" v-if="isIOSystem">
+                        
+                        <span v-for="(p, index) in item.iospics"  :key="p" style="margin-right:15px;">
+                        <img  :src="p" style="width:100px; height:100px;" @click="showLargeImg(item.iospics, index)"/>
+                        </span>
+                    </div>
+                    <van-popup v-model="imgShow" position="bottom" closeable >
+                        <van-swipe class="my-swipe"  indicator-color="white">
+                        <van-swipe-item v-for="(picItem, index) in tmpPics" :key="index">
+                            <img :src="picItem" style="width:100%;" />
+                        </van-swipe-item>
+                        </van-swipe>
+                    </van-popup>
                 </van-cell-group>
+                
             </div>
-            <div class="form_btn" style="margin: 16px;">
-                <van-button v-if="canEdit" round block type="info" native-type="submit"> 提交 </van-button>
-                <p v-if="canEdit&&form.domains.length>0 && form.domains[0].id != null" round block type="default" style="padding-top:30px;font-size:15px;color:#999;margin:0 auto;text-align:center;" @click="deleteReport"> 删除 </p>
+            <div style="text-align:center;" >
+            <van-tag v-if="canEdit" size="large" style="text-align:center;margin:10px;padding:12px;margin-bottom:120px;border: 1px solid #20a0ff;"
+                :disabled="!canEdit" @click="addNewPro" 
+                icon="plus" color="#ffffff" ><span style="color:#999;text-align:center;padding: 0 50px;"> + 新增项目  </span></van-tag>
+            </div>  
+            <div class="form_btn" style="position:fixed; bottom:0px;width:100%;">
+                <van-button v-if="canEdit" block type="info" native-type="submit"> 提交 </van-button>
+                
+                <p v-if="canEdit&&form.domains.length>0 && form.domains[0].id != null" block type="default" 
+                    style="padding-top:30px;font-size:15px;color:#666;margin:0 auto;text-align:center;padding-bottom:10px;background:#ffffff;" @click="deleteReport"> 删除 </p>
             </div>
         </van-form>
-        <div style="padding:15px;">
-            <van-button  v-if="canCancel" round block type="default" @click="cancel"> 撤销 </van-button>
+        <div style="position:fixed; bottom:0px;width:100%;">
+            <van-button  v-if="canCancel" block type="default" @click="cancel"> 撤销 </van-button>
         </div>
         
         <div class="form_tip" v-if="!canEdit && !canCancel"> 已审核无法修改 </div> 
     </div>
 </template>
-
+<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
 <script>
+    import wx from 'weixin-js-sdk'
+    // Vue.prototype.$wx = wx
     export default {
         data() {
             return {
-
+                isIOSystem:false,
+                imgShow: false,
+                isCorpWX:false,
+                isWX: false,
                 showPickerTask:false,
                 canCancel:false,
                 canEdit:false,
@@ -165,6 +204,9 @@
                         workingTime: "",
                         content: "",
                         state: 2,
+                        // pics:["https://worktime.ttkuaiban.com/upload/bc4df504fa724e6cab69872e2c1cfb35.png",
+                        // "https://worktime.ttkuaiban.com/upload/bc4df504fa724e6cab69872e2c1cfb35.png",
+                        // "https://worktime.ttkuaiban.com/upload/bc4df504fa724e6cab69872e2c1cfb35.png",]
                     }],
                 },
                 rules: {
@@ -176,13 +218,102 @@
                 loading: false,
                 finished: false,
                 // isOvertime: false
+                tmpPics:[],
             };
         },
 
         created() {
+
         },
 
         methods: {
+            isIOS(){
+                var u = navigator.userAgent;
+                var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
+                return isiOS;
+            },
+            
+            showLargeImg(item, index) {
+                this.imgShow = true;
+                this.tmpPics = item;
+            },
+            //拍照上传
+            takePhoto(index) {
+                var that = this;
+                wx.chooseImage({
+                    count: 3, // 默认9
+                    sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
+                    sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有
+                    defaultCameraMode: "batch", //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
+                    isSaveToAlbum: 0, //整型值,0表示拍照时不保存到系统相册,1表示自动保存,默认值是1
+                    success: function (res) {
+                        var localIds = res.localIds; // 返回选定照片的本地ID列表,
+                                // andriod中localId可以作为img标签的src属性显示图片;
+                                // iOS应当使用 getLocalImgData 获取图片base64数据,从而用于img标签的显示(在img标签内使用 wx.chooseImage 的 localid 显示可能会不成功)
+                        
+                        if (that.isIOSystem) {
+                            var retArray = [];
+                            for (var i=0;i<localIds.length; i++) {
+                                wx.getLocalImgData({
+                                    localId: localIds[i], // 图片的localID
+                                    success: function (res) {
+                                        var localData = res.localData; // localData是图片的base64数据,可以用img标签显示
+                                        retArray.push(localData);
+                                    }
+                                });
+                            }
+                            that.form.domains[index].iospics = retArray;
+                            that.form.domains[index].pics = localIds; 
+                        } else {
+                            that.form.domains[index].pics = localIds; 
+                            that.$forceUpdate();   
+                        }
+                        var serverIdList = [];
+                        //立即就上传到企业微信服务器
+                        for (var i=0;i<localIds.length; i++) {
+                            wx.uploadImage({
+                                localId: localIds[i], // 需要上传的图片的本地ID,由chooseImage接口获得
+                                isShowProgressTips: 1, // 默认为1,显示进度提示
+                                success: function (res) {
+                                    var serverId = res.serverId; // 返回图片的服务器端ID
+                                    serverIdList.push(serverId);
+                                }
+                            });
+                        }
+                        that.form.domains[index].serverPics = serverIdList;
+                    }
+                });
+            },
+            copyProject(index) {
+                var leftProgress = 10;
+                if (this.reportTimeType.type == 3) {
+                    //计算已经待分配工时比例
+                    let array = this.form.domains;
+                    let totalProgress = 0;
+                    for (var i=0;i<array.length; i++) {
+                        totalProgress += array[i].progress;
+                    }
+                    if (totalProgress < 100) {
+                        leftProgress = 100 - totalProgress;
+                    }
+                }
+                var newIndex = index+1;
+                var pName = "";
+                if (this.form.domains[index].projectId != '') {
+                    pName = this.project.filter(p=>p.id == this.form.domains[index].projectId)[0].projectName;
+                }
+                var itemDomain = {
+                    id: null,
+                    projectId: this.form.domains[index].projectId,
+                    projectName: pName,
+                    workingTime: this.reportTimeType.type==3?(leftProgress*this.reportTimeType.allday/100).toFixed(1):"",
+                    progress:leftProgress,
+                    content: "",
+                    state: 2,
+                    isOvertime:false,
+                };
+                this.form.domains.splice(newIndex, 0,itemDomain);
+            },
             //删除日报
             deleteReport() {
                 this.$dialog.confirm({
@@ -414,6 +545,8 @@
                                     taskId: list[i].taskId,
                                     taskName:tname,
                                     professionProgress:list[i].professionProgressList,
+                                    pics: list[i].pics,
+                                    iospics:list[i].pics,
                                 })
                                 if (list[i].state >= 2) {
                                     this.canEdit = true;
@@ -650,6 +783,14 @@
                     } else {
                         formData.append("professionProgress", "[]");
                     }
+                    //图片的处理,只处理当前通过手机拍摄的新的照片
+                    if (this.form.domains[i].serverPics!= null && this.form.domains[i].serverPics.length > 0) {
+                        let m = JSON.stringify(this.form.domains[i].serverPics);
+                        m = m.replace(/,/g,"@");//replaceAll(',','@');企业微信不兼容replaceAll
+                        formData.append("pics", m);
+                    } else {
+                        formData.append("pics", "@");
+                    }
                 }
                 this.$axios.post("/report/editReport", formData)
                 .then(res => {
@@ -663,9 +804,50 @@
                     }
                 }).catch(err=> {toast.clear();});
             },
+            //初始化参数
+            initWxConfig() {
+                var curUrl=location.href.split("#")[0];
+                
+                this.$axios.post("/wxcorp/getCorpWXConfig", {url: curUrl, token: this.user.id})
+                        .then(res => {
+                            if(res.code == "ok") {
+                                var data=res.data;
+                                wx.config({ 
+                                beta: true,
+                                debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+                                appId: data.appid, // 必填,公众号的唯一标识 
+                                timestamp: data.timestamp, // 必填,生成签名的时间戳 
+                                nonceStr: data.noncestr, // 必填,生成签名的随机串 
+                                signature: data.sign, // 必填,签名,见附录1 
+                                jsApiList: [
+                                    'chooseImage',
+                                    'previewImage',
+                                    'uploadImage',
+                                    'downloadImage',
+                                    'previewFile',
+                                    'getLocation',
+                                ] 
+                                });
+                                wx.ready(function(){
+                                    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
+                                    console.log('企业微信初始化执行成功了。 ');
+                                });
+                            } else {
+                                this.$toast.fail('获取失败');
+                            }
+                        }).catch(err=> {this.$toast.fail('发生异常'+err);console.log(err)});
+                
+            }
         },
         
         mounted() {
+            var ua = navigator.userAgent.toLowerCase();
+            this.isIOSystem = this.isIOS();
+            if (ua.indexOf("wxwork") > 0) {
+                this.isCorpWX = true;
+            } else if (ua.indexOf("micromessenger") > 0) {
+                this.isWX = true;
+            }
             //获取传递过来的日期
             var passDate = this.$route.query.date;
             if (passDate != null) {
@@ -675,31 +857,50 @@
             this.getProject();
             this.getReport();
             this.getTimeType();
-
+            //初始化微信js-sdk参数
+            if (this.isCorpWX) {
+                this.initWxConfig();
+            }
         }
     };
 </script>
 
 <style lang="less" scope>
+.my-swipe .van-swipe-item {
+  color: #fff;
+  font-size: 20px;
+  line-height: 150px;
+  text-align: center;
+  background-color: #39a9ed;
+}
+
     .login_form {
         margin-top: 46px;
     }
 
     .form_domains {
         position: relative;
-        .form_addNew {
+        .form_copy {
             position: absolute;
-            right: 15px;
+            right: 85px;
             top: 10px;
         }
-
+        .form_addNew {
+            text-align: center;
+            margin:10px;
+        }
         .form_del {
-            color: #ff0000;
-            font-size: 22px;
             position: absolute;
-            right: 15px;
+            right: 10px;
             top: 10px;
         }
+        // .form_del {
+        //     color: #ff0000;
+        //     font-size: 22px;
+        //     position: absolute;
+        //     right: 15px;
+        //     top: 10px;
+        // }
     }
 
     .form_tip {

+ 4 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/index/index.vue

@@ -11,7 +11,10 @@
             :to="item.url">
             </van-grid-item>
         </van-grid>
-        <div class="tip">
+        <div class="tip"  v-if="isCorpWX">
+            工时报表统计等更多功能,请从PC端企业微信进入
+        </div>
+        <div class="tip"  v-if="!isCorpWX">
             体验报表统计等更多功能,尽在PC端<br>
             网页用户访问http://worktime.ttkuaiban.com,钉钉用户直接从钉钉PC端进入工时管家
         </div>

+ 18 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/department_list.vue

@@ -24,12 +24,23 @@
                         <div class="project_title" v-if="item1.taskId != null" >任务:{{item1.taskName}}</div>
                         <div class="project_time">时长:{{item1.time}}h <span class="one_span" v-if="item1.isOvertime === 1">加班</span></div>
                         <div class="project_content">事项:<span v-html="item1.content"></span></div>
-                        <van-divider />
+                        <div style="padding:5px;text-align:center;" v-if="item1.pics != null && item1.pics.length > 0">
+                            <span v-for="(p, index) in item1.pics"  :key="p" style="margin-right:10px;">
+                            <img  :src="p" style="width:80px; height:80px;" @click="showLargeImg(item1.pics, index)"/>
+                            </span>
+                        </div>
                     </div>
                     <div class="form_btn" slot="footer">
                         <van-button size="small" type="info" @click="approve(item.id, item)">通过</van-button>
                         <van-button size="small" type="danger" @click="deny(item.id,1, item)">驳回</van-button>
                     </div>
+                    <van-popup v-model="imgShow" position="bottom" closeable >
+                        <van-swipe class="my-swipe"  indicator-color="white">
+                        <van-swipe-item v-for="(picItem, index) in tmpPics" :key="index">
+                            <img :src="picItem" style="width:100%;" />
+                        </van-swipe-item>
+                        </van-swipe>
+                    </van-popup>
                 </van-panel>
             </van-skeleton>
         </div>
@@ -40,6 +51,8 @@
     export default {
         data() {
             return {
+                tmpPics:[],
+                imgShow: false,
                 user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
@@ -52,6 +65,10 @@
         created() {
         },
         methods: {
+            showLargeImg(item, index) {
+                this.imgShow = true;
+                this.tmpPics = item;
+            },
             // 返回
             back() {
                 history.back();

+ 18 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/index.vue

@@ -30,13 +30,24 @@
                         <div class="project_title" v-if="item1.taskId != null" >任务:{{item1.taskName}}</div>
                         <div class="project_time">时长:{{item1.time}}h <span class="one_span" v-if="item1.isOvertime === 1">加班</span></div>
                         <div class="project_content">事项:<span v-html="item1.content"></span></div>
-                        <van-divider />
+                        <div style="padding:5px;text-align:center;" v-if="item1.pics != null && item1.pics.length > 0">
+                            <span v-for="(p, index) in item1.pics"  :key="p" style="margin-right:10px;">
+                            <img  :src="p" style="width:80px; height:80px;" @click="showLargeImg(item1.pics, index)"/>
+                            </span>
+                        </div>
                     </div>
                     <div class="form_btn" slot="footer">
                         <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 0" size="small" type="info" @click="approve(item.id, item)">通过</van-button>
                         <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 0" size="small" type="danger" @click="deny(item.id,1, item)">驳回</van-button>
                         <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 1" size="small" type="danger" @click="deny(item.id,2, item)">撤销</van-button>
                     </div>
+                    <van-popup v-model="imgShow" position="bottom" closeable >
+                        <van-swipe class="my-swipe"  indicator-color="white">
+                        <van-swipe-item v-for="(picItem, index) in tmpPics" :key="index">
+                            <img :src="picItem" style="width:100%;" />
+                        </van-swipe-item>
+                        </van-swipe>
+                    </van-popup>
                 </van-panel>
             </van-skeleton>
         </div>
@@ -47,6 +58,8 @@
     export default {
         data() {
             return {
+                tmpPics:[],
+                imgShow: false,
                 user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
@@ -59,6 +72,10 @@
         created() {
         },
         methods: {
+            showLargeImg(item, index) {
+                this.imgShow = true;
+                this.tmpPics = item;
+            },
             // 返回
             back() {
                 history.back();

+ 18 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/profession_list.vue

@@ -25,12 +25,23 @@
                         <div class="project_title" v-if="item1.taskId != null" >任务:{{item1.taskName}}</div>
                         <div class="project_time">时长:{{item1.time}}h <span class="one_span" v-if="item1.isOvertime === 1">加班</span></div>
                         <div class="project_content">事项:<span v-html="item1.content"></span></div>
-                        <van-divider />
+                        <div style="padding:5px;text-align:center;" v-if="item1.pics != null && item1.pics.length > 0">
+                            <span v-for="(p, index) in item1.pics"  :key="p" style="margin-right:10px;">
+                            <img  :src="p" style="width:80px; height:80px;" @click="showLargeImg(item1.pics, index)"/>
+                            </span>
+                        </div>
                     </div>
                     <div class="form_btn" slot="footer">
                         <van-button size="small" type="info" @click="approve(item.id, item)">通过</van-button>
                         <van-button size="small" type="danger" @click="deny(item.id,1, item)">驳回</van-button>
                     </div>
+                    <van-popup v-model="imgShow" position="bottom" closeable >
+                        <van-swipe class="my-swipe"  indicator-color="white">
+                        <van-swipe-item v-for="(picItem, index) in tmpPics" :key="index">
+                            <img :src="picItem" style="width:100%;" />
+                        </van-swipe-item>
+                        </van-swipe>
+                    </van-popup>
                 </van-panel>
             </van-skeleton>
         </div>
@@ -41,6 +52,8 @@
     export default {
         data() {
             return {
+                tmpPics:[],
+                imgShow: false,
                 user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
@@ -53,6 +66,10 @@
         created() {
         },
         methods: {
+            showLargeImg(item, index) {
+                this.imgShow = true;
+                this.tmpPics = item;
+            },
             // 返回
             back() {
                 history.back();

+ 19 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/view/index.vue

@@ -35,8 +35,20 @@
                             <div class="button" v-if="item1.isOvertime == 1">加班</div>
                         </div>
                         <div class="project_content">事项:<span v-html="item1.content"></span></div>
+                        <div style="padding:5px;text-align:center;" v-if="item1.pics != null && item1.pics.length > 0">
+                            <span v-for="(p, index) in item1.pics"  :key="p" style="margin-right:10px;">
+                            <img  :src="p" style="width:80px; height:80px;" @click="showLargeImg(item1.pics, index)"/>
+                            </span>
+                        </div>
                         <van-divider />
                     </div>
+                    <van-popup v-model="imgShow" position="bottom" closeable >
+                        <van-swipe class="my-swipe"  indicator-color="white">
+                        <van-swipe-item v-for="(picItem, index) in tmpPics" :key="index">
+                            <img :src="picItem" style="width:100%;" />
+                        </van-swipe-item>
+                        </van-swipe>
+                    </van-popup>
                 </van-panel>
             </van-skeleton>
         </div>
@@ -47,6 +59,8 @@
     export default {
         data() {
             return {
+                tmpPics:[],
+                imgShow: false,
                 hasWaiting: false,
                 state: 0,
                 user: JSON.parse(localStorage.userInfo),
@@ -63,6 +77,11 @@
         created() {
         },
         methods: {
+            showLargeImg(item, index) {
+                this.imgShow = true;
+                this.tmpPics = item;
+            },
+
             // 返回
             back() {
                 history.back();
@@ -111,7 +130,6 @@
                     if(res.code == "ok") {
                         toast.clear();
                         this.report = res.data;
-                        console.log(this.report);
                         //计算状态
                         for (var i=0;i<this.report.length; i++) {
                             var item = this.report[i];