统计一段时间内,人员在线数量

统计一段时间内,人员在线数量

1.表格

(1)人员表

CREATE TABLE IF NOT EXISTS public.fd_operatives
(
    pid integer NOT NULL DEFAULT nextval('fd_operatives_pid_seq'::regclass),
    name character varying(16) COLLATE pg_catalog."default" NOT NULL DEFAULT ''::character varying,
    sex smallint NOT NULL DEFAULT 0,
    phone character varying COLLATE pg_catalog."default" NOT NULL DEFAULT ''::character varying,
    email character varying COLLATE pg_catalog."default" DEFAULT ''::character varying,
    remark character varying COLLATE pg_catalog."default" DEFAULT ''::character varying,
    createuser character varying COLLATE pg_catalog."default" DEFAULT ''::character varying,
    createtime timestamp without time zone NOT NULL DEFAULT now(),
    status character(1) COLLATE pg_catalog."default"
    CONSTRAINT fd_operatives_pidkey PRIMARY KEY (pid)
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS public.fd_operatives
    OWNER to postgres;

COMMENT ON TABLE public.fd_operatives
    IS '作业人员';

COMMENT ON COLUMN public.fd_operatives.name
    IS '名称';

COMMENT ON COLUMN public.fd_operatives.sex
    IS '性别(radio:1.男;2.女)';

COMMENT ON COLUMN public.fd_operatives.phone
    IS '手机号';

COMMENT ON COLUMN public.fd_operatives.email
    IS '邮箱';

COMMENT ON COLUMN public.fd_operatives.remark
    IS '备注';

COMMENT ON COLUMN public.fd_operatives.createuser
    IS '创建人';

COMMENT ON COLUMN public.fd_operatives.createtime
    IS '创建时间';

COMMENT ON COLUMN public.fd_operatives.status
    IS '打卡状态:1 上船 0 离船';

(2)打卡记录表

CREATE TABLE IF NOT EXISTS public.fd_operatives_sign
(
    pid integer NOT NULL DEFAULT nextval('fd_operatives_sign_pid_seq'::regclass),
    userid integer NOT NULL,
    createtime timestamp without time zone NOT NULL DEFAULT now(),
    out_in_type integer,
    index_code character varying(32) COLLATE pg_catalog."default",
    CONSTRAINT fd_operatives_sign_pidkey PRIMARY KEY (pid)
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS public.fd_operatives_sign
    OWNER to postgres;

COMMENT ON TABLE public.fd_operatives_sign
    IS '作业人员签到';

COMMENT ON COLUMN public.fd_operatives_sign.userid
    IS '作业人员的pid';

COMMENT ON COLUMN public.fd_operatives_sign.createtime
    IS '打卡时间';

COMMENT ON COLUMN public.fd_operatives_sign.out_in_type
    IS '进出类型(1:进 0:出 -1:未知)';

COMMENT ON COLUMN public.fd_operatives_sign.index_code
    IS '门禁唯一编码';

2.需求

(1)查询当前时间 和 过去6天,总计7天,这段时间内,每天人员的累计数量
(2)若有打卡记录,则计数
(3)员工可能连续工作,非每天打卡,只要打了上班卡,未打下班卡,则视为 打卡时间 到 目前为止该员工都在线,跨越的时间都需要计数

3.实现

实现类种的方法

@Override
    public List<FdCountConstructionData> countOnlineOperativesWeek(FdCountOperativesSignVo vo, HttpServletRequest request) {
        Date dateYMR = TimeUtils.getDateYMR();
        Date startTime = TimeUtils.addDate(dateYMR, -6);
        Date endTime = TimeUtils.addDate(dateYMR, 1);

        List<String> dateList = TimeUtils.getTimeIntervalStrList(TimeUtils.toLocalDateTime(startTime),TimeUtils.toLocalDateTime(endTime),1,"day");
        for (int i = 0; i < dateList.size(); i++) {
            String s = dateList.get(i);
            dateList.set(i,s.split(" ")[0]);
        }
        //去掉最后一个日期,最后一个日期为当天+1
        dateList.remove(dateList.size()-1);
        Map<String, Set<Integer>> map = new HashMap<>(dateList.size());
        for (String s : dateList) {
            map.put(s,new HashSet<>());
        }


        //打卡记录
        vo.setStartTime(startTime);
        vo.setEndTime(endTime);
        List<OperativesSignByStatisticsDto> dtos =  this.getBaseMapper().selectOperativesSignByStatistics(vo);


        Map<Integer, List<OperativesSignByStatisticsDto>> map_dtoId = dtos.stream().collect(Collectors.groupingBy(a -> a.getUserid()));
        Map<String, List<OperativesSignByStatisticsDto>> map_dtoDate = dtos.stream().collect(Collectors.groupingBy(a -> a.getDate()));


        for (int i = 0; i < dateList.size(); i++) {
            String s = dateList.get(i);

            Set<Integer> set = map.get(s);
            //若当天有打卡记录,则当天在线
            List<OperativesSignByStatisticsDto> operativesSignByStatisticsDtos = map_dtoDate.get(s);
            if (null == operativesSignByStatisticsDtos){
                continue;
            }
            Map<Integer, List<OperativesSignByStatisticsDto>> collect = operativesSignByStatisticsDtos.stream().collect(Collectors.groupingBy(a -> a.getUserid()));
            for (Integer id : collect.keySet()) {
                set.add(id);

                //若当天的最后一次打卡记录为 进入,则到下一次最近的一次 打卡记录,视为这段时间每天在线
                //若当天的最后一次打卡记录为 进入,且没有下次 打卡记录为 出,则视为该时间到目前位置,该人员每天在线
                OperativesSignByStatisticsDto dto = collect.get(id).stream().max(Comparator.comparing(OperativesSignByStatisticsDto::getCreatetime)).get();
                if (null != dto.getOutInType() && dto.getOutInType() == 1){

                    //是否到今天为止都是在线
                    Date startTime_zx = dto.getCreatetime();
                    Date endTime_zx = null;
                    if (i == dateList.size()-1){

                    }else {
                        Boolean wc = false;
                        for (int j = i+1; j <dateList.size(); j++) {
                            List<OperativesSignByStatisticsDto> os = map_dtoDate.get(dateList.get(j));
                            if (null == os){
                                continue;
                            }
                            Map<Integer, List<OperativesSignByStatisticsDto>> collect1 = os.stream().collect(Collectors.groupingBy(a -> a.getUserid()));
                            List<OperativesSignByStatisticsDto> jls = collect1.get(id);
                            if (null == jls){
                                continue;
                            }else {
                                List<OperativesSignByStatisticsDto> collect2 = jls.stream().sorted(Comparator.comparing(OperativesSignByStatisticsDto::getCreatetime)).collect(Collectors.toList());
                                for (OperativesSignByStatisticsDto jl : collect2) {
                                    if (jl.getOutInType() == 0){
                                        endTime_zx = jl.getCreatetime();
                                        wc = true;
                                        break;
                                    }
                                }
                            }
                            if (wc){
                                break;
                            }
                        }
                    }
                    if (null == endTime_zx){
                        endTime_zx = new Date();
                    }

                    //连续在线所在区间
                    List<String> dateList1 = TimeUtils.getTimeIntervalStrList(TimeUtils.toLocalDateTime(startTime_zx),TimeUtils.toLocalDateTime(endTime_zx),1,"day");
                    for (String s1 : dateList1) {
                        map.get(s1.split(" ")[0]).add(id);
                    }
                }
            }
        }



        //查询范围以外的记录
        List<OperativesSignByStatisticsDto> dtos_w =  this.getBaseMapper().selectOperativesSignByStatisticsOut(vo);
        for (OperativesSignByStatisticsDto d : dtos_w) {
            List<OperativesSignByStatisticsDto> ds = map_dtoId.get(d.getUserid());
            if (null == ds){
                //这里说明在统计时间以前就已经在线,从未下线
                for (String s : map.keySet()) {
                    map.get(s).add(d.getUserid());
                }
            }else {
                //找到最小的打卡记录
                OperativesSignByStatisticsDto min = ds.stream().min(Comparator.comparing(OperativesSignByStatisticsDto::getCreatetime)).get();
                //从记录外的时间 到 最小的打卡记录 直接的时间视为在线
                if (d.getCreatetime().getTime() < min.getCreatetime().getTime()){
                    List<String> day = TimeUtils.getTimeIntervalStrList(TimeUtils.toLocalDateTime(d.getCreatetime()), TimeUtils.toLocalDateTime(min.getCreatetime()), 1, "day");
                    for (String s : day) {
                        Set<Integer> set = map.get(s.split(" ")[0]);
                        if (null != set){
                            set.add(d.getUserid());
                        }
                    }
                }
            }
        }

        List<FdCountConstructionData> list = new ArrayList<>();
        for (String s : dateList) {
            FdCountConstructionData a = new FdCountConstructionData();
            a.setTime(s);
            a.setOperatives(map.get(s).size());
            a.setOs(new ArrayList<>(map.get(s)));
            list.add(a);
        }
        return list;

    }

mapper中的查询语句

<select id="selectOperativesSignByStatistics"
            resultType="com.maphao.windfarms.service.dto.ship.OperativesSignByStatisticsDto">
        select TO_CHAR(a.createtime,'yyyy-MM-dd') date,a.userid,a.out_in_type as outInType,a.createtime,b.status
        from fd_operatives_sign a
        join fd_operatives b on a.userid = b.pid
        where a.createtime &gt;= #{startTime} and a.createtime &lt; #{endTime}
    </select>
    <select id="selectOperativesSignByStatisticsOut"
            resultType="com.maphao.windfarms.service.dto.ship.OperativesSignByStatisticsDto">
        SELECT a.userid, TO_CHAR(a.createtime,'yyyy-MM-dd') date,a.createtime
        FROM fd_operatives_sign a
        INNER JOIN (
        SELECT userid, MAX(createtime) AS max_createtime
        FROM fd_operatives_sign
        GROUP BY userid
        ) b ON a.userid = b.userid AND a.createtime = b.max_createtime
        where a.out_in_type = 1 and a.createtime &lt; #{startTime}
    </select>

所用的实体类

@Data
public class FdCountOperativesSignVo {
    /**
     * 风电场fdid
     */
    private String fdid;
    /**
     * 打卡时间
     */
    private String punchInTime;

    /**
     * 统计类型
     * 0 默认 所有时间点 统计规则为累计数据
     * 1 最近的时间节点为当天,则改时间节点的数据为实时数据
     *      例如 当天为 2024-05-16 14:00:00,
     *          查询 2024-05-10 至 2024-05-16 数据时,2024-05-10 至 2024-05-15 数据为累计数据,2024-05-16 数据为实时数据
     *          查询当天数据时,2024-05-16 00:00:00 至 2024-05-16 13:30:00 数据为 累计数据,2024-05-16 14:00:00 数据为实时数据,2024-05-16 14:30:00至 2024-05-16 23:30:00 数据为空(为发生时间节点数据为空)
     */
    private Integer statisticsType = 0;

    private Date startTime;

    private Date endTime;

}
@Data
public class OperativesSignByStatisticsDto {

    /**
     * 人员id
     */
    private Integer userid;

    /**
     * 人员实时状态
     * 0 在船
     * 1 离船
     */
    private Integer status;

    /**
     * 打卡时间所在日期
     * 年月日
     */
    private String date;

    /**
     * 打卡时间
     */
    private Date createtime;

    /**
     * 打卡类型
     * 进出类型(1:进 0:出 -1:未知)
     */
    private Integer outInType;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FdCountConstructionData implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "时间")
    private String time;

    @ApiModelProperty(value = "施工船数量")
    private Integer constructionShip;

    @ApiModelProperty(value = "作业人员数量")
    private Integer operatives;

    /**
     * 在线人员 pid
     */
    private List<Integer> os;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值