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

  导言

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

 业务

    签到可以有时间段限制,一天可以有多段可签到时间(如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,一经查实,立即删除!

相关文章

Go Sonyflake学习与使用

文章目录 Sonyflake 特点Sonyflake ID 结构Sonyflake 使用场景Sonyflake 与 Snowflake 的对比Sonyflake 的实现安装 Sonyflake 库注意1. panic: no point解决方法&#xff1a; 2. panic: memory解决方法&#xff1a; 示例代码中的改进 Sonyflake 是一种分布式唯一 ID 生成器&am…

Pillow:Python图像处理库详解

Pillow&#xff08;之前称为PIL&#xff0c;Python Imaging Library&#xff09;是一个开源的Python图像处理库&#xff0c;它提供了广泛的文件格式支持、强大的图像处理能力和易于使用的API。Pillow可以处理几乎所有类型的图像文件&#xff0c;并且可以进行复杂的图像操作&…

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

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

在 Webpack 中配置多入口应用并实现公共依赖的提取

1. 配置多入口点 首先&#xff0c;在 webpack.config.js 文件中定义多个入口点。你可以通过对象形式来指定多个入口点&#xff0c;每个入口点对应一个输出文件。 const path require(path);module.exports {entry: {app1: ./src/app1/index.js,app2: ./src/app2/index.js},…

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

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

Java使用Map数据结构配合函数式接口存储方法引用

Java使用Map数据结构配合函数式接口存储方法引用 背景 需求中存在这样一直情况 一个国家下面有很多的州 每个州对应的计算日期方法是不同的 这个时候 就面临 可能会有很多if else 为了后期维护尽量还是不想采用这个方式&#xff0c;那么就可以使用策略模式 但是 使用策略带来的…

【论文笔记】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.…

富文本编辑器wangEdittor使用入门

一、wangEdittor介绍 富文本编辑器为开源产品wangEditor。wangEditor是一款轻量级Web富文本编辑器&#xff0c;配置方便&#xff0c;使用简单。读者可在其官网和GitHub仓库进行更多了解。主要有以下功能&#xff1a; 1&#xff09;图文混排 wangEditor可以编辑的内容比较丰富…

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;帮助你在日常工作中逐步构…

大语言模型量化方法GPTQ、GGUF、AWQ详细原理

大语言模型量化的目的是减少模型的计算资源需求和存储占用&#xff0c;同时尽量保持模型的性能。以下是几种常见的量化方法的原理&#xff1b; 1. GPTQ (Gradient-based Post-training Quantization) GPTQ 是一种基于梯度的后训练量化方法&#xff0c;主要目的是在减少浮点计…

macOS 系统中python的安装步骤

访问Python官网&#xff1a; 打开浏览器&#xff0c;访问Python的官方网站&#xff08;https://www.python.org/&#xff09;。 下载Python安装包&#xff1a; 在官网首页找到“Downloads”链接&#xff0c;点击进入下载页面。选择适用于macOS的安装包。在撰写本文时&#xff…

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

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

Ubuntu USB设置别名

在 Ubuntu 中&#xff0c;可以通过创建 udev 规则为 USB 设备设置别名。这样你可以通过自定义的别名访问设备&#xff0c;而不是使用随机分配的设备节点&#xff08;例如 /dev/ttyUSB0&#xff09;。 1. 确认设备信息 首先&#xff0c;你需要找到设备的相关信息&#xff08…

linux 内存屏障(barrier)分析

谈起内存屏障,大家感觉这个"玩意儿"很虚,不太实际,但是内核代码中又广泛地可以看到起身影。内存屏障,英文barrier,这个"玩意儿"它还不太好去定义它。barrier,中文翻译为栅栏&#xff0c;栅栏大家都见过,现实生活中就是防止他人或者动物非法闯入而用来进行隔…