当前位置: 首页 > news >正文

28. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表定时器与报表数据修正

这篇文章是《.NET 8 实战–孢子记账–从单体到微服务》系列专栏的《单体应用》专栏的最后一片和开发有关的文章。在这片文章中我们一起来实现一个数据统计的功能:报表数据汇总。这个功能为用户查看月度、年度、季度报表提供数据支持。

一、需求

数据统计方面,我们应该考虑一个问题:用户是否需要看到实时数据。一般来说个人记账软件的数据统计是不需要实时的,因此我们可以将数据统计时间设置为每天统计或者每天每月统计,这样我们不仅可以减少统计数据时受到正在写入的数据的影响,也能提升用户体验。在数据更新方面,我们要在每次新增、删除、更新几张记录时进行更新统计报表。整理后的需求如下:

编号需求说明
1统计支出报表1. 每月、每季度、每年定时统计支出数据
2报表更新1. 新增、删除、更新支出记录时更新报表数据; 2. 如果报表数据不存在则不进行任何处理

二、功能编写

根据前面的需求,我们分别实现这两个功能。

1. 支出数据统计

因为数据每天都定时更新,因此我们要创建一个定时器来实现这个功能,定时器我们依然使用Quartz来实现(以月度报表定时器为例)。我们在Task\Timer文件夹下新建ReportMonthTimer类来实现定时器。代码如下:

using Quartz;
using SporeAccounting.Models;
using SporeAccounting.Server.Interface;namespace SporeAccounting.Task.Timer;/// <summary>
/// 月度报表定时器
/// </summary>
public class ReportMonthTimer : IJob
{private readonly IServiceScopeFactory _serviceScopeFactory;/// <summary>/// 构造函数/// </summary>/// <param name="serviceScopeFactory"></param>public ReportMonthTimer(IServiceScopeFactory serviceScopeFactory){_serviceScopeFactory = serviceScopeFactory;}/// <summary>/// 执行/// </summary>/// <param name="context"></param>/// <returns></returns>public System.Threading.Tasks.Task Execute(IJobExecutionContext context){using var scope = _serviceScopeFactory.CreateScope();// 获取每个用户最近一次报表记录日期var reportServer = scope.ServiceProvider.GetRequiredService<IReportServer>();var incomeExpenditureRecordServer = scope.ServiceProvider.GetRequiredService<IIncomeExpenditureRecordServer>();var reportLogServer = scope.ServiceProvider.GetRequiredService<IReportLogServer>();var reportLogs = reportLogServer.Query();var reportLogDic = reportLogs.GroupBy(x => x.UserId).ToDictionary(x => x.Key,x => x.Max(x => x.CreateDateTime));// 查询上次日期以后的记账记录List<Report> dbReports = new();List<ReportLog> dbReportLogs = new();foreach (var log in reportLogDic){var incomeExpenditureRecords = incomeExpenditureRecordServer.QueryByUserId(log.Key);incomeExpenditureRecords = incomeExpenditureRecords.Where(x => x.RecordDate > log.Value).Where(p => p.IncomeExpenditureClassification.Type == IncomeExpenditureTypeEnmu.Income).ToList();// 生成报表// 按照月度创建报表数据,根据支出类型统计var monthlyReports = incomeExpenditureRecords.GroupBy(x => new { x.RecordDate.Year, x.RecordDate.Month }).Select(g => new Report{Year = g.Key.Year,Month = g.Key.Month,Name = $"{g.Key.Year}{g.Key.Month}月报表",Type = ReportTypeEnum.Month,Amount = g.Sum(x => x.AfterAmount),UserId = log.Key,ClassificationId = g.First().IncomeExpenditureClassificationId,CreateDateTime = DateTime.Now,CreateUserId = log.Key}).ToList();dbReports.AddRange(monthlyReports);// 记录日志var reportLogEntries = dbReports.Select(report => new ReportLog{UserId = report.UserId,ReportId = report.Id,CreateDateTime = DateTime.Now,CreateUserId = report.UserId}).ToList();dbReportLogs.AddRange(reportLogEntries);// 保存报表和日志到数据库reportServer.Add(dbReports);reportLogServer.Add(dbReportLogs);}return System.Threading.Tasks.Task.CompletedTask;}
}

这段代码实现了一个定时任务类ReportMonthTimer,用于生成和记录用户的月度报表。它实现了Quartz库中的IJob接口,定期执行Execute方法。首先,构造函数接收IServiceScopeFactory,用于创建服务作用域,确保每次任务执行时获得正确的服务实例。然后,Execute方法通过依赖注入获取IReportServerIIncomeExpenditureRecordServerIReportLogServer,分别用于处理报表生成、收入支出记录和报表日志。
代码从reportLogServer查询所有报表日志,并根据每个用户的最新报表日期筛选出新的收入支出记录。接着,通过GroupBy按年和月对收入支出记录进行分组,生成月度报表,并将报表数据保存到dbReports中。同时,为每份报表创建日志记录,并保存到dbReportLogs中。最后,报表和日志通过reportServer.Add()reportLogServer.Add()方法存储到数据库。

Tip:这段代码中涉及到了一个新表报表日志,这个用于记录报表数据生成记录的。在这里就不把这个表的结构、操作类列出来了,大家自己动手来实现一下。

2. 报表更新

报表更新逻辑很简单,在这里我们只展示新增的逻辑,其他逻辑大家自己动手实现。我们在IncomeExpenditureRecordImp类的Add方法中添加如下代码:

// 获取包含支出记录记录日期的报表记录
var reports = _sporeAccountingDbContext.Reports.Where(x => x.UserId == incomeExpenditureRecord.UserId&& x.Year <= incomeExpenditureRecord.RecordDate.Year &&x.Month >= incomeExpenditureRecord.RecordDate.Month &&x.ClassificationId==incomeExpenditureRecord.IncomeExpenditureClassificationId);
// 如果没有就说明程序还未将其写入报表,那么就不做任何处理
for (int i = 0; i < reports.Count(); i++)
{var report = reports.ElementAt(i);report.Amount += incomeExpenditureRecord.AfterAmount;_sporeAccountingDbContext.Reports.Update(report);
}

这段代码添加在了if (classification.Type == IncomeExpenditureTypeEnmu.Income) 分支中,当新增的类型时支出项目时,我们就执行这段代码。在这段代码中,当没有查询到支出记录的话就认为对应该日期的指出记录没有进行数据统计,因此不进行任何处理。

三、总结

在这篇文章中,我们介绍了如何在.NET 8环境下实现定时生成财务报表的功能。首先,分析了需求,确定了报表数据统计的时间和更新策略。然后,通过使用Quartz库创建了ReportTimer定时器类,该类实现了IJob接口,并在其Execute方法中实现了报表数据的生成和更新逻辑。在实现过程中,通过依赖注入获取必要的服务实例,查询用户的收入和支出记录,生成季度、年度和月度报表,并将这些报表和日志条目保存到数据库中,实现了报表数据的定期更新和持久化存储。此外,还展示了如何在新增支出记录时更新报表数据,确保报表数据的实时性和准确性。通过这种设计,提高了报表生成的效率,确保了数据的一致性和完整性。希望读者能掌握相关技术并应用到实际项目中。
在下一篇文章,也就是这个专栏的最后一篇文章,我们将一起把这个服务端部署到服务器上。

相关文章:

28. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表定时器与报表数据修正

这篇文章是《.NET 8 实战–孢子记账–从单体到微服务》系列专栏的《单体应用》专栏的最后一片和开发有关的文章。在这片文章中我们一起来实现一个数据统计的功能&#xff1a;报表数据汇总。这个功能为用户查看月度、年度、季度报表提供数据支持。 一、需求 数据统计方面&…...

Java 泛型<? extends Object>

在 Java 泛型中&#xff0c;<? extends Object> 和 <?> 都表示未知类型&#xff0c;但它们在某些情况下有细微的差异。泛型的引入是为了消除运行时错误并增强类型安全性&#xff0c;使代码更具可读性和可维护性。 在 JDK 5 中引入了泛型&#xff0c;以消除编译时…...

FPGA|使用quartus II通过AS下载POF固件

1、将开发板设置到AS下载挡位&#xff0c;或者把下载线插入到AS端口 2、打开quartus II&#xff0c;选择Tools→Programmer→ Mode选择Active Serial Programming 3、点击左侧Add file…&#xff0c;选择 .pof 文件 →start 4、勾选program和verify&#xff08;可选&#xff0…...

“新月之智”智能战术头盔系统(CITHS)

新月人物传记&#xff1a;人物传记之新月篇-CSDN博客 相关文章链接&#xff08;更新&#xff09;&#xff1a; 星际战争模拟系统&#xff1a;新月的编程之道-CSDN博客 新月智能护甲系统CMIA--未来战场的守护者-CSDN博客 目录 一、引言 二、智能头盔控制系统概述 三、系统架…...

php:代码中怎么搭建一个类似linux系统的crontab服务

一、前言 最近使用自己搭建的php框架写一些东西&#xff0c;需要用到异步脚本任务的执行&#xff0c;但是是因为自己搭建的框架没有现成的机制&#xff0c;所以想自己搭建一个类似linux系统的crontab服务的功能。 因为如果直接使用linux crontab的服务配置起来很麻烦&#xff0…...

【LeetCode: 958. 二叉树的完全性检验 + bfs + 二叉树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

MinDoc 安装与部署

下载可执行文件 mindoc mindoc_linux_amd64.zip 上传并解压压缩包 cd /opt mkdir mindoc cd mindocunzip mindoc_linux_amd64.zip 创建数据库 CREATE DATABASE mindoc_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; 配置数据库 将解压目录下 conf/app.conf.exam…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(基础组件实现)

目录 基础组件实现 如何将图像和文字显示到OLED上 如何绘制图像 如何绘制文字 如何获取字体&#xff1f; 如何正确的访问字体 如何抽象字体 如何绘制字符串 绘制方案 文本绘制 更加方便的绘制 字体附录 ascii 6x8字体 ascii 8 x 16字体 基础组件实现 我们现在离手…...

windows系统如何检查是否开启了mongodb服务

windows系统如何检查是否开启了mongodb服务&#xff01;我们有很多软件开发&#xff0c;网站开发时候需要使用到这个mongodb数据库&#xff0c;下面我们看看&#xff0c;如何在windows系统内排查&#xff0c;是否已经启动了本地服务。 在 Windows 系统上&#xff0c;您可以通过…...

VS安卓仿真器下载失败怎么办?

如果网络不稳定&#xff0c;则VS的安卓仿真器很容易下载失败&#xff0c;如下 Downloaded file <USER_HOME>\AppData\Local\Temp\xamarin-android-sdk\x86_64-35_r08.zip not found for Android SDK archive https://dl.google.com/android/repository/sys-img/google_a…...

计算机网络一点事(24)

TCP可靠传输&#xff0c;流量控制 可靠传输&#xff1a;每字节对应一个序号 累计确认&#xff1a;收到ack则正确接收 返回ack推迟确认&#xff08;不超过0.5s&#xff09; 两种ack&#xff1a;专门确认&#xff08;只有首部无数据&#xff09; 捎带确认&#xff08;带数据…...

视频拼接,拼接时长版本

目录 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg imageio&#xff0c;适合视频较短 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg import subprocess import glob import os from nats…...

制造企业的成本核算

一、生产成本与制造费用的区别 (1)生产成本,是直接用于产品生产,构成产品实体的材料成本。 包括企业在生产经营过程中实际消耗的原材料、辅助材料、备品备件、外购半成品、燃料、动力包装物以及其它直接材料,和直接参加产品生产的工人工资,以及按生产工人的工资总额和规…...

doris:高并发导入优化(Group Commit)

在高频小批量写入场景下&#xff0c;传统的导入方式存在以下问题&#xff1a; 每个导入都会创建一个独立的事务&#xff0c;都需要经过 FE 解析 SQL 和生成执行计划&#xff0c;影响整体性能每个导入都会生成一个新的版本&#xff0c;导致版本数快速增长&#xff0c;增加了后台…...

LLMs之WebRAG:STORM/Co-STORM的简介、安装和使用方法、案例应用之详细攻略

LLMs之WebRAG&#xff1a;STORM/Co-STORM的简介、安装和使用方法、案例应用之详细攻略 目录 STORM系统简介 1、Co-STORM 2、更新新闻 STORM系统安装和使用方法 1、安装 pip安装 直接克隆GitHub仓库 2、模型和数据集 两个数据集 FreshWiki数据集 WildSeek数据集 支持…...

鸿蒙HarmonyOS实战-ArkUI动画(页面转场动画)_鸿蒙arkui tab 切换动画

PageTransitionExit({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number}) 在HarmonyOS中&#xff0c;PageTransitionEnter和PageTransitionExit是用于控制页面切换动画的参数。它们分别表示页面进入和退出时的动画。1. type&#xff08;动画类型…...

图漾相机-ROS2-SDK-Ubuntu版本编译(新版本)

文章目录 前言1.Camport ROS2 SDK 介绍1.1 Camport ROS2 SDK源文件介绍1.2 Camport ROS2 SDK工作流程1.2.1 包含头文件1.2.2 2 初始化 ROS 2 节点1.2.3 创建节点对象1.2.4 创建发布者对象并实现发布逻辑1.2.5 启动 ROS 2 1.3 ROS2 SDK环境配置与编译1.3.1 Ubuntu 20.04 下ROS2 …...

小程序的协同工作与发布

1.小程序API的三大分类 2.小程序管理的概念&#xff0c;以及成员管理两个方面 3.开发者权限说明以及如何维护项目成员 4.小程序版本...

解锁维特比算法:探寻复杂系统的最优解密码

引言 在复杂的技术世界中&#xff0c;维特比算法以其独特的魅力和广泛的应用&#xff0c;成为通信、自然语言处理、生物信息学等领域的关键技术。今天&#xff0c;让我们一同深入探索维特比算法的奥秘。 一、维特比算法的诞生背景 维特比算法由安德鲁・维特比在 1967 年提出…...

计算机网络一点事(20)

IEEE802.11 无线局域网 分类有无基础设施 星型拓扑&#xff0c;基本服务集BSS一基站多移动站&#xff0c;服务集标识符SSID不超过32b&#xff0c;可接入802.3 漫游&#xff1a;移动站从一个基本服务集切换到另一个&#xff08;类似换联WiFi&#xff09; 802.11帧&#xff1…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...