Przeglądaj źródła

工时管家提交对于企微考勤校准的修改,判断是否包含休息时间

QuYueTing 3 tygodni temu
rodzic
commit
dcc8233d70
17 zmienionych plików z 390 dodań i 2670 usunięć
  1. 15 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  2. 7 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserCorpwxTimeController.java
  3. 0 2533
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserCorpwxTimeController.java~
  4. 1 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskExecutor.java
  5. 1 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java
  6. 0 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  7. 2 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  8. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  9. 8 8
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  10. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  11. 44 16
      fhKeeper/formulahousekeeper/timesheet/src/components/popUpWindowForSelectingPersonnel.vue
  12. 49 9
      fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue
  13. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  14. 21 7
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  15. 6 3
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue
  16. 7 4
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/edit.vue
  17. 223 69
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/task/editask.vue

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

@@ -837,8 +837,12 @@ public class ReportController {
                     final int i1 = i;
                     Project project = projectList.stream().filter(p -> p.getId().equals(integers.get(i1))).findFirst().orElse(null);
                     List<ConstructionStage> stageList = JSONArray.parseArray(constructionStagesStr[i], ConstructionStage.class);
+                    boolean hasFinishNum = false;
                     for (ConstructionStage currentStage : stageList) {
                         if (currentStage == null) continue;
+                        if (currentStage.getFinishNumber() != null && currentStage.getFinishNumber() > 0) {
+                            hasFinishNum = true;
+                        }
                         //获取到施工分项的id
                         ProjectConstructionStage projectConstructionStage = projectConstructionStageService.getOne(new QueryWrapper<ProjectConstructionStage>().eq("project_id", project.getId()).eq("stage_id", currentStage.getId()));
                         if (projectConstructionStage != null && projectConstructionStage.getDesignNumber() != null && projectConstructionStage.getDesignNumber() > 0) {
@@ -873,6 +877,13 @@ public class ReportController {
                             }
                         }
                     }
+                    if (stageList.size() > 0 && !hasFinishNum) {
+                        //完成数量不能为0
+                        HttpRespMsg msg = new HttpRespMsg();
+                        msg.setError("项目"+project.getProjectName()+"中的完成数量不能全部为0");
+                        return msg;
+
+                    }
                 }
             }
         }
@@ -1680,9 +1691,11 @@ public class ReportController {
             }
         }
 
+        //获取当前填报的是否有非项目
         //校验非项目工时占比
         User reportOwner = userMapper.selectById(reportList.get(0).getCreatorId());
-        if (reportOwner.getUserGroupId() != null) {
+        boolean hasNonProject = projectList.stream().anyMatch(p -> p.getIsPublic() == 1);
+        if (hasNonProject && reportOwner.getUserGroupId() != null) {
             //获取最大的日期
             LocalDate maxDate = reportList.stream().map(Report::getCreateDate).max(new Comparator<LocalDate>() {
                 @Override
@@ -1692,7 +1705,6 @@ public class ReportController {
             }).get();
             //该逻辑生效日期
             LocalDate effectiveDate = LocalDate.of(2024, 8, 14);
-//            System.out.println(reportOwner.getId()+", maxDate:"+maxDate);
             if (maxDate.isAfter(effectiveDate)) {
                 //取最近五个工作日
                 int cnt = 0;
@@ -1736,6 +1748,7 @@ public class ReportController {
                 }
             }
         }
+
         DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 
         //对于正北(苏州和广州)需校验项目开始结束日期

+ 7 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserCorpwxTimeController.java

@@ -1179,10 +1179,14 @@ public class UserCorpwxTimeController {
             return;
         }
         
-        // 解析日期列(从第4列开始,前三列是期间、人员、划分)
+        // 解析日期列(从第4列开始,前三列是期间、人员、划分),兼容第四列是部门的情况
+        boolean hasDeptColumn = false;
+        String column4Name = headerRow.getCell(3).toString().trim();
+        hasDeptColumn = column4Name.contains("部门");
         // 最后一列是考勤总工时,需要排除
         List<Integer> dateColumns = new ArrayList<>();
-        for (int colIndex = 3; colIndex < headerRow.getLastCellNum() - 1; colIndex++) {
+        int dateColumnStartIndex = 3 + (hasDeptColumn ? 1 : 0);
+        for (int colIndex = dateColumnStartIndex; colIndex < headerRow.getLastCellNum() - 1; colIndex++) {
             Cell cell = headerRow.getCell(colIndex);
             if (cell != null) {
                 String cellValue = cell.toString().trim();
@@ -1308,7 +1312,7 @@ public class UserCorpwxTimeController {
                     }
                     LocalDate workDate = LocalDate.of(year, month, day);
                     
-                    Cell workHoursCell = row.getCell(colIndex + 3); // +3是因为前三列是期间、人员、划分
+                    Cell workHoursCell = row.getCell(colIndex + dateColumnStartIndex); // +dateColumnStartIndex是因为前三列是期间、人员、划分// (可能还有部门列)
                     if (workHoursCell == null) {
                         continue;
                     }

Plik diff jest za duży
+ 0 - 2533
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserCorpwxTimeController.java~


+ 1 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskExecutor.java

@@ -83,6 +83,7 @@ public class TaskExecutor extends Model<TaskExecutor> {
     @TableField("file_charge_one_id")
     private String fileChargeOneId;
 
+
     @TableField(exist = false)
     private String fileChargeOneName;
 

+ 1 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java

@@ -704,6 +704,7 @@ public class TimeType extends Model<TimeType> {
     @TableField("finance_twice_assign")
     private Boolean financeTwiceAssign;
 
+
     @TableField(exist = false)
     private List<User> userList;
     @TableField(exist = false)

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

@@ -890,7 +890,6 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     public HttpRespMsg getProjectList(Integer forReport, String userId,Integer projectMainId, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
-            System.out.println("userId===="+userId);
             if (userId == null) {
                 userId = request.getHeader("Token");
             }

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

@@ -695,7 +695,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 }
                 r.setProjectName(allProjectList.stream().filter(p->p.getId().equals(r.getProjectId())).findFirst().get().getProjectName());
                 r.setSubProjectList(subProjectList.stream().filter(s->s.getProjectId().equals(r.getProjectId())).collect(Collectors.toList()));
-                r.setTaskList(taskMapper.recentSimpleList(r.getProjectId(), userId, r.getStage(), r.getGroupId()));
+                List<UserRecentTask> tasks = taskMapper.recentSimpleList(r.getProjectId(), userId, r.getStage(), r.getGroupId());
+                r.setTaskList(tasks);
                 //获取当前项目的工程专业进度
                 List<ReportProfessionProgress> progressList = reportProfessionProgressService.list(new QueryWrapper<ReportProfessionProgress>().eq("report_id", r.getId()));
                 //去掉当前项目上已经不存在的专业
@@ -948,7 +949,6 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
                 if (companyId == 10 || companyId == 4811) {
                     List<ReportProjectConstruction> rpcList = reportProjectConstructionMapper.selectList(new QueryWrapper<ReportProjectConstruction>().eq("report_id", r.getId()));
-                    System.out.println(r.getProjectName()+ ", rpcList.size()=="+rpcList.size()+", r.getProjectId()="+r.getProjectId());
                     for (ReportProjectConstruction rpc : rpcList) {
                         System.out.println(rpc.getConstructionStageId()+", "+rpc.getFinishNumber());
                     }
@@ -967,16 +967,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             resultMap.put("report", reports);
             if(CollectionUtils.isEmpty(reports)){
                 List<BustripProject> businessTrips = bustripProjectMapper.getByDate(date,userId);
-//                List<BusinessTrip> businessTrips = bustripProjectMapper.selectList(new LambdaQueryWrapper<BusinessTrip>()
-//                        .eq(BusinessTrip::getOwnerId, userId)
-//                        .lt(BusinessTrip::getStartDate,date)
-//                        .gt(BusinessTrip::getEndDate,date)
-//                );
-//                if(CollectionUtils.isNotEmpty(businessTrips)){
-//                    resultMap.put("businessTrips",businessTrips);
-//                }
                 resultMap.put("businessTrips",businessTrips);
-
             }
             boolean showRefresh = false;
             if (timeType.getShowDdCardtime() == 1) {

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

@@ -1542,6 +1542,8 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                     int sTime = summary_info.getIntValue("earliest_time");//秒
                     int eTime = summary_info.getIntValue("lastest_time");//秒
                     int regular_work_sec = summary_info.getIntValue("regular_work_sec");//秒
+                    int standard_work_sec = summary_info.getIntValue("standard_work_sec");//秒
+                    double standard_work_time = DateTimeUtil.getHoursFromSeconds(standard_work_sec);//小时
                     ct.setStartTime(DateTimeUtil.getTimeFromSeconds(sTime));
                     ct.setEndTime(DateTimeUtil.getTimeFromSeconds(eTime));
                     boolean isCrossDay = regular_work_sec > 0 && eTime >= 24 * 3600;//加班至第二天
@@ -1823,7 +1825,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                             }
                         } else {
                             //企微传过来的考勤时间大于等于9小时,可能是包含午休的时间,需要减去。
-                            if (ct.getEndTime().compareTo(baseAfternoonStart) >= 0 && ct.getCardTime() >= 9.0) {
+                            if (ct.getEndTime().compareTo(baseAfternoonStart) >= 0 && ct.getCardTime() >= standard_work_time + restTime) {
                                 //重新计算工作工时时,需要用打卡总时间减去中间午休时间
                                 timeDelta = ct.getCardTime() - restTime;
                             } else {

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

@@ -1063,7 +1063,7 @@
         <if test="endDate != null">
             AND report.create_date &lt; #{endDate}
         </if>
-        GROUP BY project_id, report.creator_id;
+        GROUP BY project_id, report.creator_id order by project_id, report.creator_id;
     </select>
 
     <select id="getRealProjectTimeNew" resultType="java.util.Map">
@@ -1088,7 +1088,7 @@
         AND not exists(
         select 1 from finance_exclude_project fep where fep.company_id = report.company_id and fep.use_ym = #{ym} and fep.project_id = report.project_id
         )
-        GROUP BY project_id, report.creator_id order by project_id;
+        GROUP BY project_id, report.creator_id order by project_id, report.creator_id;
     </select>
 
     <select id="getUploadThirdReportData" resultType="java.util.Map">
@@ -1222,7 +1222,7 @@
         <foreach collection="projectIds" item="item" separator="," open="(" close=")" index="index">
             #{item}
         </foreach>
-        GROUP BY project_id, basecost_id
+        GROUP BY project_id, basecost_id order by project_id, basecost_id
     </select>
 
     <!-- 项目填报的成本,待审核和已审核的都算 -->
@@ -1232,7 +1232,7 @@
         <foreach collection="projectIds" item="item" separator="," open="(" close=")" index="index">
             #{item}
         </foreach>
-        GROUP BY project_id, basecost_id
+        GROUP BY project_id, basecost_id order by project_id, basecost_id
     </select>
 
     <select id="getOneProjectBaseCost" resultType="java.util.HashMap">
@@ -1257,7 +1257,7 @@
                 #{item}
             </foreach>
         </if>
-        group by user.id,rl.create_date
+        group by user.id,rl.create_date order by `user`.id, rl.create_date
     </select>
 
 
@@ -1276,7 +1276,7 @@
                 #{item}
             </foreach>
         </if>
-        group by t.id,user.id,rl.work_date
+        group by t.id,user.id,rl.work_date order by t.id, user.id, rl.work_date
     </select>
 
     <select id="getDefaultDegree" resultType="java.util.Map">
@@ -1481,7 +1481,7 @@
         <if test="userId!=null and userId!=''">
             and u.id=#{userId}
         </if>
-        group by p.id,r.create_date,u.id
+        group by p.id,r.create_date,u.id order by p.id, r.create_date, u.id
     </select>
 
     <select id="getCustomDataWithDate" resultType="java.util.Map">
@@ -1493,7 +1493,7 @@
         <if test="startDate!=null and endDate!=null">
             AND b.create_date BETWEEN #{startDate} AND #{endDate}
         </if>
-        GROUP BY b.project_id,b.`create_date`
+        GROUP BY b.project_id,b.`create_date` order by b.project_id, b.`create_date`
         HAVING IFNULL(SUM(b.custom_data),0) > 0
     </select>
 

+ 2 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml

@@ -311,10 +311,10 @@
         <if test="userId != null">
             and executor_id like '%${userId}%'
         </if>
-        <if test="stage != null">
+        <if test="stage != null and stage != ''">
             and stages.stages_name = #{stage}
         </if>
-        <if test="groupId != null">
+        <if test="groupId != null and groupId != 0">
             and task.group_id = #{groupId}
         </if>
         and task_status = 0 order by task.id desc limit 300

+ 44 - 16
fhKeeper/formulahousekeeper/timesheet/src/components/popUpWindowForSelectingPersonnel.vue

@@ -9,7 +9,7 @@
         </el-input>
       </div>
       <div class="theContent-tree">
-        <el-tree :data="deptMembData" show-checkbox default-expand-all check-strictly node-key="id" ref="tree"
+        <el-tree :data="deptMembData" show-checkbox default-expand-all :check-strictly="!multiple" node-key="id" ref="tree"
           highlight-current :props="defaultProps" @check-change="treeHandChange" :filter-node-method="filterNode" v-loading="selectPersonnelTreeLoading">
           <span class="custom-tree-node" slot-scope="{ node, data }">
             <span v-if="user.userNameNeedTranslate == '1'">
@@ -49,6 +49,10 @@ export default {
     width: {
       type: String,
       default: '800px'
+    },
+    multiple: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -132,10 +136,12 @@ export default {
       }
     },
     treeHandChange(val, flag) {
-      const { id } = val
-      if (flag) {
-        this.$refs.tree.setCheckedKeys([]);
-        this.$refs.tree.setCheckedKeys([id]);
+      if (!this.multiple) {
+        const { id } = val
+        if (flag) {
+          this.$refs.tree.setCheckedKeys([]);
+          this.$refs.tree.setCheckedKeys([id]);
+        }
       }
     },
     // 获取部门列表
@@ -189,18 +195,40 @@ export default {
     // 确定控件
     handleConfirm() {
       const arr = this.$refs.tree.getCheckedNodes()
-      const item = arr[0] || {}
-      if(!item.isUser) {
-        this.$message({
-          message: '请选择人员',
-          type: "error"
-        });
-        return
-      }
+      
+      if (this.multiple) {
+        // 多选模式:过滤出所有用户节点
+        const users = arr.filter(item => item.isUser)
+        if (users.length === 0) {
+          this.$message({
+            message: '请至少选择一个人员',
+            type: "error"
+          });
+          return
+        }
+        
+        const result = users.map(item => ({
+          ...item,
+          value: item.id,
+          label: item.label
+        }))
+        this.$emit('confirm', result)
+        this.handleClose()
+      } else {
+        // 单选模式
+        const item = arr[0] || {}
+        if(!item.isUser) {
+          this.$message({
+            message: '请选择人员',
+            type: "error"
+          });
+          return
+        }
 
-      const row = { ...item, value: item.id, label: item.label }
-      this.$emit('confirm', row)
-      this.handleClose()
+        const row = { ...item, value: item.id, label: item.label }
+        this.$emit('confirm', row)
+        this.handleClose()
+      }
     },
 
     // 设置树形控件的选中项

+ 49 - 9
fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue

@@ -154,7 +154,7 @@
             <el-link type="primary" v-if="(((addForm.executorListFront == null || addForm.executorListFront.length<100) && 
             (addForm.id == null|| user.id == addForm.createrId || currentProject.inchargerId == user.id || permissions.projectManagement || permissions.editAnyTask)) || 
             groupResponsibleId == user.id)" 
-            style="margin:0 0 10px 35px;position: relative;z-index: 999;" @click.stop="addExecutorLine">{{ $t('addinganexecutor') }}</el-link>
+            style="margin:0 0 10px 35px;position: relative;z-index: 999;" @click.stop="addMultipleExecutors">{{ $t('addinganexecutor') }}</el-link>
             </div>
 
             <template v-if="addForm.taskPlanType != 3">
@@ -775,8 +775,11 @@
         </span>
     </el-dialog>
 
-    <!-- 定义选择人员 -->
-    <popUpWindowForSelectingPersonnel v-model="specificExecutorVisable" ref="popUpWindowForSelectingPersonnelRef" @confirm="popUpWindowForSelectingPersonnelChange" />
+    <!-- 定义选择人员(单选) -->
+    <popUpWindowForSelectingPersonnel v-model="specificExecutorVisable" ref="popUpWindowForSelectingPersonnelRef" @confirm="popUpWindowForSelectingPersonnelChange" :multiple="false" />
+    
+    <!-- 定义选择人员(多选) -->
+    <popUpWindowForSelectingPersonnel v-model="multipleExecutorVisable" ref="popUpWindowForSelectingPersonnelMultiRef" @confirm="popUpWindowForSelectingPersonnelChange" :multiple="true" title="批量添加执行人" />
   </div>
 </template>
 
@@ -1056,6 +1059,7 @@ export default {
         // 添加具体执行人
         specificExecutor: { index: '', id: '', row: {} },
         specificExecutorVisable: false,
+        multipleExecutorVisable: false,
     };
   },
   computed: {
@@ -2678,13 +2682,49 @@ export default {
         this.specificExecutorVisable = true
     },
     popUpWindowForSelectingPersonnelChange(val) {
-        const { index = 0 } = this.specificExecutor
-        const row = this.addForm.executorListFront[index] || {}
-        this.addForm.executorListFront[index] = {
-            ...row,
-            executorId: val.value,
-            executorName: val.label
+        if (Array.isArray(val)) {
+            // 多选模式:批量添加执行人
+            // 如果第一条数据的执行人为空,先移除它
+            if (this.addForm.executorListFront.length > 0 && !this.addForm.executorListFront[0].executorId) {
+                this.addForm.executorListFront.splice(0, 1)
+                this.gstimday.splice(0, 1)
+                this.gstimhour.splice(0, 1)
+            }
+            
+            val.forEach(user => {
+                this.addForm.executorListFront.push({
+                    executorId: user.value,
+                    executorName: user.label,
+                    planHours: this.user.timeType.allday
+                })
+                this.gstimday.push(1)
+                this.gstimhour.push(this.user.timeType.allday)
+            })
+            this.$forceUpdate()
+            this.replacementResult()
+            setTimeout(() => {
+                this.bottomScrollClick()
+            }, 100)
+        } else {
+            // 单选模式:更新指定执行人
+            const { index = 0 } = this.specificExecutor
+            const row = this.addForm.executorListFront[index] || {}
+            this.addForm.executorListFront[index] = {
+                ...row,
+                executorId: val.value,
+                executorName: val.label
+            }
         }
+    },
+    
+    // 批量添加执行人(多选模式)
+    addMultipleExecutors() {
+        this.multipleExecutorVisable = true
+        this.$nextTick(() => {
+            if (this.$refs.popUpWindowForSelectingPersonnelMultiRef) {
+                this.$refs.popUpWindowForSelectingPersonnelMultiRef.setTreeCheckedKeys([])
+            }
+        })
     }
   },
 };

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

@@ -721,7 +721,7 @@
                                 </el-table-column>
                                 <el-table-column prop="percent"  label="占比">
                                     <template slot-scope="scope">
-                                        <el-input type="number" style="width:100px;" v-model="scope.row.percent" min="0" oninput="value=value.replace(/[^\d.]/g,'')"></el-input>&nbsp;%
+                                        <el-input :id="'percent'+scope.row.id" style="width:100px;" v-model="scope.row.percent"   @keyup.native="restrictNumber('percent'+scope.row.id)"></el-input>&nbsp;%
                                     </template>
                                 </el-table-column>
                                 <el-table-column prop="designNumber"  label="设计量" width="200">

+ 21 - 7
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -845,7 +845,7 @@
                             :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)" @change="onTaskSelected(domain)">
                                 <el-option v-for="item in domain.taskList" :key="item.taskId" :label="item.taskName" :value="item.taskId"></el-option>
                             </el-select>
-                            <el-checkbox v-model="domain.taskFinish" v-if="domain.taskId != undefined && user.companyId != '5608'">{{$t('state.completed')}}</el-checkbox>
+                            <!-- <el-checkbox v-model="domain.taskFinish" v-if="domain.taskId != undefined && user.companyId != '5608'">{{$t('state.completed')}}</el-checkbox> -->
                         </el-form-item>
                         <!--针对依斯贝的SAP服务-->
                         <el-form-item v-if="user.companyId==3092" :label="$t('fuWu')" :prop="'domains.' + index + '.sapServiceId'" 
@@ -1275,6 +1275,13 @@
                             <el-option v-for="item in zhoBao.stages" :key="item.id" :label="item.stagesName" :value="item.stagesName"></el-option>
                     </el-select>
                 </div>
+                <!-- 选择任务 -->
+                <div class="zhoFel" v-if="user.company.packageProject==1 && !user.timeType.hideTask && (user.company.nonProjectSimple==0 || (user.company.nonProjectSimple==1&&zhoBao.isPublic!=1))">
+                    <p>{{ $t('renWuLiChengBei') }}</p>
+                    <el-select v-model="zhoBao.taskId" :placeholder="$t('defaultText.pleaseChoose')" clearable="true" style="width: 355px" filterable @change="$forceUpdate()">
+                        <el-option v-for="item in zhoBao.taskList" :key="item.taskId" :label="item.taskName" :value="item.taskId"></el-option>
+                    </el-select>
+                </div>
                 <!-- 工单号,行号 -->
                 <div class="zhoFel" v-if="user.timeType.reportExtraField4Name">
                     <p>{{ user.timeType.reportExtraField4Name }}</p>
@@ -7632,6 +7639,8 @@
                         sss.subProjectList = data.subProjectList
                         sss.stages = data.stages
                         sss.taskGroups = data.taskGroups;
+                        sss.taskList = data.taskList;
+                        sss.taskId = data.taskId;
                         sss.auditUserList = data.auditUserList;
                         sss.degreeId = data.degreeId;
                         sss.customData = data.customData;
@@ -7644,10 +7653,10 @@
                         this.zhoBaoName = names
                         this.zhoBao = sss
                         this.zhis = row
-                        if (sss.groupId) {
-                            //最后一个参数表示是否保留stage的值,不要重置为空
-                            this.getGroupStages(this.zhoBao, 0, true)
-                        }
+                        // if (sss.groupId) {
+                        //     //最后一个参数表示是否保留stage的值,不要重置为空
+                        //     this.getGroupStages(this.zhoBao, 0, true)
+                        // }
                         if((reportExtraField4Name || reportExtraField5Name) && sss.groupId) {
                             this.weekGetInfoByProjectId(sss)
                         }
@@ -7747,6 +7756,12 @@
                 sss.stage = item.stage;
                 sss.workingTime = item.workingTime
                 sss.projectAuditorId = item.projectAuditorId;
+                // 设置isPublic属性,用于判断是否显示任务选择
+                var projectList = this.isSubstitude ? this.subFillProjectList : this.fillProjectList;
+                var selectedProject = projectList.find(p => p.id == projectId);
+                if (selectedProject) {
+                    sss.isPublic = selectedProject.isPublic;
+                }
                 if (this.timeBasecostList && this.timeBasecostList.length > 0) {
                     //默认选中第一个
                     sss.basecostId = this.timeBasecostList[0].id;
@@ -7754,8 +7769,6 @@
                 var hasEdited = this.zhoData[i][names].hasEdited;
 
                 if (hasEdited) {
-                    console.log('执行到了这个')
-                    console.log('执行到了这个', { ...item }, obj)
                     sss = { ...item }
                     //编辑过了
                     sss.subProjectId = item.subProjectId
@@ -7763,6 +7776,7 @@
                     sss.subProjectList = item.subProjectList
                     sss.stages = item.stages
                     sss.taskGroups = item.taskGroups;
+                    sss.taskList = item.taskList;
                     // sss.auditUserList = obj.auditUserList ;
                     sss.degreeId = item.degreeId;
                     sss.customData = item.customData;

+ 6 - 3
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -177,9 +177,12 @@
                     <van-popup v-model="item.showPickerConstruction" position="bottom">
                         <!-- <van-picker show-toolbar :columns="item.constructionStages" value-key="name" @confirm="choseConstruction"
                             @cancel="item.showPickerConstruction = false; $forceUpdate();" /> -->
-                        
                         <van-cell-group>
-                            <van-field label-width="70%" v-for="stage in item.constructionStages" :key="item.id" inputmode="decimal" :label="stage.name+' - 今日完成'" v-model="stage.finishNumber" placeholder="完成数量" :formatter="formatDecimal"></van-field>
+                            <van-field label-width="70%" v-for="stage in item.constructionStages" :key="item.id" inputmode="decimal" :label="stage.name+' - 今日完成'" v-model="stage.finishNumber" placeholder="完成数量" :formatter="formatDecimal">
+                            <template #right-icon>
+                                <span style="margin-left:5px; color:#666;">{{ stage.unit }}</span>
+                            </template>
+                            </van-field>
                         </van-cell-group>
                         <van-button style="width:100%" type="primary" @click="choseConstruction">确定</van-button>
                     </van-popup>
@@ -460,7 +463,7 @@
                         </van-cell>
                         <van-field class="form_input" :disabled="!item.canEdit" v-model="item.content" name="content" v-if="!user.timeType.hideContent"
                             type="textarea" label="工作内容" placeholder="请输入"
-                            :rules="user.timeType.workContentState == 1 && (user.companyId != 10 || item.constructionStages == null || item.constructionStages.length == 0)? [{ required: true, message: '请填写工作内容' }] : null"
+                            :rules="user.timeType.workContentState == 1 && ((user.companyId != 4811 && user.companyId != 10) || item.constructionStages == null || item.constructionStages.length == 0)? [{ required: true, message: '请填写工作内容' }] : null"
                             rows="3" autosize />
                     </div>
 

+ 7 - 4
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/edit.vue

@@ -191,8 +191,8 @@ export default {
         return {
             user: JSON.parse(localStorage.userInfo),
             projectId: JSON.parse(sessionStorage.projectId),
-            minDate: new Date(2020,0,1),
-            maxDate: new Date(2025,11,31),
+            minDate: new Date(2023,0,1),
+            maxDate: new Date(2029,11,31),
             projectDetail: {
                 auditorList: []
             },
@@ -322,11 +322,14 @@ export default {
             this.inchargerShow = false
         },
         startDateConfirm(value){
-            this.projectDetail.planStartDate = this.formatDate(value)
+            this.currentStartDate = value
+            this.$set(this.projectDetail, 'planStartDate', this.formatDate(value));
+            console.log('333', this.projectDetail.planStartDate);
             this.startDateShow = false
         },
         endDateConfirm(value){
-            this.projectDetail.planEndDate = this.formatDate(value)
+            this.currentEndDate = value
+            this.$set(this.projectDetail, 'planEndDate', this.formatDate(value));
             this.endDateShow = false
         },
 

+ 223 - 69
fhKeeper/formulahousekeeper/timesheet_h5/src/views/task/editask.vue

@@ -105,49 +105,61 @@
                     :max-date="maxDate"/>
                 </van-popup>
                 <!-- 执行人 -->
-                <div style="border: 0.5px solid #87c3ff;margin:0.2rem;position:relative" v-for="item,index in taskform.executorList" :key="index">
-                    <van-field v-model="item.executorName" :label="'执行人' + (index + 1)" placeholder="请选择执行人" @click="executorChange(item,index)" readonly clickable>
-                        <template #input>
-                            <span v-if="!item.executorName"></span>
-                            <span v-else-if="user.userNameNeedTranslate != 1">{{item.executorName}}</span>
-                            <span v-else><TranslationOpenDataText type='userName' :openid='item.executorName'></TranslationOpenDataText></span>
-                        </template>
-                    </van-field>
+                <div class="executor-table">
+                    <table class="executor-table-content">
+                        <thead>
+                            <tr>
+                                <th>执行人</th>
+                                <th>计划工时(h)</th>
+                                <th v-if="canEdit">操作</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr v-for="item,index in taskform.executorList" :key="index">
+                                <td @click="canEdit && executorChange(item,index)" class="executor-name-cell">
+                                    <span v-if="!item.executorName" class="placeholder-text">请选择</span>
+                                    <span v-else-if="user.userNameNeedTranslate != 1">{{item.executorName}}</span>
+                                    <span v-else><TranslationOpenDataText type='userName' :openid='item.executorName'></TranslationOpenDataText></span>
+                                </td>
+                                <td class="plan-hours-cell">
+                                    <van-stepper v-model="item.planHours" :disabled="!canEdit" :min="0" :max="999"/>
+                                </td>
+                                <td v-if="canEdit" class="action-cell">
+                                    <van-icon v-if="index != 0" name="delete-o" @click.stop="deleteExecutor(index)" color="#ee0a24" size="20"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
                     
-                    <van-field label="计划工时">
-                        <template #input>
-                            <van-stepper v-model="item.planHours" :disabled="!canEdit"/><span>{{'\u3000h'}}</span>
+                    <!-- 项目服务和审核人信息(如果需要) -->
+                    <div v-for="item,index in taskform.executorList" :key="'extra-' + index" 
+                         v-if="(user.companyId == '3092' && item.executorId) || (user.timeType.taskFileCharge == 2 && item.executorId)"
+                         class="executor-extra-info">
+                        <van-cell-group v-if="user.companyId == '3092' && item.executorId">
+                            <van-cell title="项目服务" :value="`${item.serviceName || ''} - ${item.serviceCode || ''}`" is-link @click="searchServiceCli(item,index)">
+                                <template #right-icon>
+                                    <div class="iconBox"></div>
+                                </template>
+                            </van-cell>
+                        </van-cell-group>
+
+                        <template v-if="user.timeType.taskFileCharge == 2 && item.executorId">
+                            <van-field v-model="item.fileChargeOneName" :label="'审核人1'" placeholder="请选择" @click="executorChange(item,index, 'fileChargeOneName')" readonly clickable>
+                                <template #input>
+                                    <span v-if="!item.fileChargeOneName"></span>
+                                    <span v-else-if="user.userNameNeedTranslate != 1">{{item.fileChargeOneName}}</span>
+                                    <span v-else><TranslationOpenDataText type='userName' :openid='item.fileChargeOneName'></TranslationOpenDataText></span>
+                                </template>
+                            </van-field>
+                            <van-field v-model="item.fileChargeTwoName" :label="'审核人2'" placeholder="请选择" @click="executorChange(item,index, 'fileChargeTwoName')" readonly clickable>
+                                <template #input>
+                                    <span v-if="!item.fileChargeTwoName"></span>
+                                    <span v-else-if="user.userNameNeedTranslate != 1">{{item.fileChargeTwoName}}</span>
+                                    <span v-else><TranslationOpenDataText type='userName' :openid='item.fileChargeTwoName'></TranslationOpenDataText></span>
+                                </template>
+                            </van-field>
                         </template>
-                    </van-field>
-                    <van-icon v-if="index != 0 && canEdit" class="delete_executor" name="delete-o" @click.stop="deleteExecutor(index)" />
-
-                    <van-cell-group v-if="user.companyId == '3092'">
-                        <van-cell title="项目服务" :value="`${item.serviceName || ''} - ${item.serviceCode || ''}`" is-link @click="searchServiceCli(item,index)">
-                            <template #right-icon>
-                                <div class="iconBox">
-                                    <!-- <van-icon name="close" size="18" class="iconRight" /> -->
-                                    <!-- <van-icon name="arrow" size="18" class="iconRight" /> -->
-                                </div>
-                            </template>
-                        </van-cell>
-                    </van-cell-group>
-
-                    <template v-if="user.timeType.taskFileCharge == 2">
-                        <van-field v-model="item.fileChargeOneName" :label="'审核人1'" placeholder="请选择" @click="executorChange(item,index, 'fileChargeOneName')" readonly clickable>
-                            <template #input>
-                                <span v-if="!item.fileChargeOneName"></span>
-                                <span v-else-if="user.userNameNeedTranslate != 1">{{item.fileChargeOneName}}</span>
-                                <span v-else><TranslationOpenDataText type='userName' :openid='item.fileChargeOneName'></TranslationOpenDataText></span>
-                            </template>
-                        </van-field>
-                        <van-field v-model="item.fileChargeTwoName" :label="'审核人2'" placeholder="请选择" @click="executorChange(item,index, 'fileChargeTwoName')" readonly clickable>
-                            <template #input>
-                                <span v-if="!item.fileChargeTwoName"></span>
-                                <span v-else-if="user.userNameNeedTranslate != 1">{{item.fileChargeTwoName}}</span>
-                                <span v-else><TranslationOpenDataText type='userName' :openid='item.fileChargeTwoName'></TranslationOpenDataText></span>
-                            </template>
-                        </van-field>
-                    </template>
+                    </div>
                 </div>
 
                 <!-- 选择项目服务 -->
@@ -180,13 +192,22 @@
                         </div>
 
                         <div class="popupCon conBorder">
-                            <van-radio-group v-model="executor.item" class="popupItem marginNone borderNone">
+                            <!-- 单选模式:用于切换人员 -->
+                            <van-radio-group v-if="!executor.isMultiSelect" v-model="executor.item" class="popupItem marginNone borderNone">
                                 <van-radio v-for="uitem in executor.searchList" :key="uitem.id" :name="uitem" style="padding:10px">
                                     <span v-if="user.userNameNeedTranslate != 1" class="userNameClass_left">{{uitem.name}}</span>
                                     <span v-else class="userNameClass_left"><TranslationOpenDataText type='userName' :openid='uitem.name'></TranslationOpenDataText></span>
                                     <span class="userNameClass_right">{{ uitem.jobNumber }}</span>
                                 </van-radio>
                             </van-radio-group>
+                            <!-- 多选模式:用于添加执行人 -->
+                            <van-checkbox-group v-if="executor.isMultiSelect" v-model="executor.selectedItems" class="popupItem marginNone borderNone">
+                                <van-checkbox v-for="uitem in executor.searchList" :key="uitem.id" :name="uitem" style="padding:10px">
+                                    <span v-if="user.userNameNeedTranslate != 1" class="userNameClass_left">{{uitem.name}}</span>
+                                    <span v-else class="userNameClass_left"><TranslationOpenDataText type='userName' :openid='uitem.name'></TranslationOpenDataText></span>
+                                    <span class="userNameClass_right">{{ uitem.jobNumber }}</span>
+                                </van-checkbox>
+                            </van-checkbox-group>
                         </div>
 
                         <div class="popupBtn">
@@ -196,7 +217,10 @@
                 </van-popup>
                 
                 <!-- 添加执行人 -->
-                <div class="add_executor" @click="addExecutor" v-if="canEdit">添加执行人</div>
+                <div class="add_executor" @click="addExecutor" v-if="canEdit">
+                    <van-icon name="plus" />
+                    <span>添加执行人</span>
+                </div>
                 <!-- 优先级 -->
                 <van-field v-model="taskform.taskLevel" label="优先级" @click="taskLevel.show = true" readonly clickable>
                     <template #input><span>{{taskLevel.list[taskform.taskLevel]}}</span></template>
@@ -274,7 +298,9 @@ export default {
                 list: [],
                 searchList: [],
                 searchText: '',
-                type: ''
+                type: '',
+                isMultiSelect: false,
+                selectedItems: []
             },
 
             select_project_show: false,
@@ -449,12 +475,13 @@ export default {
             this.finishDateShow = false
         },
         
-        executorChange(item, index, type){  // 选择执行人
+        executorChange(item, index, type){  // 选择执行人(单选模式)
             this.executor.searchText = ''
             this.getOnSearch('')
             this.executor.show = true
             this.executor.index = index
             this.executor.type = type
+            this.executor.isMultiSelect = false  // 设置为单选模式
             this.executor.searchList.forEach(u=>{if (u.id == item.executorId) {
                 this.executor.item = u
             }})
@@ -466,12 +493,12 @@ export default {
         },
         addExecutor(){
             console.log('addExecutor');
-            this.taskform.executorList.push({
-                executorName: '',
-                executorId: '',
-                planHours: this.user.timeType.allday
-            })
-            this.$forceUpdate();
+            // 设置为多选模式并打开弹窗
+            this.executor.searchText = ''
+            this.getOnSearch('')
+            this.executor.isMultiSelect = true
+            this.executor.selectedItems = []
+            this.executor.show = true
         },
         onSearch(val) {
             if(this.user.userNameNeedTranslate != 1) {
@@ -509,22 +536,46 @@ export default {
             }).catch(err=> {this.$toast.clear();console.log(err)});
         },
         searchExecutor(){
-            if(!this.executor.type) {
-                this.taskform.executorList[this.executor.index].executorId = this.executor.item.id
-                this.taskform.executorList[this.executor.index].executorName = this.executor.item.name
-            }
-            
-            if(this.executor.type == 'fileChargeOneName') {
-                this.taskform.executorList[this.executor.index].fileChargeOneId = this.executor.item.id
-                this.taskform.executorList[this.executor.index].fileChargeOneName = this.executor.item.name
-            }
+            // 多选模式:添加执行人
+            if(this.executor.isMultiSelect) {
+                if(this.executor.selectedItems.length === 0) {
+                    this.$toast.fail('请至少选择一个执行人');
+                    return
+                }
+                // 如果第一个执行人是空的,先清除掉
+                if(this.taskform.executorList.length > 0 && !this.taskform.executorList[0].executorId) {
+                    this.taskform.executorList.splice(0, 1)
+                }
+                // 将选中的人员添加到执行人列表
+                this.executor.selectedItems.forEach(selectedUser => {
+                    this.taskform.executorList.push({
+                        executorName: selectedUser.name,
+                        executorId: selectedUser.id,
+                        planHours: this.user.timeType.allday
+                    })
+                })
+                this.$forceUpdate();
+            } 
+            // 单选模式:切换执行人
+            else {
+                if(!this.executor.type) {
+                    this.taskform.executorList[this.executor.index].executorId = this.executor.item.id
+                    this.taskform.executorList[this.executor.index].executorName = this.executor.item.name
+                }
+                
+                if(this.executor.type == 'fileChargeOneName') {
+                    this.taskform.executorList[this.executor.index].fileChargeOneId = this.executor.item.id
+                    this.taskform.executorList[this.executor.index].fileChargeOneName = this.executor.item.name
+                }
 
-            if(this.executor.type == 'fileChargeTwoName') {
-                this.taskform.executorList[this.executor.index].fileChargeTwoId = this.executor.item.id
-                this.taskform.executorList[this.executor.index].fileChargeTwoName = this.executor.item.name
+                if(this.executor.type == 'fileChargeTwoName') {
+                    this.taskform.executorList[this.executor.index].fileChargeTwoId = this.executor.item.id
+                    this.taskform.executorList[this.executor.index].fileChargeTwoName = this.executor.item.name
+                }
+                console.log('searchExecutor',this.executor.item,this.executor.item.name);
             }
+            
             this.executor.show = false
-            console.log('searchExecutor',this.executor.item,this.executor.item.name);
         },
 
         taskLevelChange(value,key){     // 优先级
@@ -762,11 +813,31 @@ export default {
     margin-top: 46px;
     overflow: auto;
     .add_executor{
-        font-size:13px;
-        color:#1989fa;
-        padding-left:0.42667rem;
-        padding-bottom:.2rem;
-        width:100px
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        gap: 6px;
+        margin: 12px 16px;
+        padding: 10px 20px;
+        background: #ffffff;
+        color: #1989fa;
+        font-size: 14px;
+        font-weight: 500;
+        border: 1px solid #1989fa;
+        border-radius: 20px;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
+        
+        &:active {
+            transform: scale(0.98);
+            background: #f7f8fa;
+            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+        }
+        
+        .van-icon {
+            font-size: 16px;
+        }
     }
     .delete_executor{
         position: absolute;
@@ -776,6 +847,89 @@ export default {
         color: #c03131;
     }
 }
+
+// 执行人表格样式
+.executor-table {
+    .executor-table-content {
+        width: 100%;
+        border-collapse: collapse;
+        background: #fff;
+        border: 1px solid #ebedf0;
+        
+        thead {
+            background: #f7f8fa;
+            
+            th {
+                padding: 10px 8px;
+                font-size: 14px;
+                font-weight: 500;
+                color: #323233;
+                text-align: center;
+                border-bottom: 1px solid #ebedf0;
+                
+                &:first-child {
+                    text-align: left;
+                    padding-left: 16px;
+                }
+            }
+        }
+        
+        tbody {
+            tr {
+                border-bottom: 1px solid #ebedf0;
+                
+                &:last-child {
+                    border-bottom: none;
+                }
+                
+                td {
+                    padding: 10px 8px;
+                    font-size: 14px;
+                    color: #323233;
+                    text-align: center;
+                    vertical-align: middle;
+                    
+                    &.executor-name-cell {
+                        text-align: left;
+                        cursor: pointer;
+                        padding-left: 16px;
+                        
+                        .placeholder-text {
+                            color: #c8c9cc;
+                        }
+                    }
+                    
+                    &.plan-hours-cell {
+                        white-space: nowrap;
+                        width: 200px;
+                        
+                        .plan-hours-wrapper {
+                            display: flex;
+                            align-items: center;
+                            justify-content: center;
+                            gap: 5px;
+                            
+                            .hours-unit {
+                                flex-shrink: 0;
+                            }
+                        }
+                    }
+                    
+                    &.action-cell {
+                        width: 60px;
+                    }
+                }
+            }
+        }
+    }
+    
+    .executor-extra-info {
+        margin-top: 0.2rem;
+        border: 1px solid #ebedf0;
+        border-radius: 4px;
+        overflow: hidden;
+    }
+}
 .xinmingghao {
     overflow: hidden;
     text-overflow: ellipsis;