瀏覽代碼

成本管理的日报填报费用计算修改

seyason 3 年之前
父節點
當前提交
d489399eed
共有 14 個文件被更改,包括 293 次插入130 次删除
  1. 1 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DingDingController.java
  2. 8 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostSettingController.java
  3. 55 28
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  4. 11 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserYearleaveSettingController.java
  5. 5 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectCurrentcost.java
  6. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/LeaveQuotaNum.java
  7. 3 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java
  8. 67 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java
  9. 4 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  10. 34 31
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  11. 4 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  12. 11 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  13. 66 50
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  14. 8 2
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

+ 1 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DingDingController.java

@@ -363,9 +363,7 @@ public class DingDingController {
     @RequestMapping("/testCorpLeaveType")
     public HttpRespMsg testCorpLeaveType(String leaveCode, Integer companyId, String userIds, long offset) {
         CompanyDingding companyDingding = companyDingdingService.getOne(new QueryWrapper<CompanyDingding>().eq("company_id", companyId));
-
-        dingDingService.getLeaveTypeList(leaveCode, companyId, userIds, offset);
-        return new HttpRespMsg();
+        return dingDingService.getLeaveTypeList(leaveCode, companyId, userIds, offset);
     }
 
     @RequestMapping("/testSendBusTripLink")

+ 8 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostSettingController.java

@@ -127,7 +127,14 @@ public class ProjectBasecostSettingController {
     }
 
 
-
+    @RequestMapping("/getReportBasecostList")
+    public HttpRespMsg getReportBasecostList(Integer companyId) {
+        //返回公司的项目工时预警的成本项列表
+        HttpRespMsg msg = new HttpRespMsg();
+        List<ProjectBasecostSetting> timeBasecostList = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", companyId).eq("alarm_type", 1));
+        msg.data = timeBasecostList;
+        return msg;
+    }
 
 }
 

+ 55 - 28
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -9,6 +9,7 @@ import com.management.platform.entity.*;
 import com.management.platform.entity.vo.SysRichFunction;
 import com.management.platform.entity.vo.WorktimeItem;
 import com.management.platform.mapper.*;
+import com.management.platform.service.CompanyService;
 import com.management.platform.service.ReportService;
 import com.management.platform.service.UserSalaryService;
 import com.management.platform.service.UserService;
@@ -56,6 +57,8 @@ public class ReportController {
     @Resource
     private UserService userService;
     @Resource
+    private CompanyService companyService;
+    @Resource
     private DepartmentMapper departmentMapper;
     @Resource
     private ProjectCurrentcostMapper projectCurrentcostMapper;
@@ -164,6 +167,7 @@ public class ReportController {
         List<Report> reportList = new ArrayList<>();
         String token = request.getHeader("Token");
         User user = userService.getById(token);
+        Company company = companyService.getById(user.getCompanyId());
         //检查当前人员账号是否停用
         if (user.getIsActive() == 0) {
             HttpRespMsg msg = new HttpRespMsg();
@@ -751,40 +755,63 @@ public class ReportController {
             }
         }
 
-
-        //检查成本是否超过预算
-        List<ProjectBasecostSetting> projectBasecostSettings = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", user.getCompanyId()).eq("alarm_type", 1));
-        if (projectBasecostSettings.size() > 0) {
-            List<Integer> collect = projectBasecostSettings.stream().map(ProjectBasecostSetting::getId).collect(Collectors.toList());
-            List<Integer> projectIds = reportList.stream().map(Report::getProjectId).distinct().collect(Collectors.toList());
+        //只有项目管理专业版才要检查成本预算
+        if (company.getPackageProject() == 1) {
+            //检查成本是否超过预算
+            List<ProjectBasecostSetting> projectBasecostSettings = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", user.getCompanyId()).eq("alarm_type", 1));
+            if (projectBasecostSettings.size() > 0) {
+                List<Integer> collect = projectBasecostSettings.stream().map(ProjectBasecostSetting::getId).collect(Collectors.toList());
+                List<Integer> projectIds = reportList.stream().map(Report::getProjectId).distinct().collect(Collectors.toList());
 //            //获取当前项目的当前成本基线值
-            List<ProjectCurrentcost> projectCurrentcosts = projectCurrentcostMapper.selectList(new QueryWrapper<ProjectCurrentcost>().in("base_id", collect).in("project_id", projectIds));
+                List<ProjectCurrentcost> projectCurrentcosts = projectCurrentcostMapper.selectList(new QueryWrapper<ProjectCurrentcost>().in("base_id", collect).in("project_id", projectIds));
 
-            List<Map<String, Object>> costList = reportMapper.getProjectCost(user.getCompanyId(), projectIds);
-            for (Report report : reportList) {
-                if (report.getBasecostId() != null && report.getBasecostId() != 0) {
-                    Optional<ProjectCurrentcost> first = projectCurrentcosts.stream().filter(cur -> cur.getProjectId().equals(report.getProjectId()) && cur.getBaseId().equals(report.getBasecostId())).findFirst();
+                List<Map<String, Object>> costList = reportMapper.getProjectFillCost(user.getCompanyId(), projectIds);
+                //计算本次填报的每个项目每个成本项合计的成本总额
+                for (Report report : reportList) {
+                    //匹配当前项目的当前成本项已填的成本金额
+                    System.out.println("本次reportCost=="+report.getCost());
+                    Optional<ProjectCurrentcost> first = projectCurrentcosts.stream().filter(p -> p.getProjectId().equals(report.getProjectId()) && p.getBaseId().equals(report.getBasecostId())).findFirst();
                     if (first.isPresent()) {
-                        //匹配上了当前成本基线项的设置
-                        double max = first.get().getBaseAmount();
-                        double realCost = 0;
-                        //匹配当前项目的当前成本项已填的成本金额
-                        for (Map<String, Object> mapItem : costList) {
-                            int pid = (int)mapItem.get("projectId");
-                            int baseId = (int) mapItem.get("basecostId");
-                            if (pid == report.getProjectId() && baseId == report.getBasecostId()) {
-                                realCost = ((BigDecimal)mapItem.get("cost")).doubleValue();
-                                break;
-                            }
+                        ProjectCurrentcost currentcost = first.get();
+                        BigDecimal curFillCost = currentcost.getCurFillCost();
+                        if (curFillCost == null) {
+                            currentcost.setCurFillCost(report.getCost());
+                        } else {
+                            //累加
+                            currentcost.setCurFillCost(curFillCost.add(report.getCost()));
                         }
-                        if (max > 0 && realCost > max) {
-                            //超支了,不能提交
-                            String name = projectList.stream().filter(p->p.getId().equals(report.getProjectId())).findFirst().get().getProjectName();
-                            HttpRespMsg msg = new HttpRespMsg();
-                            msg.setError("项目["+name+"]的["+first.get().getBaseName()+"]预算不足,请联系管理人员下拨预算");
-                            return msg;
+                    }
+                }
+                //计算本次项目和成本项的金额是否超支
+                for (ProjectCurrentcost item : projectCurrentcosts) {
+                    Map<String, Object> findOldCost = null;
+                    for (Map<String, Object> mapItem : costList) {
+                        int pid = (int)mapItem.get("projectId");
+                        int baseId = (int) mapItem.get("basecostId");
+                        if (pid == item.getProjectId() && baseId == item.getBaseId()) {
+                            findOldCost = mapItem;
+                            break;
                         }
                     }
+                    BigDecimal baseAmount = new BigDecimal(item.getBaseAmount());
+                    BigDecimal leftCost = new BigDecimal(0);
+                    //减去已经发生的记录
+                    if (findOldCost != null) {
+                        leftCost = baseAmount.subtract((BigDecimal)findOldCost.get("cost"));
+                    } else {
+                        leftCost = baseAmount;
+                    }
+                    String name = projectList.stream().filter(p->p.getId().equals(item.getProjectId())).findFirst().get().getProjectName();
+                    System.out.println("项目["+name+"]的["+item.getBaseName()+"]总预算="+baseAmount+",剩余="+leftCost);
+                    System.out.println("本次项目预算填报的="+item.getCurFillCost());
+                    //移动端可能没有选择预算来源的地方
+                    if (item.getCurFillCost() != null && item.getCurFillCost().compareTo(leftCost) > 0) {
+                        //超支了,不能填报
+//                    String name = projectList.stream().filter(p->p.getId().equals(item.getProjectId())).findFirst().get().getProjectName();
+                        HttpRespMsg msg = new HttpRespMsg();
+                        msg.setError("项目["+name+"]的["+item.getBaseName()+"]预算不足,请联系管理人员下拨预算");
+                        return msg;
+                    }
                 }
             }
         }

+ 11 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserYearleaveSettingController.java

@@ -1,14 +1,17 @@
 package com.management.platform.controller;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.dingtalk.api.DefaultDingTalkClient;
 import com.dingtalk.api.DingTalkClient;
 import com.dingtalk.api.request.OapiAttendanceVacationTypeListRequest;
 import com.dingtalk.api.response.OapiAttendanceVacationTypeListResponse;
+import com.management.platform.entity.CompanyDingding;
 import com.management.platform.entity.User;
 import com.management.platform.entity.UserYearleaveSetting;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.mapper.UserYearleaveSettingMapper;
+import com.management.platform.service.CompanyDingdingService;
 import com.management.platform.service.DingDingService;
 import com.management.platform.service.UserYearleaveSettingService;
 import com.management.platform.util.HttpRespMsg;
@@ -40,6 +43,8 @@ public class UserYearleaveSettingController {
     private UserYearleaveSettingMapper userYearleaveSettingMapper;
     @Resource
     private DingDingService dingDingService;
+    @Resource
+    private CompanyDingdingService companyDingdingService;
 
     @Resource
     private HttpServletRequest request;
@@ -87,5 +92,11 @@ public class UserYearleaveSettingController {
 //    public HttpRespMsg getDingDingList(Integer companyId) {
 //        return dingDingService.getLeaveTypeList(companyId);
 //    }
+
+    @RequestMapping("/getDingDingLeaveQt")
+    public HttpRespMsg getDingDingLeaveQt(String leaveCode, Integer companyId, String userIds, long offset) {
+        CompanyDingding companyDingding = companyDingdingService.getOne(new QueryWrapper<CompanyDingding>().eq("company_id", companyId));
+        return dingDingService.getLeaveTypeList(leaveCode, companyId, userIds, offset);
+    }
 }
 

+ 5 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectCurrentcost.java

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.extension.activerecord.Model;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.math.BigDecimal;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -57,6 +59,9 @@ public class ProjectCurrentcost extends Model<ProjectCurrentcost> {
     @TableField(exist = false)
     private Double realCost;
 
+    @TableField(exist = false)
+    private BigDecimal curFillCost;
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/LeaveQuotaNum.java

@@ -0,0 +1,16 @@
+package com.management.platform.entity.vo;
+
+public class LeaveQuotaNum {
+    public String userDingdingId;
+    public String name;//员工姓名
+    public String userId;
+    public String startTime; //假期有效开始时间
+    public String endTime;//假期有效截止时间
+    public String quotaInHours;//以小时计算的总额度
+    public String quotaInDays; //以天计算的总额度;
+    public String usedInHours;//已使用小时
+    public String usedInDays;//已使用天数
+    public String leftInHours; //剩余额度
+    public String leftInDays;//剩余额度
+
+}

+ 3 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -108,5 +108,8 @@ public interface ReportMapper extends BaseMapper<Report> {
 
     List<Map<String, Object>> getProjectCost(Integer companyId, List<Integer> projectIds);
 
+    //获取项目填报的成本,包括已审核和待审核的
+    List<Map<String, Object>> getProjectFillCost(Integer companyId, List<Integer> projectIds);
+
     List<Map<String, Object>> getOneProjectBaseCost(Integer projectId);
 }

+ 67 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java

@@ -12,16 +12,15 @@ import com.dingtalk.api.DefaultDingTalkClient;
 import com.dingtalk.api.DingTalkClient;
 import com.dingtalk.api.request.*;
 import com.dingtalk.api.response.*;
+import com.google.gson.JsonObject;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
+import com.management.platform.entity.vo.LeaveQuotaNum;
 import com.management.platform.entity.vo.LeaveTypeVO;
 import com.management.platform.entity.vo.UserVO;
 import com.management.platform.mapper.*;
 import com.management.platform.service.*;
-import com.management.platform.util.ColorUtil;
-import com.management.platform.util.DateTimeUtil;
-import com.management.platform.util.HttpRespMsg;
-import com.management.platform.util.SnowFlake;
+import com.management.platform.util.*;
 import com.taobao.api.ApiException;
 import com.taobao.api.internal.util.StringUtils;
 import org.slf4j.Logger;
@@ -33,6 +32,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
@@ -1352,7 +1353,7 @@ public class DingDingServiceImpl implements DingDingService {
         DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/vacation/type/list");
         OapiAttendanceVacationTypeListRequest req = new OapiAttendanceVacationTypeListRequest();
         List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).eq("role_name", "超级管理员"));
-        String oaManagerDid =userList.get(0).getDingdingUserid();
+        String oaManagerDid = "2221645448842951";//userList.get(0).getDingdingUserid();
         if (leaveCode == null) {
             req.setOpUserid(oaManagerDid);
             req.setVacationSource("all");
@@ -1373,22 +1374,40 @@ public class DingDingServiceImpl implements DingDingService {
                 }
                 resultMap.put("leaveTypeList", typeList);
                 leaveCode = typeList.get(0).leaveCode;
+                System.out.println("本次请求的LeaveCode: "+leaveCode);
+                reqQuotaList(companyId, dingding, leaveCode, oaManagerDid, userIds, offset, resultMap);
             } catch (ApiException e) {
                 e.printStackTrace();
             }
+        } else {
+            reqQuotaList(companyId, dingding, leaveCode, oaManagerDid, userIds, offset, resultMap);
         }
+        msg.data = resultMap;
+        return msg;
+    }
+
+    private void reqQuotaList(Integer companyId, CompanyDingding dingding,
+                                             String leaveCode, String oaManagerDid, String userIds, long offset, HashMap resultMap) {
 
         //再调用查看假期余额的接口
-        client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/list");
+        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/list");
         OapiAttendanceVacationQuotaListRequest quoataReq = new OapiAttendanceVacationQuotaListRequest();
         quoataReq.setLeaveCode(leaveCode);
         quoataReq.setOpUserid(oaManagerDid);
+        List<User> userList = null;
         if (StringUtils.isEmpty(userIds)) {
             //获取全部员工,离职的不看
             userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).eq("is_active", 1));
             String collect = userList.stream().map(User::getDingdingUserid).collect(Collectors.joining(","));
             userIds = collect;
+        } else {
+            List<String> strings = ListUtil.convertLongIdsArrayToList(userIds);
+            userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).in("dingding_userid", strings));
+        }
+        if (userList.size() > 10) {
+            userList = userList.subList(0, 10);
         }
+        System.out.println("请求的userIds: "+userIds);
         quoataReq.setUserids(userIds);
 
         quoataReq.setOffset(offset);
@@ -1400,14 +1419,51 @@ public class DingDingServiceImpl implements DingDingService {
             e.printStackTrace();
         }
         System.out.println(quotaListResponse.getBody());
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         JSONObject json = JSONObject.parseObject(quotaListResponse.getBody());
+        DecimalFormat df = new DecimalFormat("#0.0");
         if (json.getInteger("errcode") == 0) {
-
-        } else {
-            msg.setError(json.getString("errmsg"));
+            JSONObject result = json.getJSONObject("result");
+            resultMap.put("hasMore", result.getBooleanValue("has_more"));
+            JSONArray leaveQuotas = result.getJSONArray("leave_quotas");
+            if (leaveQuotas != null) {
+                List<LeaveQuotaNum> quotaNumList = new ArrayList<>();
+                for (int i=0;i<leaveQuotas.size(); i++) {
+                    JSONObject jsonObject = leaveQuotas.getJSONObject(i);
+                    String userDDid = jsonObject.getString("userid");
+                    LeaveQuotaNum quotaNum = new LeaveQuotaNum();
+                    quotaNum.userDingdingId = userDDid;
+                    User user = userList.stream().filter(u -> u.getDingdingUserid().equals(userDDid)).findFirst().get();
+                    quotaNum.userId = user.getId();
+                    quotaNum.name = user.getName();
+                    Date startDate = new Date(jsonObject.getLongValue("start_time"));
+                    quotaNum.startTime = sdf.format(startDate);
+                    Date endDate = new Date(jsonObject.getLongValue("end_time"));
+                    quotaNum.endTime = sdf.format(endDate);
+                    Integer quota_num_per_hour = jsonObject.getInteger("quota_num_per_hour");
+                    if (quota_num_per_hour != null) {
+                        //按小时为单位的情况
+                        quotaNum.quotaInHours = df.format(quota_num_per_hour*1.0/100);
+                        Integer used_num_per_hour = jsonObject.getInteger("used_num_per_hour");
+                        quotaNum.usedInHours = df.format(used_num_per_hour*1.0/100);
+                        //计算剩余
+                        quotaNum.leftInHours = df.format((quota_num_per_hour - used_num_per_hour)*1.0/100);
+                    } else {
+                        //按天单位的情况
+                        Integer quota_num_per_day = jsonObject.getInteger("quota_num_per_day");
+                        quotaNum.quotaInDays = df.format(quota_num_per_day*1.0/100);
+                        Integer used_num_per_day = jsonObject.getInteger("used_num_per_day");
+                        quotaNum.usedInDays = df.format(used_num_per_day*1.0/100);
+                        //计算剩余
+                        quotaNum.leftInDays = df.format((quota_num_per_day - used_num_per_day)*1.0/100);
+                    }
+                    quotaNumList.add(quotaNum);
+                }
+                resultMap.put("quotaNumList", quotaNumList);
+            } else {
+                resultMap.put("quotaNumList", new ArrayList<>());
+            }
         }
-
-        return msg;
     }
 
     public void activateSuite(String authCorpid, String tmpAuthCode) throws ApiException {

+ 4 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -907,8 +907,10 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Override
     public HttpRespMsg adjustBase(String baseCostData, Project project, String remark, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
-        if (project.getContractAmount() == 0) {
-            msg.setError("项目金额不能为0");
+        Integer id = project.getId();
+        Double contractAmount = projectMapper.selectById(id).getContractAmount();
+        if (contractAmount == 0) {
+            msg.setError("请先设置项目合同金额");
             return msg;
         }
         //计算项目总成本

+ 34 - 31
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -879,7 +879,6 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 //增加填报人所属部门
                 map2.put("departmentName", list2.get(0).get("departmentName"));
             }
-
             //设置照片显示
             for (Map map : nameList) {
                 List<Map<String, Object>> reportList = (List<Map<String, Object>>)map.get("data");
@@ -907,41 +906,45 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             if (timeType.getShowCorpwxCardtime() == 1) {
                 //企业微信的情况
                 QueryWrapper<UserCorpwxTime> userCorpwxTimeQueryWrapper = new QueryWrapper<>();
-                for (Map map : nameList) {
-                    String name = (String)map.get("name");
-                    String dateStr = (String)map.get("dateStr");
-                    userCorpwxTimeQueryWrapper.or(wrapper->wrapper.eq("name", name).eq("create_date", dateStr));
-                }
-                List<UserCorpwxTime> timeList = userCorpwxTimeMapper.selectList(userCorpwxTimeQueryWrapper);
-                //过滤匹配当前的数据
-                for (Map map : nameList) {
-                    String name = (String)map.get("name");
-                    String dateStr = (String)map.get("dateStr");
-                    Optional<UserCorpwxTime> first = timeList.stream().filter(time -> time.getName().equals(name) && dtf.format(time.getCreateDate()).equals(dateStr)).findFirst();
-                    if (first.isPresent()) {
-                        double wh = first.get().getWorkHours();
-                        //赋值打卡时长
-                        map.put("cardHours", wh);
+                if (nameList.size() > 0) {
+                    for (Map map : nameList) {
+                        String name = (String)map.get("name");
+                        String dateStr = (String)map.get("dateStr");
+                        userCorpwxTimeQueryWrapper.or(wrapper->wrapper.eq("name", name).eq("create_date", dateStr));
+                    }
+                    List<UserCorpwxTime> timeList = userCorpwxTimeMapper.selectList(userCorpwxTimeQueryWrapper);
+                    //过滤匹配当前的数据
+                    for (Map map : nameList) {
+                        String name = (String)map.get("name");
+                        String dateStr = (String)map.get("dateStr");
+                        Optional<UserCorpwxTime> first = timeList.stream().filter(time -> time.getName().equals(name) && dtf.format(time.getCreateDate()).equals(dateStr)).findFirst();
+                        if (first.isPresent()) {
+                            double wh = first.get().getWorkHours();
+                            //赋值打卡时长
+                            map.put("cardHours", wh);
+                        }
                     }
                 }
             } else if (timeType.getShowDdCardtime() == 1) {
                 //钉钉的情况
                 QueryWrapper<UserDingdingTime> userDingdingTimeQueryWrapper = new QueryWrapper<>();
-                for (Map map : nameList) {
-                    String itemUid = (String)map.get("userId");
-                    String dateStr = (String)map.get("dateStr");
-                    userDingdingTimeQueryWrapper.or(wrapper->wrapper.eq("user_id", itemUid).eq("work_date", dateStr));
-                }
-                List<UserDingdingTime> timeList = userDingdingTimeMapper.selectList(userDingdingTimeQueryWrapper);
-                //过滤匹配当前的数据
-                for (Map map : nameList) {
-                    String itemUid = (String)map.get("userId");
-                    String dateStr = (String)map.get("dateStr");
-                    Optional<UserDingdingTime> first = timeList.stream().filter(time -> time.getUserId().equals(itemUid) && dtf.format(time.getWorkDate()).equals(dateStr)).findFirst();
-                    if (first.isPresent()) {
-                        double wh = first.get().getWorkHours();
-                        //赋值打卡时长
-                        map.put("cardHours", wh);
+                if (nameList.size() > 0) {
+                    for (Map map : nameList) {
+                        String itemUid = (String)map.get("userId");
+                        String dateStr = (String)map.get("dateStr");
+                        userDingdingTimeQueryWrapper.or(wrapper->wrapper.eq("user_id", itemUid).eq("work_date", dateStr));
+                    }
+                    List<UserDingdingTime> timeList = userDingdingTimeMapper.selectList(userDingdingTimeQueryWrapper);
+                    //过滤匹配当前的数据
+                    for (Map map : nameList) {
+                        String itemUid = (String)map.get("userId");
+                        String dateStr = (String)map.get("dateStr");
+                        Optional<UserDingdingTime> first = timeList.stream().filter(time -> time.getUserId().equals(itemUid) && dtf.format(time.getWorkDate()).equals(dateStr)).findFirst();
+                        if (first.isPresent()) {
+                            double wh = first.get().getWorkHours();
+                            //赋值打卡时长
+                            map.put("cardHours", wh);
+                        }
                     }
                 }
             }

+ 4 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -122,6 +122,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     private UserCertMapper userCertMapper;
     @Resource
     private UserCertService userCertService;
+    @Resource
+    private TaskGroupMapper taskGroupMapper;
     //登录网页端
     @Override
     public HttpRespMsg loginAdmin(String username, String password) {
@@ -232,8 +234,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
         //返回菜单
         List<SysRoleModule> rModules = sysRoleModuleMapper.selectList(new QueryWrapper<SysRoleModule>().eq("role_id", roleId));
         List<Integer> ids = rModules.stream().map(SysRoleModule::getModuleId).collect(Collectors.toList());
-        //项目报告审核模块,如果参与日报的审核,需要自动加上
-        if (user.isLeader() || user.isHasAuditDept()) {
+        //项目报告审核模块,如果参与日报的审核,需要自动加上, 或者担任任务分组负责人
+        if (user.isLeader() || user.isHasAuditDept() || (company.getPackageProject() == 1 && taskGroupMapper.selectCount(new QueryWrapper<TaskGroup>().eq("incharger_id", user.getId())) > 0)) {
             SysModule projectAuditModule = sysModuleMapper.selectOne(new QueryWrapper<SysModule>().eq("name", "项目报告审核"));
             if (!ids.contains(projectAuditModule.getId())) {
                 ids.add(projectAuditModule.getId());

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

@@ -550,6 +550,17 @@
         </foreach>
         GROUP BY project_id, basecost_id
     </select>
+
+    <!-- 项目填报的成本,待审核和已审核的都算 -->
+    <select id="getProjectFillCost" resultType="java.util.HashMap">
+        SELECT project_id as projectId,basecost_id as basecostId, SUM(cost) AS cost FROM report WHERE company_id=#{companyId}
+        AND (state = 1 or state = 0) and basecost_id > 0 AND project_id IN
+        <foreach collection="projectIds" item="item" separator="," open="(" close=")" index="index">
+            #{item}
+        </foreach>
+        GROUP BY project_id, basecost_id
+    </select>
+
     <select id="getOneProjectBaseCost" resultType="java.util.HashMap">
         SELECT basecost_id as basecostId, IFNULL(SUM(cost), 0) AS cost FROM report WHERE state = 1 and basecost_id > 0 AND project_id = #{projectId} group by basecost_id
     </select>

+ 66 - 50
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -309,7 +309,7 @@
                         </el-time-picker>
                         </span>
                         <div class="overtime" v-if="user.timeType.fillOvertime">
-                            <el-checkbox :disabled="!canEdit" v-model="domain.isOvertime">加班</el-checkbox>
+                            <el-checkbox :disabled="!canEdit" v-model="domain.isOvertime">加班</el-checkbox>
                             <el-input :disabled="!canEdit || domain.isOvertime==null || domain.isOvertime==0" v-model="domain.overtimeHours" @blur="triggerCalculateOT(index)" @input="domain.overtimeHours=domain.overtimeHours.replace(/[^\d.]/g,'')" style="width: 100px;"></el-input><span style="margin-left:5px">小时</span>
                         </div>
                     </el-form-item>
@@ -331,11 +331,11 @@
                             <el-option v-for="item in domain.subProjectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
                         </el-select>
                         
-                        <el-link v-if="index >= 1" type="primary" :underline="false" @click="delDomain(index)" style="float:right;margin-right:10px;"
+                        <el-link v-if="index >= 1&&canEdit" type="primary" :underline="false" @click="delDomain(index)" style="float:right;margin-right:10px;"
                             :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"
+                        <el-link type="primary" v-if="canEdit"
                             :underline="false" style="margin-left:10px;" @click="copyProject(index)">复制</el-link>
                     </el-form-item>
                     <el-form-item :label="user.companyId==781?'描述':'项目描述'" v-if="user.company.packageProject==0&&domain.projectId&&projectList.filter(p=>p.id == domain.projectId)[0].projectDesc">
@@ -422,7 +422,7 @@
                             <el-select v-model="domain.projectId" placeholder="请选择项目" style="width:200px;" clearable="true"  filterable="true"
                             @change="selectProject(domain, index)"
                             :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
-                                <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id"></el-option>
+                                <el-option v-for="item in projectList" :disabled="item.status>=2" :key="item.id" :label="item.projectName" :value="item.id"></el-option>
                             </el-select>
                             <span  v-if="domain.subProjectList != null && domain.subProjectList.length> 0 && domain.projectId != ''"
                                 style="margin-left:45px;">子项目</span>
@@ -433,16 +433,16 @@
                                 <el-option v-for="item in domain.subProjectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
                             </el-select>
 
-                            <el-link v-if="index >= 1" type="primary" :underline="false" @click="delDomain(index)" style="float:right;margin-right:10px;"
+                            <el-link v-if="index >= 1&&canEdit" type="primary" :underline="false" @click="delDomain(index)" style="float:right;margin-right:10px;"
                                 :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>
 
-                            <div class="overtime" v-if="user.timeType.fillOvertime"><el-checkbox :disabled="!canEdit" v-model="domain.isOvertime">加班</el-checkbox>
+                            <div class="overtime" v-if="user.timeType.fillOvertime"><el-checkbox :disabled="!canEdit" v-model="domain.isOvertime">加班</el-checkbox>
                             <el-input :disabled="!canEdit || domain.isOvertime==null || domain.isOvertime==0" v-model="domain.overtimeHours" @blur="triggerCalculateOT(index)" @input="domain.overtimeHours=domain.overtimeHours.replace(/[^\d.]/g,'')" style="width: 100px;"></el-input><span style="margin-left:5px">小时</span>
                             </div>
                             
-                            <el-link type="primary" v-if="workForm.domains[index].state == 0 || workForm.domains[index].state == 2"
+                            <el-link type="primary" v-if="canEdit"
                                 :underline="false" style="margin-left:10px;" @click="copyProject(index)">复制</el-link>
                         </el-form-item>
                         <el-form-item :label="user.companyId==781?'描述':'项目描述'" v-if="user.company.packageProject==0&&domain.projectId&&projectList.filter(p=>p.id == domain.projectId)[0].projectDesc">
@@ -567,7 +567,8 @@
                 <el-link v-if="showAddMore"  :disabled="!canEdit" type="primary" :underline="false" @click="addDomain(reportTimeType.type)" style="margin-left:40px">添加更多</el-link>
             </el-form>
             <span slot="footer" class="dialog-footer">
-                <el-button @click="deleteReport" v-if="workForm.domains[0].id != null">删除</el-button>
+                <!-- <el-button @click="cancelReport"  v-if="workForm.domains[0].id != null && workForm.domains[0].state == 0">撤回</el-button> -->
+                <el-button @click="deleteReport"  v-if="workForm.domains[0].id != null && canEdit">删除</el-button>
                 <el-button @click="dialogVisible = false">取消</el-button>
                 <el-button v-if="!isSubstitude" @click="submitReport(1)" :loading="submitingReport" :disabled="workForm.domains.length==0?true:(canEdit?false:true)">暂存</el-button>
                 <el-button type="primary" @click="submitReport(0)" :loading="submitingReport"
@@ -624,6 +625,7 @@
                 <el-select v-model="selCon" multiple placeholder="请选择" filterable>
                     <el-option
                     v-for="item in projectList"
+                    :disabled="item.status>=2"
                     :key="item.id"
                     :label="item.projectName"
                     :value="item.id">
@@ -662,6 +664,13 @@
                         <el-option v-for="item in zhoBao.subProjectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
                     </el-select>
                 </div>
+                <!--如果设置了工时成本预警的预算成本项-->
+                <div class="zhoFel" v-if="timeBasecostList &&timeBasecostList.length>0">
+                    <p>预算来源</p>
+                    <el-select v-model="zhoBao.basecostId" style="width: 355px">
+                        <el-option v-for="item in timeBasecostList" :label="item.name" :value="item.id" :key="item.id"></el-option>
+                    </el-select>
+                </div>
                 <!-- 任务分组 -->
                 <div class="zhoFel" v-if="user.company.packageProject == 1">
                     <p>任务分组</p>
@@ -3597,6 +3606,10 @@
                 sss.time = item.time
                 sss.workingTime = item.workingTime
                 sss.projectAuditorId = item.projectAuditorId;
+                if (this.timeBasecostList && this.timeBasecostList.length > 0) {
+                    //默认选中第一个
+                    sss.basecostId = this.timeBasecostList[0].id;
+                }
                 var that = this
                 setTimeout(() =>{
                     if(Object.keys(item).length < 5) {
@@ -3808,6 +3821,18 @@
                     this.selProjectList = this.projectList
                     this.selConShow = false
                 }
+                if (!this.timeBasecostList || this.timeBasecostList.length == 0) {
+                    //重新获取工时预警类型的预算项
+                    this.http.post('/project-basecost-setting/getReportBasecostList', {
+                        companyId: this.user.companyId
+                    },
+                    res => {
+                        if (res.code == "ok") {
+                            this.timeBasecostList = res.data;
+                            console.log(this.timeBasecostList);
+                        }
+                    });
+                }
             },
             // 按周填报的项目筛选
             selListFun(){
@@ -3994,6 +4019,7 @@
                         return false
                     }
                 }
+                
                     var submits = []
                     let formData = new FormData();
                     if(this.reportTimeType.multiWorktime == 1){
@@ -4035,6 +4061,11 @@
                                     if (zhoD[j].projectAuditorId) {
                                         formData.append("projectAuditorId",zhoD[j].projectAuditorId)
                                     }
+                                    if(zhoD[j].basecostId) {
+                                        formData.append("basecostId", zhoD[j].basecostId);
+                                    } else {
+                                        formData.append("basecostId", 0);
+                                    }
                                 }
                             }
                         }
@@ -4067,6 +4098,11 @@
                                         if (zhoD[j].projectAuditorId) {
                                             formData.append("projectAuditorId",zhoD[j].projectAuditorId)
                                         }
+                                        if(zhoD[j].basecostId) {
+                                            formData.append("basecostId", zhoD[j].basecostId);
+                                        } else {
+                                            formData.append("basecostId", 0);
+                                        }
                                     }
                                 }
                             } else {
@@ -4102,44 +4138,20 @@
                                         if (zhoD[j].projectAuditorId) {
                                             formData.append("projectAuditorId",zhoD[j].projectAuditorId)
                                         }
+                                        if(zhoD[j].basecostId) {
+                                            formData.append("basecostId", zhoD[j].basecostId);
+                                        } else {
+                                            formData.append("basecostId", 0);
+                                        }
                                     }
                                 }
                             }
                         }
                     } 
-                    // else {
-                    //     for (var i in this.zhoData) {
-                    //         var zhoD = this.zhoData[i]
-                    //         var flgs = false
-                    //         for(var j in zhoD) {     
-                    //             if(j != 'zhoDataTime' && j != 'he' && zhoD[j].workingTime && zhoD[j].workingTime.length > 0 && zhoD[j].workingTime > 0 && zhoD[j].workingTime != null && zhoD[j].workingTime != 'null') {
-                    //                 flgs = true
-                    //                 formData.append("degreeId", "-1");
-                    //                 formData.append("id", '-1');
-                    //                 for(var s in this.projectList) {
-                    //                     if(j == this.projectList[s].projectName) {
-                    //                         formData.append("projectId", this.projectList[s].id);
-                    //                     }
-                    //                 }
-                    //                 formData.append("subProjectId", '0');
-                    //                 formData.append("taskId", 0);
-                    //                 formData.append("reportTimeType", this.reportTimeType.type);
-                    //                 formData.append("progress", zhoD[j].progress);
-                    //                 formData.append("workingTime", zhoD[j].workingTime);
-                    //                 formData.append("content", zhoD[j].con);
-                    //                 formData.append("multiWorktime", this.reportTimeType.multiWorktime);
-                    //                 formData.append("isOvertime", 0)
-                    //                 formData.append("professionProgress", "[]")
-                    //                 formData.append("stage", "");
-                    //                 formData.append("createDate",zhoD.zhoDataTime)
-
-                    //             }
-                    //         }
-                    //     }
-                    // }
+                    
                     this.http.uploadFile( this.port.report.editPort, formData,
                         res => {
-                            this.listLoading = false;
+                            // this.listLoading = false;
                             if (res.code == "ok") {
                                 this.$message({
                                     message: "填报成功",
@@ -4151,6 +4163,9 @@
                                 this.zhoRqi = ''
                                 this.getReportList();
                                 this.getDepartment();
+                                // 关闭弹窗 并 清空
+                                this.selProjectList = []
+                                this.selCon = []
                             } else {
                                 this.$message({
                                     message: res.msg,
@@ -4165,13 +4180,6 @@
                                 type: "error"
                             });
                         });
-                // 关闭弹窗 并 清空
-                // this.diasZho = false
-                // this.zhoData = []
-                // this.zhoRqi = ''
-                this.selProjectList = []
-                this.selCon = []
-                
             },
             ChangeHourMinutestr (str) {
                 if (str !== "0" && str !== "" && str !== null) {
@@ -4593,10 +4601,18 @@
                             if (this.workForm.domains[i].projectAuditorId) {
                                 formData.append("projectAuditorId", this.workForm.domains[i].projectAuditorId);
                             } else {
-                                this.$message({
-                                    message: "请指定项目审核人",
-                                    type: "error"
-                                });
+                                if (this.workForm.domains[i].taskGpIncharge == 0) {
+                                    this.$message({
+                                        message: "请指定项目审核人",
+                                        type: "error"
+                                    });
+                                } else if (this.workForm.domains[i].taskGroups.length == 0) {
+                                    this.$message({
+                                        message: "您在["+this.workForm.domains[i].projectName+"]项目上尚无参与的任务分组",
+                                        type: "error"
+                                    });
+                                } 
+                                
                                 return;
                             }
                         }

+ 8 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -44,7 +44,7 @@
                             @cancel="item.showPickerSubProject = false;$forceUpdate();" />
                     </van-popup>
                     <!--任务分组 -->
-                    <van-field  readonly  name="groupId" v-if="user.company.packageProject==1&&item.taskGroups != null && item.taskGroups.length > 0" clickable 
+                    <van-field  readonly  name="groupId" v-if="item.taskGpIncharge == 1 || (user.company.packageProject==1&&item.taskGroups != null && item.taskGroups.length > 0)" clickable 
                         :value="item.groupName" label="任务分组" placeholder="请选择任务分组" 
                     @click="clickPickTaskGroup(index, item)" />
                     <van-popup v-model="item.showPickerTaskGroup" position="bottom">
@@ -480,6 +480,7 @@
             //获取项目下的任务分组
             getTaskGroups(domainItem, index) {
                 domainItem.groupId=null;
+                domainItem.groupName=null;
                 this.$axios.post("/task-group/listMyJoinGroup", {projectId: domainItem.projectId})
                     .then(res => {
                         if(res.code == "ok") {
@@ -1402,7 +1403,12 @@
                     if (this.form.domains[i].projectAuditorId) {
                         formData.append("projectAuditorId", this.form.domains[i].projectAuditorId);
                     } else {
-                        this.$toast.fail("请指定["+this.form.domains[i].projectName+']项目的审核人');
+                        if (this.form.domains[i].taskGpIncharge == 0) {
+                            this.$toast.fail("请指定["+this.form.domains[i].projectName+']项目的审核人');
+                        } else if (this.form.domains[i].taskGroups.length == 0) {
+                            this.$toast.fail("您在["+this.form.domains[i].projectName+"]项目上尚无参与的任务分组");
+                        }
+                        
                         return;
                     }
                 }