1
0
Quellcode durchsuchen

超速、静止不动、断层、限制区域

daiyueteng vor 6 Jahren
Ursprung
Commit
9592561112

+ 70 - 0
module_service/module_area_entry_forbid.cpp

@@ -0,0 +1,70 @@
+#include"module_area_entry_forbid.h"
+
+#include<memory>
+
+#include "event.h"
+#include "area.h"
+#include"area_business.h"
+#include"log.h"
+#include"common_tool.h"
+
+struct forbid_data:business_data
+{
+    forbid_data()
+    {
+    }
+};
+
+void module_area_entry_forbid::on_enter(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    area_hover_ptr->m_data[index] = std::make_shared<forbid_data>();
+
+    EVENT_TYPE ev_type = ET_CARD_AREA_FORBIDDEN_PERSON;
+    if(card_ptr->is_vehicle())
+    {
+        ev_type = ET_CARD_AREA_FORBIDDEN_VEHICLE;
+    }
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ev_type, id, 0, 0, true);
+}
+
+void module_area_entry_forbid::on_hover(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+
+}
+
+void module_area_entry_forbid::on_leave(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    EVENT_TYPE ev_type = ET_CARD_AREA_FORBIDDEN_PERSON;
+    if(card_ptr->is_vehicle())
+    {
+        ev_type = ET_CARD_AREA_FORBIDDEN_VEHICLE;
+    }
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ev_type, id, 0, 0, false);
+
+    area_hover_ptr->m_data[index] = std::make_shared<forbid_data>();
+}
+
+
+
+
+
+
+

+ 31 - 0
module_service/module_area_entry_forbid.h

@@ -0,0 +1,31 @@
+#ifndef MODULE_AREA_ENTRY_FORBID_H
+#define MODULE_AREA_ENTRY_FORBID_H
+
+/**
+ * @brief 简要说明
+ * @author 戴月腾
+ * @date 2019-01-10
+ */
+
+
+#include "module_singleton_base.h"
+#include "card.h"
+
+
+
+class module_area_entry_forbid:public singleton_base<module_area_entry_forbid>
+{
+private:
+    friend class singleton_base<module_area_entry_forbid>;
+    module_area_entry_forbid()
+    {
+    }
+
+public:
+
+    void on_enter(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_hover(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_leave(std::shared_ptr<card_location_base> card_ptr, int index);
+};
+
+#endif // MODULE_AREA_ENTRY_FORBID_H

+ 112 - 0
module_service/module_area_over_speed.cpp

@@ -0,0 +1,112 @@
+#include"module_area_over_speed.h"
+
+#include<memory>
+#include<string>
+
+#include"area_business.h"
+#include"event.h"
+#include"log.h"
+#include"common_tool.h"
+#include"area.h"
+
+
+struct over_speed_data:business_data
+{
+    over_speed_data()
+    {
+        m_over_speed_count=0;
+        m_normal_speed_count=0;
+    }
+
+    int m_over_speed_count;
+    int m_normal_speed_count;
+};
+
+void module_area_over_speed::on_enter(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    area_hover_ptr->m_data[index] = std::make_shared<over_speed_data>();
+
+    double limit = area_hover_ptr->m_area->m_over_speed_vehicle;
+    if(limit < card_ptr->m_speed)
+    {
+        auto ptr = static_cast<over_speed_data*>(area_hover_ptr->m_data[index].get());
+        ptr->m_over_speed_count++;
+    }
+}
+
+void module_area_over_speed::on_hover(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+    auto ptr = static_cast<over_speed_data*>(area_hover_ptr->m_data[index].get());
+
+    double limit = area_hover_ptr->m_area->m_over_speed_vehicle;
+    if(limit < card_ptr->m_speed)//超速
+    {
+        ptr->m_over_speed_count++;
+    }
+    else//速度正常
+    {
+        ptr->m_normal_speed_count++;
+    }
+
+    //确定告警
+    if(SPEED_COUNT_LIMIT <= ptr->m_over_speed_count)
+    {
+        ptr->m_over_speed_count=SPEED_COUNT_LIMIT;
+
+        auto ev_ptr = event_list::instance()->get_event_card(card_ptr->m_id, card_ptr->m_type, ET_CARD_AREA_OVER_SPEED);
+        if(!ev_ptr)//从没有告警状态转化为告警状态
+        {
+            ptr->m_normal_speed_count=0;
+        }
+
+        uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+        event_tool::instance()->handle_event(OT_CARD, ET_CARD_AREA_OVER_SPEED, id, limit, card_ptr->m_speed, true);
+    }
+
+    //确定正常
+    if(SPEED_COUNT_LIMIT <= ptr->m_normal_speed_count)
+    {
+        ptr->m_normal_speed_count=SPEED_COUNT_LIMIT;
+
+        auto ev_ptr = event_list::instance()->get_event_card(card_ptr->m_id, card_ptr->m_type, ET_CARD_AREA_OVER_SPEED);
+        if(ev_ptr && !ev_ptr->is_end())
+        {
+            ptr->m_over_speed_count=0;
+
+            uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+            event_tool::instance()->handle_event(OT_CARD, ET_CARD_AREA_OVER_SPEED, id, limit, card_ptr->m_speed, false);
+        }
+    }
+}
+
+void module_area_over_speed::on_leave(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    double limit = area_hover_ptr->m_area->m_over_speed_vehicle;
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ET_CARD_AREA_OVER_SPEED, id, limit, card_ptr->m_speed, false);
+
+    area_hover_ptr->m_data[index] = std::make_shared<over_speed_data>();
+}
+
+

+ 36 - 0
module_service/module_area_over_speed.h

@@ -0,0 +1,36 @@
+#ifndef MODULE_AREA_OVER_SPEED_H
+#define MODULE_AREA_OVER_SPEED_H
+
+/**
+ * @brief 简要说明
+ * @author 戴月腾
+ * @date 2019-01-07
+ */
+
+#include <mutex>
+#include <map>
+#include <chrono>
+#include <boost/thread.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include "module_singleton_base.h"
+#include "card.h"
+
+
+///区域超速
+class module_area_over_speed:public singleton_base<module_area_over_speed>
+{
+private:
+    friend class singleton_base<module_area_over_speed>;
+    module_area_over_speed()
+    {
+    }
+
+public:
+    void on_enter(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_hover(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_leave(std::shared_ptr<card_location_base> card_ptr, int index);
+};
+
+
+#endif // MODULE_AREA_OVER_SPEED_H

+ 194 - 0
module_service/module_geofault.cpp

@@ -0,0 +1,194 @@
+#include"module_geofault.h"
+
+#include<memory>
+#include<string>
+
+#include"area_business.h"
+#include"event.h"
+#include"db_api/CDBSingletonDefine.h"
+#include"ya_setting.h"
+#include"common_tool.h"
+
+struct over_speed_data:business_data
+{
+    over_speed_data()
+    {
+        m_near_geofault_count=0;
+        m_far_geofault_count=0;
+    }
+
+    int m_near_geofault_count;
+    int m_far_geofault_count;
+};
+
+void module_geofault::module_geofault::on_enter(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+    area_hover_ptr->m_data[index] = std::make_shared<over_speed_data>();
+
+    double dist=0;
+    if(_is_near(area_hover_ptr->m_area, card_ptr->x, card_ptr->y, dist))
+    {
+        auto ptr = static_cast<over_speed_data*>(area_hover_ptr->m_data[index].get());
+        ptr->m_near_geofault_count++;
+    }
+}
+
+void module_geofault::on_hover(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+    auto ptr = static_cast<over_speed_data*>(area_hover_ptr->m_data[index].get());
+
+    double dist=0;
+    if(_is_near(area_hover_ptr->m_area, card_ptr->x, card_ptr->y, dist))
+    {
+        ptr->m_near_geofault_count++;
+    }
+    else
+    {
+        ptr->m_far_geofault_count++;
+    }
+
+    //确定告警
+    if(_geofault_count_limit <= ptr->m_near_geofault_count)
+    {
+        ptr->m_near_geofault_count=_geofault_count_limit;
+
+        auto ev_ptr = event_list::instance()->get_event_card(card_ptr->m_id, card_ptr->m_type, ET_VEHICLE_NEAR_GEOFAULT);
+        if(!ev_ptr)//从没有告警状态转化为告警状态
+        {
+            ptr->m_far_geofault_count=0;
+        }
+
+        uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+        event_tool::instance()->handle_event(OT_CARD, ET_VEHICLE_NEAR_GEOFAULT, id, CYaSetting::m_sys_setting.geofault_warn_dis, dist, true);
+    }
+
+    //确定正常
+    if(_geofault_count_limit <= ptr->m_far_geofault_count)
+    {
+        ptr->m_far_geofault_count=_geofault_count_limit;
+
+        auto ev_ptr = event_list::instance()->get_event_card(card_ptr->m_id, card_ptr->m_type, ET_VEHICLE_NEAR_GEOFAULT);
+        if(ev_ptr && !ev_ptr->is_end())
+        {
+            ptr->m_near_geofault_count=0;
+
+            uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+            event_tool::instance()->handle_event(OT_CARD, ET_VEHICLE_NEAR_GEOFAULT, id, CYaSetting::m_sys_setting.geofault_warn_dis, dist, false);
+        }
+    }
+}
+
+void module_geofault::on_leave(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ET_VEHICLE_NEAR_GEOFAULT, id, CYaSetting::m_sys_setting.geofault_warn_dis, 1000, false);
+
+    area_hover_ptr->m_data[index] = std::make_shared<over_speed_data>();
+}
+
+
+void module_geofault::module_geofault::init_geofault_from_db()
+{
+    const char *sql = "select area_id, pt_data from   dat_geofault g, dat_work_face w \
+            where g.workface_id=w.work_face_id;";
+    std::string Error;
+    YADB::CDBResultSet DBRes;
+    sDBConnPool.Query(sql,DBRes,Error);
+    if(!Error.empty())
+    {
+        log_error("init_geofault_from_db Error,%s",Error.c_str());
+        return;
+    }
+
+    uint64_t nCount = DBRes.GetRecordCount( Error );
+    if (static_cast<int64_t>(nCount) < 0)
+    {
+        log_error("错误,init_geofault_from_db. The record count=%ld\n", nCount );
+        return;
+    }
+
+    log_info( "init_geofault_from_db. The record count=%ld\n", nCount );
+
+    _area_geofault_map.clear();
+    while ( DBRes.GetNextRecod(Error) )
+    {
+        int area_id  = 0;
+        DBRes.GetField( "area_id",area_id, Error );
+
+        std::string pt_data;
+        DBRes.GetField( "pt_data",pt_data, Error );
+
+        std::vector<point> points;
+        std::vector<std::string> strs = split(pt_data,';');
+        for (const auto & s:strs)
+        {
+            std::vector<std::string> xy = split(s, ',');
+            if (xy.size()!=2)
+            {
+                continue;
+            }
+
+            point pt;
+            pt.x = std::atof(xy[0].c_str());
+            pt.y = std::atof(xy[1].c_str());
+
+            points.push_back(pt);
+        }
+
+        _area_geofault_map.insert({area_id,points});
+    }
+
+    for(const auto &p : _area_geofault_map)
+    {
+        auto kk = p.second;
+        std_debug("init_geofault_from_db:area_id:%d--points: %s",p.first, points2str(kk).c_str());
+        log_info("init_geofault_from_db:area_id:%d--points: %s",p.first, points2str(kk).c_str());
+    }
+}
+
+bool module_geofault::_is_near(std::shared_ptr<area>& area_ptr, double x, double y, double& out_dist)
+{
+    auto serch = _area_geofault_map.find(area_ptr->m_id);
+    if(serch == _area_geofault_map.end())
+    {
+        return false;
+    }
+
+    point pt(x, y);
+    double min=0;
+    out_dist=1000000;
+    for(auto& p : serch->second)
+    {
+        min = pt.dist(p) * area_ptr->m_scale;
+        if(min < out_dist)
+        {
+            out_dist = min;
+        }
+        if(min < CYaSetting::m_sys_setting.geofault_warn_dis)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+

+ 92 - 0
module_service/module_geofault.h

@@ -0,0 +1,92 @@
+#ifndef MODULE_GEOFAULT_H
+#define MODULE_GEOFAULT_H
+
+/**
+ * @brief 简要说明
+ * @author 戴月腾
+ * @date 2019-01-15
+ */
+
+#include <unordered_map>
+#include<vector>
+#include "module_singleton_base.h"
+#include "card.h"
+#include"area.h"
+#include"config_file.h"
+
+/**
+ * @brief 当采煤机和掘进机有数据点过来的时候,判断当前点与地址断层坐标点的距离d。如d<设置的阈值,则告警,d>阈值则取消。
+ */
+class module_geofault:public singleton_base<module_geofault>
+{
+private:
+    friend class singleton_base<module_geofault>;
+    module_geofault()
+    {
+    }
+
+public:
+    void on_enter(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_hover(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_leave(std::shared_ptr<card_location_base> card_ptr, int index);
+
+    void init(config_file& config)
+    {
+        _geofault_count_limit = std::stoi(config.get("service.geofault_count_limit","10"));
+    }
+
+    void init_geofault_from_db();
+
+private:
+    bool _is_near(std::shared_ptr<area>& area_ptr, double x, double y, double& out_dist);
+
+    static std::vector<std::string> split(const std::string& str, char tag)
+    {
+        std::vector<std::string>  arr;
+        std::string subStr;
+
+        for(size_t i = 0; i < str.length(); i++)
+        {
+            if(tag == str[i])
+            {
+                if(!subStr.empty())
+                {
+                    arr.push_back(subStr);
+                    subStr.clear();
+                }
+            }
+            else
+            {
+                subStr.push_back(str[i]);
+            }
+        }
+
+        if(!subStr.empty())
+        {
+            arr.push_back(subStr);
+        }
+
+        return arr;
+    }
+
+    static std::string points2str(std::vector<point>& points)
+    {
+        std::string str;
+        for(auto&p : points)
+        {
+            char ch[64] = {0};
+            sprintf(ch, "x=%f,y=%f;", p.x, p.y);
+            str.append(ch);
+        }
+
+        return str;
+    }
+
+private:
+    //area_id: points
+    std::unordered_map<int, std::vector<point>> _area_geofault_map;
+
+    int _geofault_count_limit;
+};
+
+#endif // MODULE_GEOFAULT_H

+ 80 - 0
module_service/module_i_thread.h

@@ -0,0 +1,80 @@
+#ifndef MODULE_I_THREAD_H
+#define MODULE_I_THREAD_H
+
+#include<atomic>
+#include<boost/thread.hpp>
+#include<mutex>
+//#include<log.h>
+
+/**
+ * @brief 线程接口类,重写run函数,改变睡眠时间 sleep_ms
+ */
+class i_thread
+{
+public:
+    i_thread()
+    {
+        sleep_ms=5*1000;
+    }
+
+    virtual ~i_thread(){}
+
+    /**
+     * @brief 启动线程
+     */
+    void start()
+    {
+        _thread_flag=true;
+
+        _thread_handler=boost::thread(&i_thread::thread_proc, this);
+    }
+
+    /**
+     * @brief 终止线程
+     */
+    void stop()
+    {
+        _thread_flag=false;
+        _thread_handler.interrupt();
+    }
+
+    ///线程睡眠时间 毫秒
+    std::atomic<int> sleep_ms;
+
+protected:
+    /// 互斥量
+    std::mutex _mutex;
+
+    /**
+     * @brief 线程函数
+     */
+    virtual void run(){}
+
+private:
+    /// 线程句柄
+    boost::thread _thread_handler;
+    /// 线程标志
+    std::atomic<bool> _thread_flag;
+
+    void thread_proc()
+    {
+        while(_thread_flag)
+        {
+            try
+            {
+                run();
+
+                boost::this_thread::sleep_for(boost::chrono::milliseconds(sleep_ms));
+            }
+            catch (boost::thread_interrupted&)
+            {
+            }
+            catch(std::exception&)
+            {
+                //log_error("thread_proc exception 结束线程 i_thread");
+            }
+        }
+    }
+};
+
+#endif // MODULE_I_THREAD_H

+ 113 - 0
module_service/module_motionless_persion.cpp

@@ -0,0 +1,113 @@
+#include"module_motionless_persion.h"
+
+
+#include"common_tool.h"
+#include"log.h"
+#include"area.h"
+#include"event.h"
+#include"tool_time.h"
+#include"area_business.h"
+
+
+struct motionless_data:business_data
+{
+    motionless_data()
+    {
+        m_acc_0count=0;
+        m_acc_start_time=0;
+    }
+
+    ///;检测到多少次之后定位完全静止
+    std::atomic<int> m_acc_0count;
+    ///检测到多久之后告警
+    time_t m_acc_start_time;
+};
+
+void module_motionless_persion::on_enter(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    area_hover_ptr->m_data[index] = std::make_shared<motionless_data>();
+}
+
+void module_motionless_persion::on_hover(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+    auto ptr = static_cast<motionless_data*>(area_hover_ptr->m_data[index].get());
+    if(0 == static_cast<int>(card_ptr->m_acc))
+    {
+        ptr->m_acc_0count++;
+    }
+    else
+    {
+        ptr->m_acc_0count=0;
+    }
+}
+
+void module_motionless_persion::on_leave(std::shared_ptr<card_location_base> card_ptr, int index)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ET_CARD_MOTIONLESS, id, 0, 0, false);
+
+    area_hover_ptr->m_data[index] = std::make_shared<motionless_data>();
+}
+
+void module_motionless_persion::deal_alarm(std::shared_ptr<card_location_base>& card_ptr)
+{
+    auto area_hover_ptr = card_ptr->get_area_hover();
+    if(!area_hover_ptr)
+    {
+        log_error("if(!area_hover_ptr)==true");
+        return;
+    }
+
+    auto arr = area_hover_ptr->m_data;
+    int index = 1;
+
+    if(arr.size()<2 || !arr[index])
+    {
+        return;
+    }
+
+    auto ptr = static_cast<motionless_data*>(area_hover_ptr->m_data[index].get());
+
+    if(ptr->m_acc_0count >= _acc_0count_limit)
+    {
+        ptr->m_acc_0count = _acc_0count_limit;
+        if(0 == ptr->m_acc_start_time)
+        {
+            ptr->m_acc_start_time = tool_time::now_to_seconds();
+        }
+    }
+    else
+    {
+        ptr->m_acc_start_time=0;
+    }
+
+    bool is_alarm = (0 != ptr->m_acc_start_time
+            &&tool_time::elapse_seconds(ptr->m_acc_start_time)> _acc_seconds_limit);
+
+    uint64_t id = tool_other::type_id_to_u64(card_ptr->m_type, card_ptr->m_id);
+    event_tool::instance()->handle_event(OT_CARD, ET_CARD_MOTIONLESS, id, 0, 0, is_alarm);
+}
+
+
+
+

+ 62 - 0
module_service/module_motionless_persion.h

@@ -0,0 +1,62 @@
+#ifndef MODULE_MOTIONLESS_PERSION_H
+#define MODULE_MOTIONLESS_PERSION_H
+
+/**
+ * @brief 简要说明
+ * @author 戴月腾
+ * @date 2019-01-12
+ */
+
+#include"module_singleton_base.h"
+#include"module_i_thread.h"
+#include"card.h"
+#include"config_file.h"
+
+/**
+ * @brief 一、硬件输出的状态
+当完全静止时人卡会连续发送 30 次定位数据,在该定位数据中的加速度状态为 0;发送
+完这一系列的定位数据之后进入休眠状态,不再发送任何定位数据。
+ 当人卡从静止切换到运动状态会在毫秒级完成。然后 2 秒后把定位数据发上来,此时加
+速度状态为 1(运动状态)。
+二、处理逻辑
+当连续收到 X(X 可以配置,X 建议不小于 10)次静止状态定位数据之后才认为完全静止。
+经过 Y(Y 可以配置)秒之后开始告警,只要收到运动状态的定位数据就认为非静止立刻取消
+告警
+ */
+class module_motionless_persion : public i_thread, public singleton_base<module_motionless_persion>
+{
+private:
+    friend class singleton_base<module_motionless_persion>;
+    module_motionless_persion()
+    {
+    }
+
+    int _acc_0count_limit;
+    int _acc_seconds_limit;
+
+    void run()
+    {
+        auto cardlist = card_list::instance()->m_map;
+        auto iter_m_map=cardlist.begin();
+        for(;iter_m_map!=cardlist.end();++iter_m_map)
+        {
+            deal_alarm(iter_m_map->second);
+        }
+    }
+
+    void deal_alarm(std::shared_ptr<card_location_base>& card_ptr);
+
+public:
+    void init(config_file& config)
+    {
+        sleep_ms = std::stoi(config.get("service.motionless_thread_sleep_ms","5000"));
+        _acc_0count_limit = std::stoi(config.get("service.motionless_acc_0count_limit","20"));
+        _acc_seconds_limit = std::stoi(config.get("service.motionless_acc_seconds_limit","120"));
+    }
+
+    void on_enter(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_hover(std::shared_ptr<card_location_base> card_ptr, int index);
+    void on_leave(std::shared_ptr<card_location_base> card_ptr, int index);
+};
+
+#endif // MODULE_MOTIONLESS_PERSION_H

+ 63 - 0
module_service/module_singleton_base.h

@@ -0,0 +1,63 @@
+#ifndef MODULE_SINGLETON_BASE_H
+#define MODULE_SINGLETON_BASE_H
+
+#include<mutex>
+
+template<typename T>
+class singleton_base
+{
+public:
+    static T *instance()
+    {
+        if(nullptr != _instance)
+        {
+            return _instance;
+        }
+
+        std::lock_guard<std::mutex> ll(_mutex_singleton_base);
+        if(nullptr == _instance)
+        {
+            _instance = new(std::nothrow) T();
+        }
+
+        return _instance;
+    }
+
+protected:
+    //使继承者无法public构造函数和析构函数
+    singleton_base(){}
+    //virtual ~singleton_base(){}
+private:
+    //禁止拷贝构造和赋值运算符
+    singleton_base(const singleton_base&){}
+    singleton_base &operator=(const singleton_base&){}
+
+    //它的唯一工作就是在析构函数中析构Singleton的实例,所以private
+    class Garbo
+    {
+    public:
+        ~Garbo()
+        {
+            if (singleton_base::_instance)
+            {
+                delete singleton_base::_instance;
+                singleton_base::_instance = nullptr;
+            }
+        }
+    };
+    //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数,我们不需要访问这个变量,所以不需要初始化
+    static Garbo garbo;
+
+    static T *_instance;
+    static std::mutex _mutex_singleton_base;
+};
+
+template<typename T>
+T *singleton_base<T>::_instance = nullptr;
+
+template<typename T>
+std::mutex singleton_base<T>::_mutex_singleton_base;
+
+
+
+#endif // MODULE_SINGLETON_BASE_H