Преглед изворни кода

考勤异常元数据更新

Heyuan пре 1 месец
родитељ
комит
d2f2c939b1

+ 4 - 0
configpage/scy/attendanceException.properties

@@ -0,0 +1,4 @@
+#发送考勤异常消息接口
+sendDingMsgUrl=http://10.0.6.222:8888/ehr/api/sendDingMsg
+# 推送考勤数据接口
+syncAttendanceDataUrl=http://10.0.6.222:8888/ehr/api/syncAttendanceData

BIN
configpage/三级菜单/考勤异常.zip


BIN
configpage/导入模板/中心负责人关系导入模板.zip


BIN
configpage/权限项/考勤异常.zip


BIN
configpage/视图/考勤异常/中心负责人.zip


BIN
configpage/视图/考勤异常/中心负责人导入模板组织过滤.zip


BIN
configpage/视图/考勤异常/考勤异常.zip


+ 9 - 9
metadata/com/kingdee/eas/custom/attendanceexception/bizEnum/PushTypeEnum.enum

@@ -42,21 +42,21 @@
         </rs>
         <rs key="bizEnum[com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum].enumValues.enumValue[CENTERLEADERREMINDER].alias">
             <lang locale="en_US" value="null" />
-            <lang locale="zh_CN" value="中心负责人提醒" />
-            <lang locale="zh_HK" value="中心負責人提醒" />
-            <lang locale="zh_TW" value="中心負責人提醒" />
+            <lang locale="zh_CN" value="中心考勤异常汇总" />
+            <lang locale="zh_HK" value="中心考勤異常匯總" />
+            <lang locale="zh_TW" value="中心考勤異常匯總" />
         </rs>
         <rs key="bizEnum[com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum].enumValues.enumValue[EMPLOYEEEXCEPTIONALERT].alias">
             <lang locale="en_US" value="null" />
-            <lang locale="zh_CN" value="员工累计异常提醒" />
-            <lang locale="zh_HK" value="員工累計異常提醒" />
-            <lang locale="zh_TW" value="員工累計異常提醒" />
+            <lang locale="zh_CN" value="员工考勤异常关怀" />
+            <lang locale="zh_HK" value="員工考勤異常關懷" />
+            <lang locale="zh_TW" value="員工考勤異常關懷" />
         </rs>
         <rs key="bizEnum[com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum].enumValues.enumValue[EMPLOYEEREMINDER].alias">
             <lang locale="en_US" value="null" />
-            <lang locale="zh_CN" value="员工提醒" />
-            <lang locale="zh_HK" value="員工提醒" />
-            <lang locale="zh_TW" value="員工提醒" />
+            <lang locale="zh_CN" value="提醒员工处理考勤" />
+            <lang locale="zh_HK" value="提醒員工處理考勤" />
+            <lang locale="zh_TW" value="提醒員工處理考勤" />
         </rs>
         <rs key="bizEnum[com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum].extendedProperty.userDefined">
             <lang locale="en_US" value="true" />

+ 8 - 0
sql/CreateTable.sql

@@ -5,3 +5,11 @@ Create Table CT_LOG_SyncLog ( FCreatorID VARCHAR(44),FCreateTime DateTime,FLastU
 -- 面谈记录表
 If not exists (select 1 from KSQL_USERTABLES where KSQL_TABNAME='CT_PER_InterviewRecord')
 Create Table CT_PER_InterviewRecord ( FCreatorID VARCHAR(44),FCreateTime DateTime,FLastUpdateUserID VARCHAR(44),FLastUpdateTime DateTime,FControlUnitID VARCHAR(44),FNumber NVARCHAR(80),FBizDate DateTime,FHandlerID VARCHAR(44),FDescription NVARCHAR(80),FHasEffected INT,FAuditorID VARCHAR(44),FSourceBillID NVARCHAR(80),FSourceFunction NVARCHAR(80),FID VARCHAR(44) DEFAULT '' NOT NULL ,CFInterviewTime DateTime,CFInterviewResult NCLOB(2000),CFInterviewerID VARCHAR(44),CFGradeLevel NVARCHAR(100),CFEvaResultID VARCHAR(44),CONSTRAINT CPK_PER_IntrvRIrht PRIMARY KEY (FID));
+
+
+-- 考勤异常提醒记录
+CREATE TABLE T_Remind_Record (
+    ID INT IDENTITY(1,1) PRIMARY KEY,  -- 自增主键
+    yearMonth VARCHAR(10) NOT NULL,
+    personNumber VARCHAR(50) NOT NULL
+);

+ 0 - 6
src/com/kingdee/eas/custom/attendanceexception/app/AttendanceExceptionLogControllerBean.java

@@ -1,11 +1,5 @@
 package com.kingdee.eas.custom.attendanceexception.app;
 
-import com.kingdee.bos.BOSException;
-import com.kingdee.bos.Context;
-import com.kingdee.bos.dao.IObjectPK;
-import com.kingdee.bos.dao.IObjectValue;
-import com.kingdee.eas.common.EASBizException;
-import com.kingdee.eas.custom.attendanceexception.AttendanceExceptionLogInfo;
 import org.apache.log4j.Logger;
 
 public class AttendanceExceptionLogControllerBean extends AbstractAttendanceExceptionLogControllerBean {

+ 0 - 1
src/com/kingdee/eas/custom/attendanceexception/app/CenterLeaderRelationControllerBean.java

@@ -18,7 +18,6 @@ import com.kingdee.eas.hr.emp.IPersonPosition;
 import com.kingdee.eas.hr.emp.PersonPositionCollection;
 import com.kingdee.eas.hr.emp.PersonPositionFactory;
 import com.kingdee.eas.hr.emp.PersonPositionInfo;
-import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 import com.kingdee.bos.*;

+ 3 - 3
src/com/kingdee/eas/custom/attendanceexception/bizEnum/PushTypeEnum.java

@@ -13,9 +13,9 @@ import com.kingdee.util.enums.StringEnum;
  */
 public class PushTypeEnum extends StringEnum
 {
-    public static final String EMPLOYEEREMINDER_VALUE = "1";//alias=员工提醒
-    public static final String EMPLOYEEEXCEPTIONALERT_VALUE = "2";//alias=员工累计异常提醒
-    public static final String CENTERLEADERREMINDER_VALUE = "3";//alias=中心负责人提醒
+    public static final String EMPLOYEEREMINDER_VALUE = "1";//alias=提醒员工处理考勤
+    public static final String EMPLOYEEEXCEPTIONALERT_VALUE = "2";//alias=员工考勤异常关怀
+    public static final String CENTERLEADERREMINDER_VALUE = "3";//alias=中心考勤异常汇总
 
     public static final PushTypeEnum EMPLOYEEREMINDER = new PushTypeEnum("EMPLOYEEREMINDER", EMPLOYEEREMINDER_VALUE);
     public static final PushTypeEnum EMPLOYEEEXCEPTIONALERT = new PushTypeEnum("EMPLOYEEEXCEPTIONALERT", EMPLOYEEEXCEPTIONALERT_VALUE);

+ 3 - 3
src/com/kingdee/eas/custom/attendanceexception/bizEnum/PushTypeEnum.properties

@@ -1,3 +1,3 @@
-EMPLOYEEREMINDER=\u5458\u5DE5\u63D0\u9192
-EMPLOYEEEXCEPTIONALERT=\u5458\u5DE5\u7D2F\u8BA1\u5F02\u5E38\u63D0\u9192
-CENTERLEADERREMINDER=\u4E2D\u5FC3\u8D1F\u8D23\u4EBA\u63D0\u9192
+EMPLOYEEREMINDER=\u63D0\u9192\u5458\u5DE5\u5904\u7406\u8003\u52E4
+EMPLOYEEEXCEPTIONALERT=\u5458\u5DE5\u8003\u52E4\u5F02\u5E38\u5173\u6000
+CENTERLEADERREMINDER=\u4E2D\u5FC3\u8003\u52E4\u5F02\u5E38\u6C47\u603B

+ 3 - 3
src/com/kingdee/eas/custom/attendanceexception/bizEnum/PushTypeEnum_l2.properties

@@ -1,3 +1,3 @@
-EMPLOYEEREMINDER=\u5458\u5DE5\u63D0\u9192
-EMPLOYEEEXCEPTIONALERT=\u5458\u5DE5\u7D2F\u8BA1\u5F02\u5E38\u63D0\u9192
-CENTERLEADERREMINDER=\u4E2D\u5FC3\u8D1F\u8D23\u4EBA\u63D0\u9192
+EMPLOYEEREMINDER=\u63D0\u9192\u5458\u5DE5\u5904\u7406\u8003\u52E4
+EMPLOYEEEXCEPTIONALERT=\u5458\u5DE5\u8003\u52E4\u5F02\u5E38\u5173\u6000
+CENTERLEADERREMINDER=\u4E2D\u5FC3\u8003\u52E4\u5F02\u5E38\u6C47\u603B

+ 3 - 3
src/com/kingdee/eas/custom/attendanceexception/bizEnum/PushTypeEnum_l3.properties

@@ -1,3 +1,3 @@
-EMPLOYEEREMINDER=\u54E1\u5DE5\u63D0\u9192
-EMPLOYEEEXCEPTIONALERT=\u54E1\u5DE5\u7D2F\u8A08\u7570\u5E38\u63D0\u9192
-CENTERLEADERREMINDER=\u4E2D\u5FC3\u8CA0\u8CAC\u4EBA\u63D0\u9192
+EMPLOYEEREMINDER=\u63D0\u9192\u54E1\u5DE5\u8655\u7406\u8003\u52E4
+EMPLOYEEEXCEPTIONALERT=\u54E1\u5DE5\u8003\u52E4\u7570\u5E38\u95DC\u61F7
+CENTERLEADERREMINDER=\u4E2D\u5FC3\u8003\u52E4\u7570\u5E38\u532F\u7E3D

+ 529 - 217
src/com/kingdee/eas/custom/attendanceexception/task/AttendanceExceptionFacadeControllerBean.java

@@ -1,20 +1,23 @@
 package com.kingdee.eas.custom.attendanceexception.task;
 
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.kingdee.eas.basedata.person.IPerson;
-import com.kingdee.eas.basedata.person.PersonCollection;
-import com.kingdee.eas.basedata.person.PersonFactory;
-import com.kingdee.eas.basedata.person.PersonInfo;
+import com.kingdee.bos.metadata.entity.*;
+import com.kingdee.eas.basedata.org.AdminOrgUnitCollection;
+import com.kingdee.eas.basedata.org.AdminOrgUnitFactory;
+import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
+import com.kingdee.eas.basedata.org.IAdminOrgUnit;
 import com.kingdee.eas.custom.attendanceexception.*;
-import com.kingdee.eas.custom.attendanceexception.bean.DingMsgBean;
 import com.kingdee.eas.custom.attendanceexception.bean.SyncAttendanceDataBean;
 import com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum;
 import com.kingdee.eas.fi.arap.util.DBUtil;
+import com.kingdee.eas.hr.ats.AttendanceFileCollection;
+import com.kingdee.eas.hr.ats.AttendanceFileFactory;
+import com.kingdee.eas.hr.ats.AttendanceFileInfo;
+import com.kingdee.eas.hr.ats.IAttendanceFile;
 import com.kingdee.eas.hr.ats.util.AtsDateUtils;
 import com.kingdee.jdbc.rowset.IRowSet;
+import com.kingdee.shr.base.syssetting.CallStatusEnum;
 import com.kingdee.util.DateTimeUtils;
 import okhttp3.MediaType;
 import okhttp3.OkHttpClient;
@@ -26,6 +29,7 @@ import org.apache.log4j.Logger;
 import com.kingdee.bos.*;
 import com.kingdee.eas.common.EASBizException;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.String;
 import java.math.BigDecimal;
@@ -35,20 +39,35 @@ import java.text.SimpleDateFormat;
 import java.util.*;
 
 public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceExceptionFacadeControllerBean {
-    private static Logger logger =
-            Logger.getLogger(AttendanceExceptionFacadeControllerBean.class);
+    private static Logger logger = Logger.getLogger(AttendanceExceptionFacadeControllerBean.class);
+    private Properties propt = new Properties();
     //通知员工个人消息模板
-    private static final String NOTIFYEMPLOYEEMSGTEMPLATE = "您在{0}出现考勤异常!";
+    //private static final String NOTIFYEMPLOYEEMSGTEMPLATE = "##### <font color=#6192f2>HR系统</font>\\n#### 考勤异常提醒:\\n您在{0}出现考勤异常,请及时处理 \\n###### (如有审批中的假勤单据,请及时催办)";
     //通知员工个人消息标题
-    private static final String NOTIFYEMPLOYEEMSGTitle = "【考勤异常提醒】";
+    //private static final String NOTIFYEMPLOYEEMSGTITLE = "【考勤异常提醒】";
     //通知员工个人消息模板
-    private static final String NOTIFYEMPLOYEECUMULATIVEMSGTEMPLATE = "您在{0}考勤异常次数以达到{1}次,请您注意本月考勤!";
+    //private static final String NOTIFYEMPLOYEECUMULATIVEMSGTEMPLATE = "##### <font color=#6192f2>HR系统</font>\\n#### 员工考勤提醒:\\n您在{0}考勤异常次数已经达到{1}次,请您注意本月考勤 \\n###### (如有审批中的假勤单据,请及时催办)";
     //通知员工个人消息标题
-    private static final String NOTIFYEMPLOYEECUMULATIVEMSGTitle = "【员工考勤提醒】";
-    //通知员工个人消息模板
-//    private static final String NOTIFYEMPLOYEECUMULATIVEMSGTEMPLATE = "您在{0}考勤异常次数以达到{1}次,请您注意本月考勤!";
-//    //通知员工个人消息标题
-//    private static final String NOTIFYEMPLOYEECUMULATIVEMSGTitle = "【员工考勤提醒】";
+    //private static final String NOTIFYEMPLOYEECUMULATIVEMSGTITLE = "【员工考勤提醒】";
+    //通知提醒中心负责人异常消息模板
+    //private static final String NOTIFYALERTLEADEREXCEPTIONMSGTEMPLATE = "##### <font color=#6192f2>HR系统</font>\\n#### 中心考勤异常周报:\\n#####时间:{0}-{1}\\n#####内容:{2}考勤人数{3}人,考勤异常人数{4}人,迟到{5}人,早退{6}人,旷工{7}人 \\n###### (如有审批中的假勤单据,请及时催办)";
+    //通知提醒中心负责人异常消息标题
+    //private static final String NOTIFYALERTLEADEREXCEPTIONMSGTITLE = "【考勤异常周报】";
+
+    //来源标识
+    private static final String SOURCE = "EHR";
+
+
+    public AttendanceExceptionFacadeControllerBean() throws BOSException {
+        String syncOAConfigPath = System.getProperty("EAS_HOME") + "/server/properties/scy/attendanceException.properties";
+        try {
+            propt.load(new FileInputStream(syncOAConfigPath));
+        } catch (IOException e) {
+            e.printStackTrace();
+            String errorMsg = "获取配置文件报错,请检查配置:" + syncOAConfigPath + "   " + e.getMessage();
+            throw new BOSException(errorMsg);
+        }
+    }
 
     /**
      * 员工个人异常提醒
@@ -64,19 +83,46 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
             logger.info("AttendanceExceptionFacadeControllerBean.notifyEmployeeException start");
         }
         super._notifyEmployeeException(ctx);
-        //1.查询异常数据
+        IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
+        PushTypeEnum pushTypeEnum = PushTypeEnum.EMPLOYEEREMINDER;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
         //昨天
         Date preDay = AtsDateUtils.getPreDay(new Date());
-        //getAttendanceExceptionData(ctx, preDay, preDay);
-        //2.调用接口给对应员工发送异常预警消息
-
-
-        String msgId = UUID.randomUUID().toString();
-        String content = MessageFormat.format(NOTIFYEMPLOYEEMSGTEMPLATE, msgId);
-        DingMsgBean dingMsgBean = new DingMsgBean(msgId, NOTIFYEMPLOYEEMSGTitle, content, "");
-
-
-        //3.保存消息记录
+        logger.error("_notifyEmployeeCumulativeException preDay: " + sdf.format(preDay));
+        //1.查询异常数据
+        Map<String, List<SyncAttendanceDataBean>> exceptionData = getAttendanceExceptionData(ctx, preDay, preDay, pushTypeEnum, 0);
+        String yearMonthDay = DateTimeUtils.format(preDay, "yyyy年MM月dd日");
+        for (String personNumber : exceptionData.keySet()) {
+            String msgId = UUID.randomUUID().toString();
+            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
+            logInfo.setMessageId(msgId);
+            logInfo.setPushType(pushTypeEnum);
+            try {
+                //发送异常消息
+                JSONObject dingMsgBean = new JSONObject();
+                dingMsgBean.put("msgTempCode", "work_notice_03");
+                dingMsgBean.put("toAllUser", false);
+                dingMsgBean.put("userIdList", personNumber);
+                dingMsgBean.put("source", SOURCE);
+                JSONObject param = new JSONObject();
+                //消息id
+                param.put("msgId", msgId);
+                //时间
+                param.put("time", yearMonthDay);
+                dingMsgBean.put("param", param);
+                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
+                //推送异常数据
+                List<SyncAttendanceDataBean> syncAttendanceDataBeans = exceptionData.get(personNumber);
+                syncAttendanceDataBeans.stream().forEach(syncAttendanceDataBean -> {
+                    syncAttendanceDataBean.setMsgId(msgId);
+                });
+                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
+            } catch (Exception e) {
+                logger.error("员工个人异常提醒报错", e);
+            }
+            //保存消息记录
+            iAttendanceExceptionLog.save(logInfo);
+        }
         if (logger.isInfoEnabled()) {
             long endTime = System.currentTimeMillis();
             float duration = (endTime - startTime) / 1000f;
@@ -85,6 +131,8 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
     }
 
     /**
+     * 员工考勤异常关怀提醒
+     *
      * @param ctx
      * @param exceptionLimit 异常次数上限
      * @throws BOSException
@@ -105,30 +153,53 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
             limit = Integer.parseInt(exceptionLimit);
         }
         IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
-        AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
-        //推送类型为员工累计异常提醒
-        logInfo.setPushType(PushTypeEnum.EMPLOYEEEXCEPTIONALERT);
-        String msgId = UUID.randomUUID().toString();
-        logInfo.setMessageId(msgId);
-        //1.查询异常数据
+        PushTypeEnum pushTypeEnum = PushTypeEnum.EMPLOYEEEXCEPTIONALERT;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
         Date today = new Date();
         //当前月第一天
         Date currentFirstDay = AtsDateUtils.getCurrentFirstDay(today);
+        logger.error("_notifyEmployeeCumulativeException currentFirstDay: " + sdf.format(currentFirstDay));
         //昨天
         Date preDay = AtsDateUtils.getPreDay(today);
-        //getAttendanceExceptionData(ctx, currentFirstDay, preDay);
-        String yearMonth = DateTimeUtils.format(today, "yyyy年M月");
-        String content = MessageFormat.format(NOTIFYEMPLOYEECUMULATIVEMSGTEMPLATE, yearMonth, limit);
-
-        //2.调用接口给对应员工发送异常预警消息
-        DingMsgBean dingMsgBean = new DingMsgBean(msgId, NOTIFYEMPLOYEECUMULATIVEMSGTitle, content, "");
-
-        //3.保存消息记录
-
-//        attendanceExceptionLogInfo.setMessageResponse("");
-//        attendanceExceptionLogInfo.setMessageRequest("");
-
-
+        logger.error("_notifyEmployeeCumulativeException preDay: " + sdf.format(preDay));
+        //查询异常数据
+        Map<String, List<SyncAttendanceDataBean>> exceptionData = getAttendanceExceptionData(ctx, currentFirstDay, preDay, pushTypeEnum, 0);
+        String yearMonth = DateTimeUtils.format(today, "yyyy年MM月");
+        for (String personNumber : exceptionData.keySet()) {
+            String msgId = UUID.randomUUID().toString();
+            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
+            logInfo.setMessageId(msgId);
+            logInfo.setPushType(pushTypeEnum);
+            try {
+                //发送异常消息
+                JSONObject dingMsgBean = new JSONObject();
+                dingMsgBean.put("msgTempCode", "work_notice_02");
+                dingMsgBean.put("toAllUser", false);
+                dingMsgBean.put("userIdList", personNumber);
+                dingMsgBean.put("source", SOURCE);
+                JSONObject param = new JSONObject();
+                //消息id
+                param.put("msgId", msgId);
+                //时间
+                param.put("time", yearMonth);
+                //考勤异常人数
+                param.put("eorNum", limit);
+                dingMsgBean.put("param", param);
+                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
+                //推送异常数据
+                List<SyncAttendanceDataBean> syncAttendanceDataBeans = exceptionData.get(personNumber);
+                syncAttendanceDataBeans.stream().forEach(syncAttendanceDataBean -> {
+                    syncAttendanceDataBean.setMsgId(msgId);
+                });
+                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
+                //写入提醒记录
+                addRemindRecord(ctx, yearMonth, personNumber);
+            } catch (Exception e) {
+                logger.error("提醒员工累计异常报错: " + e.getMessage(), e);
+            }
+            //保存消息记录
+            iAttendanceExceptionLog.save(logInfo);
+        }
         if (logger.isInfoEnabled()) {
             long endTime = System.currentTimeMillis();
             float duration = (endTime - startTime) / 1000f;
@@ -136,6 +207,14 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
         }
     }
 
+
+    /**
+     * 提醒中心负责人累计异常
+     *
+     * @param ctx
+     * @throws BOSException
+     * @throws EASBizException
+     */
     @Override
     protected void _alertLeaderExceptionTotal(Context ctx) throws BOSException, EASBizException {
         long startTime = System.currentTimeMillis();
@@ -143,10 +222,16 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
             logger.info("AttendanceExceptionFacadeControllerBean.alertLeaderExceptionTotal start");
         }
         super._alertLeaderExceptionTotal(ctx);
+        IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
         //中心负责人关系表
         ICenterLeaderRelation iCenterLeaderRelation = CenterLeaderRelationFactory.getLocalInstance(ctx);
         //获取中心负责人
         Map<String, Set<String>> leaders = iCenterLeaderRelation.getLeaders();
+        //获取各中心考勤人数
+        Map<String, Integer> attendanceCountMap = getAttendanceCount(ctx);
+        //获取中心名称
+        Map<String, String> orgMap = getOrgMap(ctx);
+        PushTypeEnum pushTypeEnum = PushTypeEnum.CENTERLEADERREMINDER;
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
         //获取考勤异常数据,本周周一至周五中心考勤异常数据
         Calendar calendar = Calendar.getInstance();
@@ -160,22 +245,88 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
             endDate = calendar.getTime();
         }
         logger.error("_alertLeaderExceptionTotal endDate: " + sdf.format(endDate));
-
-        //getAttendanceExceptionData(ctx, monday, endDate);
-
-        String url = "http://10.0.6.222:8888/ehr/api/syncAttendanceData";
-
-        //pushAttendanceExceptionData(ctx, url, );
-
-        //推送异常信息
-        //sendAttendanceExceptionMsg(ctx);
-        //推送异常数据
+        //1.查询异常数据
+        Map<String, Map<String, Integer>> exceptionCountMap = new HashMap<>();
+        Map<String, List<SyncAttendanceDataBean>> exceptionData = getAttendanceExceptionDataForLeader(ctx, monday, endDate, exceptionCountMap);
+        String mondayFormat = DateTimeUtils.format(monday, "yyyy年MM月dd日");
+        String endDateFormat = DateTimeUtils.format(endDate, "yyyy年MM月dd日");
+        for (String centerNumber : exceptionData.keySet()) {
+            String msgId = UUID.randomUUID().toString();
+            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
+            logInfo.setMessageId(msgId);
+            logInfo.setPushType(pushTypeEnum);
+            try {
+                Set<String> alertUserSet = leaders.get(centerNumber);
+                String orgName = orgMap.getOrDefault(centerNumber, "中心");
+                //中心负责人
+                String alertUsers = convertSetToString(alertUserSet);
+                if (StringUtils.isBlank(alertUsers)) {
+                    throw new BOSException(orgName + "的负责人为空!");
+                }
+                //中心考勤总人数
+                Integer attendanceCount = attendanceCountMap.getOrDefault(centerNumber, 0);
+                Map<String, Integer> orgExceptionTimes = exceptionCountMap.get(centerNumber);
+                //迟到人数
+                Integer lateEmployees = orgExceptionTimes.getOrDefault("lateEmployees", 0);
+                //早退人数
+                Integer earlyLeaveEmployees = orgExceptionTimes.getOrDefault("earlyLeaveEmployees", 0);
+                //旷工人数
+                Integer absentEmployees = orgExceptionTimes.getOrDefault("absentEmployees", 0);
+                //个人原因补卡人数
+                //Integer personalRecheckCountEmployees = orgExceptionTimes.getOrDefault("personalRecheckCountEmployees", 0);
+                //异常人数
+                Integer exceptionEmployees = orgExceptionTimes.getOrDefault("exceptionEmployees", 0);
+                //消息内容
+//                String content = MessageFormat.format(NOTIFYALERTLEADEREXCEPTIONMSGTEMPLATE,
+//                        mondayFormat,
+//                        endDateFormat,
+//                        orgName,
+//                        attendanceCount,
+//                        exceptionEmployees,
+//                        lateEmployees,
+//                        earlyLeaveEmployees,
+//                        absentEmployees
+//                );
+                //发送异常消息
+                JSONObject dingMsgBean = new JSONObject();
+                dingMsgBean.put("msgTempCode", "work_notice_01");
+                dingMsgBean.put("toAllUser", false);
+                dingMsgBean.put("userIdList", alertUsers);
+                dingMsgBean.put("source", SOURCE);
+                JSONObject param = new JSONObject();
+                //消息id
+                param.put("msgId", msgId);
+                //时间
+                param.put("time", mondayFormat + "-" + endDateFormat);
+                //中心考勤人数
+                param.put("centerNum", attendanceCount);
+                //考勤异常人数
+                param.put("eorNum", exceptionEmployees);
+                //迟到人数
+                param.put("lateNum", lateEmployees);
+                //早退人数
+                param.put("earlyNum", earlyLeaveEmployees);
+                //旷工人数
+                param.put("hookyNum", absentEmployees);
+                dingMsgBean.put("param", param);
+                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
+                //推送异常数据
+                List<SyncAttendanceDataBean> syncAttendanceDataBeans = exceptionData.get(centerNumber);
+                syncAttendanceDataBeans.stream().forEach(syncAttendanceDataBean -> {
+                    syncAttendanceDataBean.setMsgId(msgId);
+                });
+                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
+            } catch (Exception e) {
+                logger.error("提醒中心负责人累计异常报错", e);
+            }
+            //保存消息记录
+            iAttendanceExceptionLog.save(logInfo);
+        }
         if (logger.isInfoEnabled()) {
             long endTime = System.currentTimeMillis();
             float duration = (endTime - startTime) / 1000f;
             logger.info(String.format("AttendanceExceptionFacadeControllerBean.alertLeaderExceptionTotal end, duration: %fS", duration));
         }
-
     }
 
     /**
@@ -184,17 +335,17 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
      * @param ctx
      * @param startDate 开始日期
      * @param endDate   结束日期
+     * @return
      * @throws BOSException
      * @throws EASBizException
      */
-    protected void getAttendanceExceptionData(
+    protected Map<String, List<SyncAttendanceDataBean>> getAttendanceExceptionData(
             Context ctx,
             Date startDate,
             Date endDate,
-            String msgId,
             PushTypeEnum pushType,
             int limit
-    ) throws BOSException, EASBizException {
+    ) throws BOSException {
         String sql = getSql(startDate, endDate);
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         try {
@@ -204,43 +355,10 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
             if (!PushTypeEnum.CENTERLEADERREMINDER.equals(pushType)) {
                 //非中心负责人提醒
                 while (iRowSet.next()) {
-                    SyncAttendanceDataBean data = new SyncAttendanceDataBean();
-                    data.setMsgId(msgId);
-                    String personNumber = iRowSet.getString("personNumber");
-                    data.setEmployeeId(personNumber);
-                    data.setEmployeeName(iRowSet.getString("personName"));
-                    Date attenceDate = iRowSet.getDate("attenceDate");
-                    if (attenceDate != null) {
-                        data.setExceptionDate(sdf.format(attenceDate));
-                    }
-                    data.setDepartmentCode(iRowSet.getString("adminOrgNumber"));
-                    data.setDepartmentName(iRowSet.getString("adminOrgName"));
-                    data.setDepartmentManagerCode(iRowSet.getString("adminOrgLongNumber"));
-                    data.setDepartmentSortCode(iRowSet.getString("sortCode"));
-                    data.setDepartmentManagerName(iRowSet.getString("displayName"));
-                    //String admintwoNumber = iRowSet.getString("admintwoNumber");
-                    //String admintwoName = iRowSet.getString("admintwoName");
-                    StringBuilder attendanceResult = new StringBuilder();
-                    int times = 0;
-                    Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
-                    int s19 = iRowSet.getInt("s19");
-                    int s21 = iRowSet.getInt("s21");
-                    BigDecimal s23 = iRowSet.getBigDecimal("s23");
-                    int s113 = iRowSet.getInt("s113");
-                    attendanceFlags.put("迟到", s19 > 0);
-                    attendanceFlags.put("早退", s21 > 0);
-                    attendanceFlags.put("旷工", s23.compareTo(BigDecimal.ZERO) > 0);
-                    attendanceFlags.put("个人原因补卡次数", s113 > 0);
-                    for (Map.Entry<String, Boolean> entry : attendanceFlags.entrySet()) {
-                        if (entry.getValue()) {
-                            times++;
-                            attendanceResult.append(entry.getKey()).append("、");
-                        }
-                    }
-                    // 移除最后一个顿号
-                    if (attendanceResult.length() > 0) {
-                        attendanceResult.setLength(attendanceResult.length() - 1);
-                    }
+                    //设置考勤结果和次数
+                    SyncAttendanceDataBean data = setAttendanceResult(iRowSet, sdf);
+                    int times = data.getTimes();
+                    String personNumber = data.getEmployeeId();
                     //累计员工期间总异常次数
                     if (personExceptionTimes.containsKey(personNumber)) {
                         Integer i = personExceptionTimes.get(personNumber);
@@ -248,72 +366,163 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
                     } else {
                         personExceptionTimes.put(personNumber, times);
                     }
-                    data.setTimes(times);
-                    data.setAttendanceResult(attendanceResult.toString());
                     if (!result.containsKey(personNumber)) {
                         result.put(personNumber, new ArrayList<>());
                     }
                     result.get(personNumber).add(data);
                 }
                 if (PushTypeEnum.EMPLOYEEEXCEPTIONALERT.equals(pushType)) {
+                    String yearMonth = DateTimeUtils.format(startDate, "yyyy年M月");
+                    //获取提醒记录
+                    Set<String> remindRecord = getRemindRecord(ctx, yearMonth);
                     //员工累计异常提醒
                     for (Map.Entry<String, Integer> entry : personExceptionTimes.entrySet()) {
-                        if (entry.getValue() < limit) {
-                            //移除没有达到预警上限的数据
+                        if (entry.getValue() < limit || remindRecord.contains(entry.getKey())) {
+                            //移除没有达到预警上限的数据,获取已经提醒过的人员
                             result.remove(entry.getKey());
                         }
                     }
                 }
-            } else {
-                while (iRowSet.next()) {
-                    SyncAttendanceDataBean data = new SyncAttendanceDataBean();
-                    data.setMsgId(msgId);
-                    String personNumber = iRowSet.getString("personNumber");
-                    data.setEmployeeId(personNumber);
-                    data.setEmployeeName(iRowSet.getString("personName"));
-                    Date attenceDate = iRowSet.getDate("attenceDate");
-                    if (attenceDate != null) {
-                        data.setExceptionDate(sdf.format(attenceDate));
-                    }
-                    data.setDepartmentCode(iRowSet.getString("adminOrgNumber"));
-                    data.setDepartmentName(iRowSet.getString("adminOrgName"));
-                    data.setDepartmentManagerCode(iRowSet.getString("adminOrgLongNumber"));
-                    data.setDepartmentSortCode(iRowSet.getString("sortCode"));
-                    data.setDepartmentManagerName(iRowSet.getString("displayName"));
-                    String admintwoNumber = iRowSet.getString("admintwoNumber");
-                    StringBuilder attendanceResult = new StringBuilder();
-                    int times = 0;
-                    Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
-                    int s19 = iRowSet.getInt("s19");
-                    int s21 = iRowSet.getInt("s21");
-                    BigDecimal s23 = iRowSet.getBigDecimal("s23");
-                    int s113 = iRowSet.getInt("s113");
-                    attendanceFlags.put("迟到", s19 > 0);
-                    attendanceFlags.put("早退", s21 > 0);
-                    attendanceFlags.put("旷工", s23.compareTo(BigDecimal.ZERO) > 0);
-                    attendanceFlags.put("个人原因补卡次数", s113 > 0);
-                    for (Map.Entry<String, Boolean> entry : attendanceFlags.entrySet()) {
-                        if (entry.getValue()) {
-                            times++;
-                            attendanceResult.append(entry.getKey()).append("、");
+            }
+            return result;
+        } catch (SQLException e) {
+            logger.error(e.getMessage(), e);
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * 获取中心考勤异常数据
+     *
+     * @param ctx
+     * @param startDate 开始日期
+     * @param endDate   结束日期
+     * @return
+     * @throws BOSException
+     * @throws EASBizException
+     */
+    protected Map<String, List<SyncAttendanceDataBean>> getAttendanceExceptionDataForLeader(
+            Context ctx,
+            Date startDate,
+            Date endDate,
+            Map<String, Map<String, Integer>> exceptionCountMap
+    ) throws BOSException {
+        String sql = getSql(startDate, endDate);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Map<String, Map<String, Set<String>>> exceptionData = new HashMap<>();
+        try {
+            IRowSet iRowSet = DBUtil.executeQuery(ctx, sql);
+            Map<String, List<SyncAttendanceDataBean>> result = new HashMap<>();
+            while (iRowSet.next()) {
+                //设置考勤结果和次数
+                SyncAttendanceDataBean data = setAttendanceResult(iRowSet, sdf);
+                //中心编码
+                String admintwoNumber = iRowSet.getString("admintwoNumber");
+                String personNumber = data.getEmployeeId();
+                Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
+                int s19 = iRowSet.getInt("s19");
+                int s21 = iRowSet.getInt("s21");
+                BigDecimal s23 = iRowSet.getBigDecimal("s23");
+                int s113 = iRowSet.getInt("s113");
+                attendanceFlags.put("lateEmployees", s19 > 0);//迟到
+                attendanceFlags.put("earlyLeaveEmployees", s21 > 0);//早退
+                attendanceFlags.put("absentEmployees", s23.compareTo(BigDecimal.ZERO) > 0);//旷工
+                attendanceFlags.put("personalRecheckCountEmployees", s113 > 0);//个人原因补卡
+                Map<String, Set<String>> exceptionPersonMap = null;
+                if (exceptionData.containsKey(admintwoNumber)) {
+                    exceptionPersonMap = exceptionData.get(admintwoNumber);
+                } else {
+                    exceptionPersonMap = new HashMap<>();
+                    exceptionData.put(admintwoNumber, exceptionPersonMap);
+                }
+                Set<String> exceptionEmployees = exceptionPersonMap.get("exceptionEmployees");
+                if (exceptionEmployees == null) {
+                    exceptionEmployees = new HashSet<>();
+                    exceptionPersonMap.put("exceptionEmployees", exceptionEmployees);
+                }
+                exceptionEmployees.add(personNumber);
+                for (Map.Entry<String, Boolean> entry : attendanceFlags.entrySet()) {
+                    if (entry.getValue()) {
+                        Set<String> set = exceptionPersonMap.get(entry.getKey());
+                        if (set == null) {
+                            set = new HashSet<>();
+                            exceptionPersonMap.put(entry.getKey(), set);
                         }
+                        set.add(personNumber);
                     }
-                    // 移除最后一个顿号
-                    if (attendanceResult.length() > 0) {
-                        attendanceResult.setLength(attendanceResult.length() - 1);
-                    }
-                    data.setTimes(times);
-                    data.setAttendanceResult(attendanceResult.toString());
-                    if (!result.containsKey(admintwoNumber)) {
-                        result.put(admintwoNumber, new ArrayList<>());
-                    }
-                    result.get(admintwoNumber).add(data);
                 }
+                if (!result.containsKey(admintwoNumber)) {
+                    result.put(admintwoNumber, new ArrayList<>());
+                }
+                result.get(admintwoNumber).add(data);
             }
+            for (String orgNumber : exceptionData.keySet()) {
+                Map<String, Set<String>> orgExceptionData = exceptionData.get(orgNumber);
+                Map<String, Integer> orgExceptionTimes = new HashMap<>();
+                //迟到人数
+                orgExceptionTimes.put("lateEmployees", orgExceptionData.get("lateEmployees").size());
+                //早退人数
+                orgExceptionTimes.put("earlyLeaveEmployees", orgExceptionData.get("earlyLeaveEmployees").size());
+                //旷工人数
+                orgExceptionTimes.put("absentEmployees", orgExceptionData.get("absentEmployees").size());
+                //个人原因补卡人数
+                orgExceptionTimes.put("personalRecheckCountEmployees", orgExceptionData.get("personalRecheckCountEmployees").size());
+                //异常人数
+                orgExceptionTimes.put("exceptionEmployees", orgExceptionData.get("exceptionEmployees").size());
+                exceptionCountMap.put(orgNumber, orgExceptionTimes);
+            }
+            return result;
         } catch (SQLException e) {
+            logger.error(e.getMessage(), e);
             throw new RuntimeException(e);
         }
+    }
 
+    /**
+     * 设置考勤结果和次数
+     *
+     * @param iRowSet
+     * @param sdf
+     * @throws SQLException
+     */
+    protected SyncAttendanceDataBean setAttendanceResult(IRowSet iRowSet, SimpleDateFormat sdf) throws SQLException {
+        SyncAttendanceDataBean data = new SyncAttendanceDataBean();
+        data.setEmployeeId(iRowSet.getString("personNumber"));
+        data.setEmployeeName(iRowSet.getString("personName"));
+        Date attenceDate = iRowSet.getDate("attenceDate");
+        if (attenceDate != null) {
+            data.setExceptionDate(sdf.format(attenceDate));
+        }
+        data.setDepartmentCode(iRowSet.getString("adminOrgNumber"));
+        data.setDepartmentName(iRowSet.getString("adminOrgName"));
+        data.setDepartmentManagerCode(iRowSet.getString("adminOrgLongNumber"));
+        data.setDepartmentSortCode(iRowSet.getString("sortCode"));
+        data.setDepartmentManagerName(iRowSet.getString("displayName"));
+        StringBuilder attendanceResult = new StringBuilder();
+        int times = 0;
+        Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
+        int s19 = iRowSet.getInt("s19");
+        int s21 = iRowSet.getInt("s21");
+        BigDecimal s23 = iRowSet.getBigDecimal("s23");
+        int s113 = iRowSet.getInt("s113");
+        attendanceFlags.put("迟到", s19 > 0);
+        attendanceFlags.put("早退", s21 > 0);
+        attendanceFlags.put("旷工", s23.compareTo(BigDecimal.ZERO) > 0);
+        attendanceFlags.put("个人原因补卡次数", s113 > 0);
+        for (Map.Entry<String, Boolean> entry : attendanceFlags.entrySet()) {
+            if (entry.getValue()) {
+                times++;
+                attendanceResult.append(entry.getKey()).append("、");
+            }
+        }
+        // 移除最后一个顿号
+        if (attendanceResult.length() > 0) {
+            attendanceResult.setLength(attendanceResult.length() - 1);
+        }
+        data.setTimes(times);
+        data.setAttendanceResult(attendanceResult.toString());
+        return data;
     }
 
     /**
@@ -349,14 +558,14 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
                 .append("    adminOrg.FLongNumber as adminOrgLongNumber,").append("\n")
                 .append("    adminOrg.FSortCode as sortCode,").append("\n")
                 .append("    adminOrg.FDisplayName_L2 as displayName,").append("\n")
-                .append("    admintow.fid as admintowId,").append("\n")
-                .append("    admintow.fnumber as admintowNumber,").append("\n")
-                .append("    admintow.Fname_l2 as admintowName").append("\n")
+                .append("    admintwo.fid as admintwoId,").append("\n")
+                .append("    admintwo.fnumber as admintwoNumber,").append("\n")
+                .append("    admintwo.Fname_l2 as admintwoName").append("\n")
                 .append("from").append("\n")
                 .append("    T_HR_ATS_AttendanceResult attendanceResult").append("\n")
                 .append("    left join t_bd_person person on person.fid = attendanceResult.FProposerID").append("\n")
                 .append("    left join T_ORG_admin adminOrg on attendanceResult.FAdminOrgUnitID = adminOrg.fid").append("\n")
-                .append("    left join T_ORG_admin admintow on adminOrg.FLevelTwoGroupID = admintow.fid").append("\n")
+                .append("    left join T_ORG_admin admintwo on adminOrg.FLevelTwoGroupID = admintwo.fid").append("\n")
                 .append("where").append("\n")
                 .append("    attendanceResult.FAttenceDate >= { TS '").append(sdf.format(startDate)).append("' }").append("\n")
                 .append("    and attendanceResult.FAttenceDate <= { TS '").append(sdf.format(endDate)).append("' }").append("\n")
@@ -366,38 +575,41 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
                 .append("        or attendanceResult.s23 > 0").append("\n")
                 .append("         or attendanceResult.S113 > 0").append("\n")
                 .append("    );").append("\n");
+        if (logger.isInfoEnabled()) {
+            logger.info(String.format("AttendanceExceptionFacadeControllerBean.getSql: %s", sql.toString()));
+        }
         return sql.toString();
     }
 
     /**
      * 发送考勤异常消息
      *
-     * @param ctx
+     * @param dingMsgBean
+     * @param logInfo
      * @throws BOSException
-     * @throws EASBizException
      */
     protected void sendAttendanceExceptionMsg(
-            Context ctx,
-            String url
-    ) throws BOSException, EASBizException {
-
+            JSONObject dingMsgBean,
+            AttendanceExceptionLogInfo logInfo
+    ) throws BOSException {
         try {
-//            if (list == null || list.size() <= 0) {
-//                logger.error("pushAttendanceExceptionData list is null");
-//                throw new BOSException("pushAttendanceExceptionData list is null");
-//            }
+            String url = propt.getProperty("sendDingMsgUrl");
             if (url == null || url.isEmpty()) {
                 logger.error("pushAttendanceExceptionData url is null");
                 throw new BOSException("pushAttendanceExceptionData url is null");
             }
-//            String params = JSON.toJSONString(list);
-            //String url = "http://10.0.6.222:8888/ehr/api/syncAttendanceData";
+            logger.error("pushAttendanceExceptionData url: " + url);
+            if (dingMsgBean == null) {
+                logger.error("pushAttendanceExceptionData dingMsgBean is null");
+                throw new BOSException("pushAttendanceExceptionData dingMsgBean is null");
+            }
+            String params = dingMsgBean.toJSONString();
+            logInfo.setMessageRequest(params);
             OkHttpClient client = new OkHttpClient();
-
             MediaType mediaType = MediaType.parse("application/json");
-            RequestBody body = RequestBody.create(mediaType, "{\r\n    \"msgId\": \"test_msg_id_12322\",\r\n    \"title\": \"考勤异常通知测试\",\r\n    \"content\": \"##### <font color=#6192f2>HR系统</font>\\n#### 员工考勤提醒:\\n您在2025年3月考勤异常次数已经达到5次,请您注意本月考勤 \\n###### (如有审批中的假勤单据,请及时催办)\",\r\n    \"toAllUser\": false,\r\n    \"alertUser\": \"SCY003987\",\r\n    \"alertType\": 2\r\n}");
+            RequestBody body = RequestBody.create(mediaType, params);
             Request request = new Request.Builder()
-                    .url("http://10.0.6.222:8888/ehr/api/sendDingMsg")
+                    .url(url)
                     .post(body)
                     .addHeader("Accept", "*/*")
                     .addHeader("Accept-Encoding", "gzip, deflate, br")
@@ -405,38 +617,27 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
                     .addHeader("Connection", "keep-alive")
                     .addHeader("Content-Type", "application/json")
                     .build();
-
             Response response = client.newCall(request).execute();
             logger.error("response----" + response.isSuccessful());
             if (response.isSuccessful()) {
-                //ObjectMapper mapper = new ObjectMapper();
                 String resultBody = response.body().string();
+                logInfo.setMessageResponse(resultBody);
                 logger.error("resultBody----" + resultBody);
                 JSONObject result = JSONObject.parseObject(resultBody);
-                logger.error("respMap----" + result);
                 if (result.getBoolean("success")) {
-                    //                    String data = result.get("data").toString();
-                    //                    JSONArray jsonArray = JSONArray.parseArray(data);
-                    //                    logger.error("jsonArray---" + jsonArray.toString());
-                    //                    logger.error("jsonArray---" + jsonArray.size());
-                    //                    IPerson iPerson = PersonFactory.getLocalInstance(ctx);
-                    //                    PersonCollection personCollection = iPerson.getPersonCollection("select number ");
-                    //                    Set set = new HashSet();
-                    //                    for (int i = 0; i < personCollection.size(); i++) {
-                    //                        PersonInfo personInfo = personCollection.get(i);
-                    //                        set.add(personInfo.getNumber().toString());
-                    //                    }
-                    //                    for (int i = 0; i < jsonArray.size(); i++) {
-                    //                        JSONObject resultData = jsonArray.getJSONObject(i);
-                    //                        //保存门禁打卡记录
-                    //                    }
+                    logInfo.setPushStatus(CallStatusEnum.success);
                 } else {
                     //推送失败
-                    String msg = result.getString("msg");
+                    throw new BOSException(result.getString("msg"));
                 }
+            } else {
+                throw new BOSException("接口请求超时");
             }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            logInfo.setPushStatus(CallStatusEnum.failure);
+            logInfo.setPushResult("发送考勤异常消息报错: " + e.getMessage());
+            throw new BOSException(e);
         }
     }
 
@@ -444,27 +645,27 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
     /**
      * 推送考勤异常数据
      *
-     * @param ctx
-     * @param msgId 消息id
+     * @param list
+     * @param logInfo
      * @throws BOSException
-     * @throws EASBizException
      */
     protected void pushAttendanceExceptionData(
-            Context ctx,
-            String url,
-            List list
-    ) throws BOSException, EASBizException {
+            List list,
+            AttendanceExceptionLogInfo logInfo
+    ) throws BOSException {
         try {
-            if (list == null || list.size() <= 0) {
-                logger.error("pushAttendanceExceptionData list is null");
-                throw new BOSException("pushAttendanceExceptionData list is null");
-            }
+            String url = propt.getProperty("syncAttendanceDataUrl");
             if (url == null || url.isEmpty()) {
                 logger.error("pushAttendanceExceptionData url is null");
                 throw new BOSException("pushAttendanceExceptionData url is null");
             }
+            logger.error("pushAttendanceExceptionData url: " + url);
+            if (list == null || list.size() <= 0) {
+                logger.error("pushAttendanceExceptionData list is null");
+                throw new BOSException("pushAttendanceExceptionData list is null");
+            }
             String params = JSON.toJSONString(list);
-            //String url = "http://10.0.6.222:8888/ehr/api/syncAttendanceData";
+            logInfo.setDataPushRequest(params);
             OkHttpClient client = new OkHttpClient();
             MediaType mediaType = MediaType.parse("application/json");
             RequestBody body = RequestBody.create(mediaType, params);
@@ -478,40 +679,151 @@ public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceE
                     .addHeader("Content-Type", "application/json")
                     .build();
             Response response = client.newCall(request).execute();
-            logger.error("response----" + response.isSuccessful());
             if (response.isSuccessful()) {
-                //ObjectMapper mapper = new ObjectMapper();
                 String resultBody = response.body().string();
+                logInfo.setDataPushResponse(resultBody);
                 logger.error("resultBody----" + resultBody);
                 JSONObject result = JSONObject.parseObject(resultBody);
-                logger.error("respMap----" + result);
                 if (result.getBoolean("success")) {
-//                    String data = result.get("data").toString();
-//                    JSONArray jsonArray = JSONArray.parseArray(data);
-//                    logger.error("jsonArray---" + jsonArray.toString());
-//                    logger.error("jsonArray---" + jsonArray.size());
-//                    IPerson iPerson = PersonFactory.getLocalInstance(ctx);
-//                    PersonCollection personCollection = iPerson.getPersonCollection("select number ");
-//                    Set set = new HashSet();
-//                    for (int i = 0; i < personCollection.size(); i++) {
-//                        PersonInfo personInfo = personCollection.get(i);
-//                        set.add(personInfo.getNumber().toString());
-//                    }
-//                    for (int i = 0; i < jsonArray.size(); i++) {
-//                        JSONObject resultData = jsonArray.getJSONObject(i);
-//                        //保存门禁打卡记录
-//                    }
+                    logInfo.setPushStatus(CallStatusEnum.success);
                 } else {
                     //推送失败
-                    String msg = result.getString("msg");
+                    throw new BOSException(result.getString("msg"));
                 }
+            } else {
+                throw new BOSException("接口请求超时");
             }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            logInfo.setPushStatus(CallStatusEnum.failure);
+            logInfo.setPushResult("推送考勤数据报错: " + e.getMessage());
+            throw new BOSException(e);
+        }
+    }
 
-        } catch (IOException e) {
-            logger.error("pushAttendanceExceptionData start", e);
+    /**
+     * set转字符串
+     *
+     * @param set
+     * @return
+     */
+    public String convertSetToString(Set set) {
+        if (set != null && set.size() > 0) {
+            Iterator iter = set.iterator();
+            StringBuffer sql = new StringBuffer();
+            while (iter.hasNext()) {
+                sql.append(iter.next()).append(",");
+            }
+            sql.deleteCharAt(sql.length() - 1);
+            return sql.toString();
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * 获取各个中心考勤总人数
+     *
+     * @param ctx
+     * @return
+     */
+    public Map<String, Integer> getAttendanceCount(Context ctx) {
+        Map<String, Integer> attendanceCountMap = new HashMap<>();
+        try {
+            IAttendanceFile iAttendanceFile = AttendanceFileFactory.getLocalInstance(ctx);
+            FilterInfo filterInfo = new FilterInfo();
+            FilterItemCollection filterItems = filterInfo.getFilterItems();
+            filterItems.add(new FilterItemInfo("attendFileState", "1"));
+            SelectorItemCollection sic = new SelectorItemCollection();
+            sic.add("adminOrgUnit.levelTwoGroup.number");
+            EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
+            AttendanceFileCollection attendanceFileCol = iAttendanceFile.getAttendanceFileCollection(viewInfo);
+            for (int i = 0; i < attendanceFileCol.size(); i++) {
+                AttendanceFileInfo attendanceFileInfo = attendanceFileCol.get(i);
+                String number = attendanceFileInfo.getAdminOrgUnit().getLevelTwoGroup().getNumber();
+                if (attendanceCountMap.containsKey(number)) {
+                    Integer i1 = attendanceCountMap.get(number);
+                    attendanceCountMap.put(number, i1 + 1);
+                } else {
+                    attendanceCountMap.put(number, 1);
+                }
+            }
+        } catch (BOSException e) {
+            logger.error("获取各个中心考勤总人数报错: " + e.getMessage(), e);
             throw new RuntimeException(e);
         }
+        return attendanceCountMap;
     }
 
 
+    /**
+     * 获取中心名称
+     *
+     * @param ctx
+     * @return
+     */
+    public Map<String, String> getOrgMap(Context ctx) {
+        Map<String, String> orgMap = new HashMap<>();
+        try {
+            IAdminOrgUnit iAdminOrgUnit = AdminOrgUnitFactory.getLocalInstance(ctx);
+            FilterInfo filterInfo = new FilterInfo();
+            FilterItemCollection filterItems = filterInfo.getFilterItems();
+            //组织层级为一级组织
+            filterItems.add(new FilterItemInfo("unitLayerType", "00000000-0000-0000-0000-00000000000362824988"));
+            filterItems.add(new FilterItemInfo("isSealUp", "0"));
+            SelectorItemCollection sic = new SelectorItemCollection();
+            sic.add("number");
+            sic.add("name");
+            EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
+            AdminOrgUnitCollection adminOrgUnitCol = iAdminOrgUnit.getAdminOrgUnitCollection(viewInfo);
+            for (int i = 0; i < adminOrgUnitCol.size(); i++) {
+                AdminOrgUnitInfo adminOrgUnitInfo = adminOrgUnitCol.get(i);
+                String number = adminOrgUnitInfo.getNumber();
+                String name = adminOrgUnitInfo.getName();
+                orgMap.put(number, name);
+            }
+        } catch (Exception e) {
+            logger.error("获取中心名称报错: " + e.getMessage(), e);
+            throw new RuntimeException(e);
+        }
+        return orgMap;
+    }
+
+    /**
+     * 获取提醒记录
+     *
+     * @param ctx
+     * @param yearMonth
+     * @return
+     */
+    private Set<String> getRemindRecord(Context ctx, String yearMonth) {
+        Set<String> remindRecordSet = new HashSet<>();
+        try {
+            String querySql = "select personNumber from T_Remind_Record where yearMonth=?";
+            IRowSet iRowSet = DBUtil.executeQuery(ctx, querySql, new Object[]{yearMonth});
+            while (iRowSet.next()) {
+                remindRecordSet.add(iRowSet.getString("personNumber"));
+            }
+        } catch (Exception e) {
+            logger.error("获取提醒记录报错: " + e.getMessage(), e);
+            throw new RuntimeException(e);
+        }
+        return remindRecordSet;
+    }
+
+    /**
+     * 新增提醒记录
+     *
+     * @param ctx
+     * @param yearMonth
+     */
+    private void addRemindRecord(Context ctx, String yearMonth, String personNumber) {
+        try {
+            String querySql = "insert into T_Remind_Record(yearMonth,personNumber) values (?,?)";
+            DBUtil.execute(ctx, querySql, new Object[]{yearMonth, personNumber});
+        } catch (Exception e) {
+            logger.error("新增提醒记录报错: " + e.getMessage(), e);
+            throw new RuntimeException("新增提醒记录报错: " + e.getMessage());
+        }
+    }
 }