有关 签到/签退 业务逻辑 的梳理与学习

  导言

     最近搞到了个签到管理,其中的业务逻辑感觉有点复杂(可能是我的方向不对),虽然是实现了,不过代码和逻辑很多,也有些乱,想趁着还记得逻辑来记录梳理一下,看看自己以后有没有更好的思路,或者有大佬有思路也可以在评论指导一下,非常感谢( ̄▽ ̄)!

 业务

    签到可以有时间段限制,一天可以有多段可签到时间(如9:00到12:00,15:00到18:00...),签退不能超过最大签到时间,也不能跨时间段签到)。

 逻辑

  由于可签到时间段我是按一天来想,所以格式是从一天的零点算起到当天的24:结束,所以下面的一些逻辑和实现也参照这个来。

    签到:

    这个比较简单,可以拿个bool变量IsInSignInTime 开始为假,判断当前签到时间是否在签到时间段里,直接拿到存数据库的时间段列表来循环判断就行,如果当前时间既大于可签到时间段开始时间又小于结束时间的话,就说明在可签到时间段里反之直接返回前端错误。

    签退:

    签退除了前端传的数据有误之外不管是 超过最大签到时间 还是 跨时间段 都是可以直接签退成功的,就是有上面两种情况的就要把本次签到的时间记为零

   1.跨时间段 

    由于上面在创建签到时做了限制,如果有可签到时间段,那最大签到时间不能超过24小时(如果超24小时的话肯定会跨时间段的)。所以签退只需考虑签到时间为一天以内的情况,有以下两种状态:

 1)签退跨时间段,但是没跨天

  这样直接和签到的逻辑差不多,拿个bool变量,如果跨了时间段就把其变真,后面做个置零判断。

  2)签退跨天,但是没跨可签到时间段

  如果有签到时间段:

这样还要在1)的循环中作判断,看有没有这样从今天晚上12点之前到明天凌晨0点的时间段,如果有的话就额外判断用户的签到时间段在不在这里面。在的话就不能判为跨时间。

C#代码实现

说明:

签到记录的时间是按分钟来记的,时间段的比较是用了C#的TimeOnly来比。里面有点注释掉的代码,不影响实现。

#region 签到记录接口/// <summary>/// 签到定义/// </summary>/// <returns></returns>[HttpPost][Authorization]public IActionResult Create([FromBody] SignInOrSignOutDto parm){var signIn = _signInService.GetId(parm.SignInID);if (_signInService.Any(m => m.SignInNo == signIn.SignInNo && m.Enable == false)){return toResponse(StatusCodeType.Error, $"该签到未启用,不能签到!");}//签到启用//没有同一条签到记录//在签到时间段//存在同一签到记录且状态为1的签到记录if (_signInRecordService.Any(m => m.SignInID == parm.SignInID && m.UserID == parm.UserID && m.Status == 1)){return toResponse(StatusCodeType.Error, $"不能重复签到!");}//不在签到时间段//从中拿到签到时间段// 将JSON字符串反序列化为List<SignInPeriods>对象列表var signInPeriodsList = JsonConvert.DeserializeObject<List<SignInPeriodsDto>>(signIn.SignInPeriods);TimeOnly currentTime = TimeOnly.FromDateTime(DateTime.Now);//拿个变量在循环里,如果当前时间在签到时间段就为真,反之为假bool IsInSignInTime = false;//循环比较判断foreach(SignInPeriodsDto signInPeriod in signInPeriodsList){if(signInPeriod.StartTime < currentTime&& signInPeriod.EndTime > currentTime){//在里面变真IsInSignInTime = true;}}//为假就是不在签到时间段,返回错误if (!IsInSignInTime){return toResponse(StatusCodeType.Error, $"不在签到时间段!");}try{var signInRecord = parm.Adapt<Base_SignInRecord>().ToCreate(_tokenManager.GetSessionInfo());signInRecord.Status = 1;signInRecord.StartTime = DateTime.Now;_unitOfWork.BeginTran();//新增签到记录表var response = _signInRecordService.Add(signInRecord);//改签到表对应签到的当前签到人数_signInService.Update(m => m.ID == parm.SignInID, m => new Base_SignIn(){CurrentSignInNum = signIn.CurrentSignInNum + 1,});//改用户-签到表对应用户状态为在线/签到_signInUsersService.Update(m => m.SignInNo == signIn.SignInNo && m.UserID == parm.UserID, m => new Base_SignIn_Users(){IsOnline = true});_unitOfWork.CommitTran();return toResponse(response);}catch (Exception){_unitOfWork.RollbackTran();throw;}}/// <summary>/// 签退定义/// </summary>/// <returns></returns>[HttpPost][Authorization]public IActionResult Delete([FromBody] SignInOrSignOutDto parm){//拿到数据var signIn = _signInService.GetId(parm.SignInID);var signInRecord = _signInRecordService.GetFirst(m => m.SignInID == signIn.ID && m.UserID == parm.UserID && m.Status == 1);if (_signInService.Any(m => m.SignInNo == signIn.SignInNo && m.Enable == false)){return toResponse(StatusCodeType.Error, $"该签到未启用,不能签退!");}//不做数的 体现在Time字段上//超出最大签到时间的//横跨签到时间段的//算出签到时间TimeDateTime currentTimeForDateTime = DateTime.Now;var TimePeriod = currentTimeForDateTime - signInRecord.StartTime;var currentTime = TimeOnly.FromDateTime(currentTimeForDateTime);测试 可删算出签到时间Time//DateTime currentTimeForDateTime = new DateTime(2024, 9, 24, 07, 49, 15);//var TimePeriod = currentTimeForDateTime - signInRecord.StartTime;var currentTime = TimeOnly.FromDateTime(currentTimeForDateTime);//TimeOnly currentTime = TimeOnly.Parse("07:49:15");int  Time = (int)TimePeriod.TotalMinutes;//签到提示信息,如果签到没问题就直接输成功var remindMessager = "成功";//从中拿到签到时间段// 将JSON字符串反序列化为List<SignInPeriods>对象列表var signInPeriodsList = JsonConvert.DeserializeObject<List<SignInPeriodsDto>>(signIn.SignInPeriods);//看是否超了最大时间if (Time > signIn.MaxSignInTime && signIn.MaxSignInTime != 0){Time = 0;remindMessager = "签到时间超出最大签到时间,本次签到时间置零!";}//如果是开了可签到时间段if (!string.IsNullOrEmpty(signIn.SignInPeriods)){直接拿开始时间和现在时间做判断,看其是这个时间段是否在某一时间段里面,其他不满足的都是跨时间段的//if (Time < 1440)//没隔天 一天的分钟计数//{//把签到记录表的开始签到时间转成TimeOnlyvar StartTime = TimeOnly.FromDateTime(signInRecord.StartTime);//拿个变量在循环里,如果时间段没跨签到时间段就为真,反之为假bool IsInSignInTime = false;//看有没有开始时间为0:00的时间段和结束时间为24:00的时间段SignInPeriodsDto todayPeriod = null; //结束时间为24:00的时间段SignInPeriodsDto nextDayPeriod = null;//开始时间为0:00的时间段//循环比较判断foreach (SignInPeriodsDto signInPeriod in signInPeriodsList){if (signInPeriod.StartTime < StartTime && signInPeriod.EndTime > currentTime){//在里面变真IsInSignInTime = true;}if (signInPeriod.StartTime == TimeOnly.MinValue) //看其开始时间段是否为为0:00{nextDayPeriod = signInPeriod;}if (signInPeriod.EndTime == new TimeOnly(23, 59, 59)) //看其结束时间段是否为为24:00{todayPeriod = signInPeriod;}}//有的话看开始签到时间是否在大于结束时间为24:00的时间段里   及  签退时间是否在在开始时间为0:00的时间段里//不满足条件的直接判跨时间段if (todayPeriod != null && nextDayPeriod != null){   //可以考虑将跨天取消掉,分别判是否在签到时间段里和单独看是否在跨天时间段里就行//可以在添加签到时加个判断,如过加了时间段,那最大时间就不能出现超过24小时的情况,//可以免除上面签到和签退时间隔天了还在同一签到时间段的情况if(todayPeriod.StartTime< StartTime&& nextDayPeriod.EndTime >currentTime){IsInSignInTime = true;}}//如果没设置最大签到时间但是设置了时间段//只判断其有没有超时间段,在关键判断那看其签到时间是不是超了一天// Time > 1440由于上面已经验证了有没有时间段,所以到这的都是有时间段的,不用额外判断了if (!IsInSignInTime|| Time > 1440)//跨时间段了{Time = 0;remindMessager = "横跨时间段,本次签到时间置零!";}//}}//至此留下了符合条件的try{var userSession = _tokenManager.GetSessionInfo();_unitOfWork.BeginTran();//改签到记录表状态为 签退,补上签到时间Timevar response = _signInRecordService.Update(m => m.SignInID == signIn.ID && m.UserID == parm.UserID && m.Status == 1, m => new Base_SignInRecord(){Status = 0,EndTime = currentTimeForDateTime,Time = Time,});//改签到表在线签到人数-1_signInService.Update(m => m.ID == parm.SignInID, m => new Base_SignIn(){CurrentSignInNum = signIn.CurrentSignInNum - 1,UpdateID = userSession.UserID,UpdateName = userSession.UserName,UpdateTime = DateTime.Now});//改 用户-签到表对应用户状态为离线/签退_signInUsersService.Update(m => m.SignInNo == signIn.SignInNo && m.UserID == parm.UserID,m=> new Base_SignIn_Users(){IsOnline = false});_unitOfWork.CommitTran();return toResponse(StatusCodeType.Success, remindMessager);}catch (Exception){_unitOfWork.RollbackTran();throw;}}#endregion

结语

   这个搞了有些久,还是怕有些情况没考虑,不过接口是考虑到的情况都测试通过了的。想着还有没有更优雅,更便捷的解决方法,不管是从业务开始考虑,还是从我这方法开始优化,那就看以后的我有没有时间看了,或者各位大佬指点一下,我会很开心的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/54634.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C#]winform 使用opencvsharp实现玉米粒计数

【算法介绍】 这段代码是使用OpenCvSharp库&#xff08;OpenCV的C#封装&#xff09;对图像进行处理&#xff0c;主要流程包括图像的二值化、腐蚀操作、距离变换、轮廓检测&#xff0c;并在原图上标出检测到的轮廓位置及数量。下面是对代码的详细解读&#xff1a; 初始化&…

Ubuntu22.04安装GNSS数据处理软件GAMIT/GLOBK

由于微信公众号改变了推送规则&#xff0c;为了每次新的推送可以在第一时间出现在您的订阅列表中&#xff0c;记得将本公众号设为星标或置顶喔~ 手把手带您安装gamit/globk软件~ &#x1f33f;前言 受朋友之托&#xff0c;出一期Ubuntu22.04安装GNSS数据处理软件——gamit软件…

【论文笔记】Are Large Kernels Better Teacheres than Transformers for ConvNets

Abstract 本文提出蒸馏中小核ConvNet做学生时&#xff0c;与Transformer相比&#xff0c;大核ConvNet因其高效的卷积操作和紧凑的权重共享&#xff0c;使得其做教师效果更好&#xff0c;更适合资源受限的应用。 用蒸馏从Transformers蒸到小核ConvNet的效果并不好&#xff0c;原…

MySQL篇(存储过程 触发器 存储函数)(持续更新迭代)

目录 一、存储过程 1. 简介 2. 特点 3. 语法 3.1. 创建 3.2. 调用 3.3. 查看 3.4. 删除 4. 示例 二、变量 1. 简介 2. 系统变量 2.1. 查看系统变量 2.2. 设置系统变量 2.3. 演示示例 3. 用户定义变量 3.1. 赋值 方式一 方式二 3.2. 使用 3.3. 演示示例 4.…

Rust - 字符串:str 与 String

在其他语言中&#xff0c;字符串通常都会比较简单&#xff0c;例如 “hello, world” 就是字符串章节的几乎全部内容了。 但是Rust中的字符串与其他语言有所不同&#xff0c;若带着其他语言的习惯来学习Rust字符串&#xff0c;将会波折不断。 所以最好先忘记脑中已有的关于字…

华为---代理ARP简介及示例配置

目录 1. 概念 2. 前提条件 3. 使用环境 4. 工作过程 5. 优点 6. 缺点 7. 示例配置 7.1 示例场景 7.2基本配置 7.3 配置端口隔离 7.4 开启代理ARP 7.4.1 VLAN内代理ARP 7.4.2 VLAN间代理ARP 7.4.3路由式ARP代理 1. 概念 代理ARP&#xff08;Proxy ARP&#xff09;&…

C#使用实体类Entity Framework Core操作mysql入门:从数据库反向生成模型

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

matlab恢复默认窗口布局

1.点击主页&#xff0c;选择布局 2.选择默认&#xff0c;即可恢复到默认的窗口布局

LIN总线CAPL函数—— 设置LIN报文字节间隔长度(linSetInterByteSpace)

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

利士策分享,如何培养良好的工作习惯?

利士策分享&#xff0c;如何培养良好的工作习惯&#xff1f; 在这个快节奏、高压力的职场环境中&#xff0c;培养良好的工作习惯不仅关乎个人职业发展的顺畅度&#xff0c; 更是提升工作效率、保持身心健康的关键。 以下是一些实用的建议&#xff0c;帮助你在日常工作中逐步构…

智慧水利采砂船在线监控平台:构建高效、智能的河道采砂监管体系

随着科技的不断发展&#xff0c;水利行业的智慧化转型也日益受到重视。智慧水利采砂船在线监控平台便是这一转型的重要成果之一。该平台主要服务于水政执法人员&#xff0c;针对取得河道采砂许可证的采砂公司及采砂船&#xff0c;实施在线自动监控&#xff0c;旨在提高监管效率…

iptables限制网速

1、使用hashlimit来限速 #从eth0网卡进入INPUT链数据&#xff0c;使用模块hashlimit 限制网速为100kb/s或2mb/s,超过限制的数据包会被DROP。OUTPUT链同理&#xff0c;mode为srcip&#xff0c;有4个mode选项: srcip&#xff08;默认匹配每个源地址IP&#xff0c;配置指定源地址…

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

【STM32开发笔记】移植AI框架TensorFlow【上篇】 一、TFLM是什么&#xff1f;二、TFLM开源项目2.1 下载TFLM源代码2.2 TFLM基准测试说明2.3 TFLM基准测试命令 三、TFLM初步体验3.1 PC上运行Keyword基准测试3.2 PC上运行Person detection基准测试3.3 No module named numpy问题解…

保障电气安全的电气火灾监控系统主要组成有哪些?

电气火灾是什么&#xff1f; 电气火灾一般是指由于电气线路、用电设备、器具以及供配电设备出现故障性释放的热能&#xff1a;如高温、电弧、电火花以及非故障性释放的能量&#xff1b;如电热器具的炽热表面&#xff0c;在具备燃烧条件下引燃本体或其他可燃物而造成的火灾&…

递归基础训练-路径总和

路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 我们可以把之前的…

计算机组成原理(笔记4)

定点加减法运算 补码加法&#xff1a; 补码减法&#xff1a; 求补公式&#xff1a; 溢出的概念 在定点小数机器中,数的表示范围为|&#xff58;|<1。在运算过程中如出现大于1的现象,称为 “溢出”。 上溢&#xff1a;两个正数相加&#xff0c;结果大于机器所能表示的最…

数据结构-线性表的单链式存储结构图解及C语言实现

概念 链式存储&#xff1a;结点在存储器中的位置是任意的&#xff0c;即逻辑相邻的数据元素在物理上不一定相邻 链式存储结构也称非顺序映像或链式映像 图解 链式存储结构中结点一般有两个部分组成&#xff0c;即数据域(data)和指针域&#xff0c;数据域是用于存放数据的&…

开源ids snort (windows版)

Snort-IPS-on-Windows-main资源-CSDN文库 GitHub - eldoktor1/Snort-IPS-on-Windows: A comprehensive guide to installing and configuring Snort IPS on Windows, ensuring robust network security 手动打造Snortbarnyard2BASE可视化告警平台 - FreeBuf网络安全行业门户 …

JavaWeb--小白笔记07:servlet对表单数据的简单处理

这里的servlet对表单数据的处理是指使用IDEA创建web工程&#xff0c;再创建html和class文件进行连接&#xff0c;实现html创建一个表单网页&#xff0c;我们对网页中的表单进行填充&#xff0c;可以通过class文件得到网页我们填充的内容进行打印到控制台。 一登录系统页面---h…

Linux网络之UDP与TCP协议详解

文章目录 UDP协议UDP协议数据报报头 TCP协议确认应答缓冲区 超时重传三次握手其他问题 四次挥手滑动窗口流量控制拥塞控制 UDP协议 前面我们只是说了UDP协议的用法,但是并没有涉及到UDP协议的原理 毕竟知道冰箱的用法和知道冰箱的原理是两个层级的事情 我们首先知道计算机网…