diff --git a/SimpleAdmin.Application/Entity/Medicinal.cs b/SimpleAdmin.Application/Entity/Medicinal.cs deleted file mode 100644 index c4512e2..0000000 --- a/SimpleAdmin.Application/Entity/Medicinal.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Entity -{ - [SugarTable("WeiBingJu_Medicinal", TableDescription = "药材管理")] - [Tenant(SqlSugarConst.DB_DEFAULT)] - [CodeGen] - public class Medicinal : DataEntityBase - { - /// - /// 药材 - /// - [SugarColumn(ColumnDescription = "药材")] - public string MedicinalName { get; set; } - /// - /// 数量(g) - /// - [SugarColumn(ColumnDescription = "数量(g)")] - public decimal Number { get; set; } - - } -} diff --git a/SimpleAdmin.Application/Entity/MedicinalAddLog.cs b/SimpleAdmin.Application/Entity/MedicinalAddLog.cs deleted file mode 100644 index b7d979a..0000000 --- a/SimpleAdmin.Application/Entity/MedicinalAddLog.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Entity -{ - [SugarTable("WeiBingJu_MedicinalAddLog", TableDescription = "药材添加记录")] - [Tenant(SqlSugarConst.DB_DEFAULT)] - [CodeGen] - public class MedicinalAddLog : DataEntityBase - { - /// - /// 药材关联id - /// - [SugarColumn(ColumnDescription = "药材关联id")] - public long MedicinalId { get; set; } - /// - /// 添加重量(g) - /// - [SugarColumn(ColumnDescription = "添加重量(g)")] - public decimal AddWeight { get; set; } - - /// - /// 药材单价 - /// - [SugarColumn(ColumnDescription = "药材单价")] - public decimal UnitPrice { get; set; } - - /// - /// 总价 - /// - [SugarColumn(ColumnDescription = "总价")] - public decimal TotalPrice { get; set; } - - } -} diff --git a/SimpleAdmin.Application/Entity/Person.cs b/SimpleAdmin.Application/Entity/Person.cs deleted file mode 100644 index a9735c5..0000000 --- a/SimpleAdmin.Application/Entity/Person.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Entity -{ - [SugarTable("WeiBingJu_Person", TableDescription = "人员表(员工和员工亲戚)")] - [Tenant(SqlSugarConst.DB_DEFAULT)] - [CodeGen] - public class Person : DataEntityBase - { - [SugarColumn(Length = 128, ColumnDescription = "姓名")] - public string Name { get; set; } - - /// - /// 若非空,表示此 person 是某员工的家属 - /// - [SugarColumn(ColumnDescription = "关联员工Id", IsNullable = true)] - public long? EmployeeId { get; set; } - - [SugarColumn(ColumnDescription = "关系配置id", IsNullable = true)] - public long? RelationShip { get; set; } - - [SugarColumn(ColumnDescription = "出生日期", IsNullable = true)] - public string Birthday { get; set; } - - /// 单位 cm,保留两位小数 - [SugarColumn(ColumnDescription = "身高(cm)", IsNullable = true)] - public decimal? Height { get; set; } - - [SugarColumn(ColumnDescription = "1领导,2普通员工,3其他", IsNullable = true)] - public int? Type { get; set; } - } -} diff --git a/SimpleAdmin.Application/Entity/Prescription.cs b/SimpleAdmin.Application/Entity/Prescription.cs deleted file mode 100644 index 6e337a7..0000000 --- a/SimpleAdmin.Application/Entity/Prescription.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Entity -{ - [SugarTable("WeiBingJu_Prescription", TableDescription = "处方管理")] - [Tenant(SqlSugarConst.DB_DEFAULT)] - [CodeGen] - public class Prescription : DataEntityBase - { - [SugarColumn(ColumnDescription = "处方对象 PersonId")] - public long PersonId { get; set; } - - [SugarColumn(ColumnDescription = "诊断结果", ColumnDataType = StaticConfig.CodeFirst_BigString)] - public string DiagnosisResult { get; set; } - - [SugarColumn(ColumnDescription = "用药建议", ColumnDataType = StaticConfig.CodeFirst_BigString)] - public string UserMedicinaAdvice { get; set; } - - [SugarColumn(ColumnDescription = "就诊时间")] - public DateTime? VisitDate { get; set; } - - - /// 单位 kg,保留两位小数 - [SugarColumn(ColumnDescription = "体重(kg)", IsNullable = true)] - public decimal? Weight { get; set; } - } - -} - diff --git a/SimpleAdmin.Application/Entity/PrescriptionHerb.cs b/SimpleAdmin.Application/Entity/PrescriptionHerb.cs deleted file mode 100644 index 24ca4b7..0000000 --- a/SimpleAdmin.Application/Entity/PrescriptionHerb.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Entity -{ - [SugarTable("WeiBingJu_PrescriptionHerb", TableDescription = "处方消耗药材表")] - [Tenant(SqlSugarConst.DB_DEFAULT)] - [CodeGen] - public class PrescriptionHerb : DataEntityBase - { - [SugarColumn(ColumnDescription = "处方Id")] - public long PrescriptionId { get; set; } - - [SugarColumn(ColumnDescription = "药材Id")] - public long MedicinalId { get; set; } - - /// 消耗克数,单位 g - [SugarColumn(ColumnDescription = "消耗(g)")] - public decimal AmountG { get; set; } - - [SugarColumn(Length = 500, IsNullable = true, ColumnDescription = "用量说明/备注")] - public string Note { get; set; } - } -} diff --git a/SimpleAdmin.Application/GlobalUsings.cs b/SimpleAdmin.Application/GlobalUsings.cs index 5f1ff20..d5406ed 100644 --- a/SimpleAdmin.Application/GlobalUsings.cs +++ b/SimpleAdmin.Application/GlobalUsings.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 +// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 // // SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: // 1.请不要删除和修改根目录下的LICENSE文件。 @@ -23,7 +23,3 @@ global using SimpleAdmin.SqlSugar; global using SimpleAdmin.System; global using SqlSugar; global using System.Reflection; -global using SimpleAdmin.Application.Services.Medicinal; -global using SimpleAdmin.Application.Services.Medicinal.Dto; -global using SimpleAdmin.Application.Services.Prescription; -global using SimpleAdmin.Application.Services.Prescription.Dto; diff --git a/SimpleAdmin.Application/Services/Medicinal/Dto/MedicinalDto.cs b/SimpleAdmin.Application/Services/Medicinal/Dto/MedicinalDto.cs deleted file mode 100644 index b11e594..0000000 --- a/SimpleAdmin.Application/Services/Medicinal/Dto/MedicinalDto.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Services.Medicinal.Dto -{ - // 药材列表DTO - public class MedicinalDto - { - public long Id { get; set; } - public string MedicinalName { get; set; } - public decimal Stock { get; set; } - public decimal UsedCost { get; set; } - public decimal RemainingValue { get; set; } - public decimal TotalUsedWeight { get; set; } - } - - // 药材消耗记录DTO - public class MedicinalConsumptionRecordDto - { - public decimal AmountG { get; set; } - public string PersonName { get; set; } - public bool IsRelative { get; set; } - public string EmployeeName { get; set; } - public DateTime? UseTime { get; set; } - } - - // 药材添加记录DTO - public class MedicinalAddLogDto - { - public long Id { get; set; } - public decimal AddWeight { get; set; } - public decimal UnitPrice { get; set; } - public DateTime AddTime { get; set; } - public string AddUserName { get; set; } - public decimal TotalPrice { get; set; } - - public bool CanEdit { get; set; } - } - - // 添加药材输入DTO - public class AddMedicinalInput - { - public long? Id { get; set; } - public decimal AddWeight { get; set; } - public decimal TotalPrice { get; set; } - /// - /// 未找到下拉框的时候传这个值代表添加新的药材 - /// - public string MedicinalName { get; set; } - } - - // 修改药材添加记录输入DTO - public class UpdateMedicinalAddLogInput - { - public long Id { get; set; } - public decimal AddWeight { get; set; } - public decimal TotalPrice { get; set; } - } - - // 药材类型DTO - public class MedicinalTypeDto - { - public long Id { get; set; } - public string Name { get; set; } - } - - // 添加药材类型输入DTO - public class AddMedicinalTypeInput - { - [Required(ErrorMessage = "药材名称不能为空")] - public string Name { get; set; } - } - - public class DeleteMedicinalLog - { - public long Id { get; set; } - } - -} diff --git a/SimpleAdmin.Application/Services/Medicinal/IMedicinalService.cs b/SimpleAdmin.Application/Services/Medicinal/IMedicinalService.cs deleted file mode 100644 index 44325fb..0000000 --- a/SimpleAdmin.Application/Services/Medicinal/IMedicinalService.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Services.Medicinal -{ - public interface IMedicinalService : ITransient - { - /// - /// 获取药材列表,带筛选 - /// - /// 药材名称筛选 - /// 页码 - /// 页大小 - /// - Task> GetMedicinalList(string medicinalName, int page, int size); - - /// - /// 获取药材消耗记录 - /// - /// 药材ID - /// - Task> GetConsumptionRecords(long medicinalId, int page, int size); - /// - /// 获取药材下拉 - /// - /// - Task> GetMedicinalDictList(); - - /// - /// 获取药材添加记录 - /// - /// 药材ID - /// - Task> GetAdditionRecords(long medicinalId, int page, int size); - - /// - /// 添加药材 - /// - /// 添加信息 - /// - Task AddMedicinal(AddMedicinalInput input); - - /// - /// 修改药材添加记录(仅当天可修改) - /// - /// 记录ID - /// 修改信息 - /// - Task UpdateAdditionRecord(UpdateMedicinalAddLogInput input); - - /// - /// 删除药材添加记录(仅当天可删除) - /// - /// 记录ID - /// - Task DeleteAdditionRecord(long id); - } -} diff --git a/SimpleAdmin.Application/Services/Medicinal/MedicinalService.cs b/SimpleAdmin.Application/Services/Medicinal/MedicinalService.cs deleted file mode 100644 index f939c05..0000000 --- a/SimpleAdmin.Application/Services/Medicinal/MedicinalService.cs +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System.Linq.Dynamic.Core; -using SimpleAdmin.Application.Entity; -using Yitter.IdGenerator; - -public class MedicinalService : DbRepository, IMedicinalService -{ - private readonly ISysUserService _sysUserService; - private readonly IDictService _dictService; - public MedicinalService(ISysUserService sysUserService, IDictService dictService) - { - _sysUserService = sysUserService; - _dictService = dictService; - } - public async Task> GetMedicinalList(string medicinalName, int page, int size) - { - // 1. 获取数据范围(原有逻辑不变) - //var dataScope = await _sysUserService.GetLoginUserApiDataScope(); - //dataScope?.Remove(UserManager.OrgId); - - // 2. 分页查询药材基本信息 - var query = this.AsQueryable() - //.WhereIF(dataScope.Any(), m => dataScope.Contains(m.Id)) - .WhereIF(!string.IsNullOrEmpty(medicinalName), m => m.MedicinalName.Contains(medicinalName)) - .OrderBy(p => p.Number) - .Select(m => new MedicinalDto - { - Id = m.Id, - MedicinalName = m.MedicinalName, - Stock = m.Number, // 当前库存 - }); - - var pageInfo = await query.ToPagedListAsync(page, size); - if (!pageInfo.List.Any()) return pageInfo; - - // 3. 批量计算:成本、剩余价值、总使用量 - var medicinalIds = pageInfo.List.Select(dto => dto.Id).ToList(); - var costAndUsageDict = await BatchCalculateCostAndValue(medicinalIds); - //decimal all = 0; - foreach (var item in pageInfo.List) - { - if (costAndUsageDict.TryGetValue(item.Id, out var metrics)) - { - //all += metrics.usedCost; - item.UsedCost = metrics.usedCost; // 使用成本 - item.RemainingValue = metrics.remainingValue; // 剩余价值 - item.TotalUsedWeight = metrics.totalUsedWeight; // 新增:总使用量 - } - else - { - // 无数据时默认值 - item.UsedCost = 0; - item.RemainingValue = 0; - item.TotalUsedWeight = 0; - } - } - - return pageInfo; - } - - /// - /// 获取药材下拉 - /// - /// - public async Task> GetMedicinalDictList() - { - ////获取数据范围 - //var dataScope = await _sysUserService.GetLoginUserApiDataScope(); - //dataScope?.Remove(UserManager.OrgId); - //药材查询 - return await this.AsQueryable() - //.WhereIF(dataScope.Any(), m => dataScope.Contains(m.Id)) //机构ID查询 - .OrderBy(p => p.Number) - .Select(m => new MedicinalDto - { - Id = m.Id, - MedicinalName = m.MedicinalName, - Stock = m.Number, - }).ToListAsync(); - } - /// - /// 获取药材消耗记录 - /// - /// - /// - /// - public async Task> GetConsumptionRecords(long medicinalId, int page, int size) - { - return await Context.Queryable() - // 先关联处方 - .LeftJoin((ph, p) => ph.PrescriptionId == p.Id) - // 再关联就诊人 - .LeftJoin((ph, p, pe) => p.PersonId == pe.Id) - // 再关联员工 - .LeftJoin((ph, p, pe, emp) => pe.EmployeeId != null && pe.EmployeeId == emp.Id) - .Where((ph, p, pe, emp) => ph.MedicinalId == medicinalId) - .OrderByDescending((ph, p, pe, emp) => p.CreateTime) - .Select((ph, p, pe, emp) => new MedicinalConsumptionRecordDto - { - AmountG = ph.AmountG, - PersonName = pe.Name, - IsRelative = pe.EmployeeId != null, - EmployeeName = emp == null ? null : emp.Name, - UseTime = p.VisitDate - }) - .ToPagedListAsync(page, size); - } - - /// - /// 获取药材添加记录 - /// - /// - /// - public async Task> GetAdditionRecords(long medicinalId, int page, int size) - { - var returnList = await Context.Queryable() - .Where(log => log.MedicinalId == medicinalId) - .OrderByDescending(dto => dto.CreateTime) - .Select(log => new MedicinalAddLogDto - { - Id = log.Id, - AddWeight = log.AddWeight, - UnitPrice = log.UnitPrice, - AddTime = log.CreateTime.Value, - AddUserName = log.CreateUser, - TotalPrice = log.TotalPrice, - CanEdit = false - }) - .ToPagedListAsync(page, size); - - foreach (var item in returnList.List) - { - if (item.AddTime.Date == DateTime.Now.Date || UserManager.SuperAdmin) - { - item.CanEdit = true; - } - } - return returnList; - } - /// - /// 添加药材 - /// - /// - /// - public async Task AddMedicinal(AddMedicinalInput input) - { - if (input.TotalPrice <= 0 || input.AddWeight <= 0) throw Oops.Bah("请填写正确的金额!"); - // 开启事务 - await Context.Ado.BeginTranAsync(); - try - { - // 检查药材是否已存在 - var existing = await Context.Queryable() - .Where(m => m.Id == input.Id) - .FirstAsync(); - - if (existing != null) - { - // 更新库存 - existing.Number += input.AddWeight; - await Context.Updateable(existing).ExecuteCommandAsync(); - } - else - { - var medicinalModel = await Context.Queryable() - .Where(m => m.MedicinalName == input.MedicinalName) - .FirstAsync(); - if (medicinalModel != null) throw Oops.Bah("已存在该药材,请在下拉框选择!"); - input.Id = YitIdHelper.NextId(); - // 新增药材记录 - await Context.Insertable(new Medicinal - { - Id = input.Id.Value, - Number = input.AddWeight, - MedicinalName = input.MedicinalName, - }).ExecuteCommandAsync(); - } - decimal unitPrice = 0m; - if (input.AddWeight > 0) - { - unitPrice = Decimal.Round(input.TotalPrice / input.AddWeight, 5, MidpointRounding.AwayFromZero); - } - // 添加记录 - await Context.Insertable(new MedicinalAddLog - { - MedicinalId = input.Id.Value, - AddWeight = input.AddWeight, - UnitPrice = unitPrice, - TotalPrice = input.TotalPrice - }).ExecuteCommandAsync(); - - await Context.Ado.CommitTranAsync(); - } - catch - { - await Context.Ado.RollbackTranAsync(); - throw; - } - return true; - } - /// - /// 修改药材添加记录 - /// - /// - /// - /// - public async Task UpdateAdditionRecord(UpdateMedicinalAddLogInput input) - { - if(input.TotalPrice<=0 || input.AddWeight<=0) throw Oops.Bah("请填写正确的金额!"); - var log = await Context.Queryable().Where(l => l.Id == input.Id).FirstAsync(); - if (log == null) - { - throw Oops.Bah("记录不存在!"); - } - - // 检查是否是当天记录,超级管理员随时都可以操作 - if (log.CreateTime.Value.Date != DateTime.Now.Date && !UserManager.SuperAdmin) - { - throw Oops.Bah("只能修改当天的记录!"); - } - - // 计算重量变化 - var weightDiff = input.AddWeight - log.AddWeight; - - // 开启事务 - await Context.Ado.BeginTranAsync(); - - try - { - // 更新记录 - log.AddWeight = input.AddWeight; - log.TotalPrice = input.TotalPrice; - log.UnitPrice = Decimal.Round(input.TotalPrice / input.AddWeight, 5, MidpointRounding.AwayFromZero); - await Context.Updateable(log).ExecuteCommandAsync(); - - // 更新药材库存 - var medicinal = await Context.Queryable() - .Where(m => m.Id == log.MedicinalId) - .FirstAsync(); - - if (medicinal != null) - { - medicinal.Number += weightDiff; - if(medicinal.Number<0) throw Oops.Bah("无法修改,库存不足!"); - await Context.Updateable(medicinal).ExecuteCommandAsync(); - } - - await Context.Ado.CommitTranAsync(); - } - catch - { - await Context.Ado.RollbackTranAsync(); - throw; - } - - return true; - } - /// - /// 删除药材添加记录 - /// - /// - /// - /// - public async Task DeleteAdditionRecord(long id) - { - var log = await Context.Queryable().Where(l => l.Id == id).FirstAsync(); - if (log == null) - { - throw Oops.Bah("记录不存在!"); - } - - // 检查是否是当天记录,超级管理员随时都可以操作 - if (log.CreateTime.Value.Date != DateTime.Now.Date && !UserManager.SuperAdmin) - { - throw Oops.Bah("只能删除当天的记录!"); - } - - // 开启事务 - await Context.Ado.BeginTranAsync(); - - try - { - // 删除记录 - log.IsDelete = true; - await Context.Updateable(log).ExecuteCommandAsync(); - - - // 更新药材库存 - var medicinal = await Context.Queryable() - .Where(m => m.Id == log.MedicinalId) - .FirstAsync(); - - if (medicinal != null) - { - medicinal.Number -= log.AddWeight; - if(medicinal.Number<0) throw Oops.Bah("无法删除,库存不足!"); - await Context.Updateable(medicinal).ExecuteCommandAsync(); - } - - await Context.Ado.CommitTranAsync(); - } - catch - { - await Context.Ado.RollbackTranAsync(); - throw; - } - - return true; - } - - /// - /// 批量计算:使用成本、剩余价值、总使用量(先进先出法) - /// - /// 需要计算的药材ID列表 - private async Task> BatchCalculateCostAndValue(List medicinalIds) - { - var result = new Dictionary(); - if (!medicinalIds.Any()) return result; - - // 1. 批量查询所有药材的【当前库存】 - var medicinals = await Context.Queryable() - .Where(m => medicinalIds.Contains(m.Id)) - .Select(m => new { m.Id, m.Number }) // Number = 当前库存 - .ToListAsync(); - - // 2. 批量查询所有药材的【入库记录】 - var allAddLogs = await Context.Queryable() - .Where(l => medicinalIds.Contains(l.MedicinalId)) - .OrderBy(l => l.CreateTime) // 先进先出:按入库时间排序 - .Select(l => new { - l.MedicinalId, - l.AddWeight, // 入库量 - l.UnitPrice, // 单价(用于计算成本) - l.TotalPrice // 总成本(用于计算成本) - }) - .ToListAsync(); - - // 3. 按【药材ID】分组入库记录 - var groupedLogs = allAddLogs - .GroupBy(l => l.MedicinalId) - .ToDictionary(g => g.Key, g => g.ToList()); - - // 4. 遍历每个药材,内存中计算所有指标 - foreach (var med in medicinals) - { - // 初始化默认值(无入库记录时) - decimal totalIn = 0; // 总入库量(AddWeight 总和) - decimal totalCost = 0; // 总入库成本 - decimal totalUsedWeight = 0; // 总使用量 - decimal usedCost = 0; // 使用成本 - decimal remainingValue = 0;// 剩余价值 - - // 若有入库记录,计算总入库量、总成本 - if (groupedLogs.TryGetValue(med.Id, out var addLogs) && addLogs.Any()) - { - totalIn = addLogs.Sum(l => l.AddWeight); // 总入库量 = 所有 AddWeight 求和 - totalCost = addLogs.Sum(l => l.TotalPrice); // 总入库成本 - } - - // 计算总使用量:总入库量 - 当前库存(若结果为负,说明数据异常,按0处理) - totalUsedWeight = Math.Max(0, totalIn - med.Number); - - // 若有使用量,先进先出法计算使用成本 - if (totalUsedWeight > 0 && groupedLogs.TryGetValue(med.Id, out var validLogs)) - { - decimal remainingToCalculate = totalUsedWeight; - foreach (var log in validLogs) - { - if (remainingToCalculate <= 0) break; - - // 当前入库记录的量 <= 剩余未计算的使用量:全部计入成本 - if (log.AddWeight <= remainingToCalculate) - { - usedCost += log.AddWeight * log.UnitPrice; - remainingToCalculate -= log.AddWeight; - } - // 当前入库记录的量 > 剩余未计算的使用量:仅计算剩余部分 - else - { - usedCost += remainingToCalculate * log.UnitPrice; - remainingToCalculate = 0; - } - } - } - - // 剩余价值 = 总入库成本 - 使用成本(若为负,按0处理) - remainingValue = Math.Max(0, totalCost - usedCost); - - // 存入结果字典 - result[med.Id] = (usedCost, remainingValue, totalUsedWeight); - } - - return result; - } -} diff --git a/SimpleAdmin.Application/Services/Prescription/Dto/PrescriptionDtos.cs b/SimpleAdmin.Application/Services/Prescription/Dto/PrescriptionDtos.cs deleted file mode 100644 index b0c00d7..0000000 --- a/SimpleAdmin.Application/Services/Prescription/Dto/PrescriptionDtos.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Services.Prescription.Dto -{ - // 人员类型枚举 - public enum PersonType - { - [Description("员工")] - Employee = 1, - [Description("家属")] - Relative = 2 - } - - // 处方列表DTO - public class PrescriptionDto - { - public long Id { get; set; } - public long PersonId { get; set; } - public string PersonName { get; set; } - public PersonType PersonType { get; set; } - /// - /// 关联的员工名称 - /// - public string EmployeeName { get; set; } - public DateTime? VisitDate { get; set; } - public bool CanEdit { get; set; } - - public DateTime CreateTime { get; set; } - - public decimal TotalMedicineCost { get; set; } - public int? Type { get; set; } - - } - // 辅助类:存储FIFO计算所需的入库记录信息 - public class MedicinalFifoRecord - { - public long MedicinalId { get; set; } - public decimal AddWeight { get; set; } - public decimal UnitPrice { get; set; } - } - // 处方查询输入DTO - public class PrescriptionQueryInput: BasePageInput - { - public DateTime? VisitDate { get; set; } - public long? MedicinalId { get; set; } - public PersonType? PersonType { get; set; } - public long? EmployeeId { get; set; } - - public string PersonName { get; set; } - } - - // 处方详情DTO - public class PrescriptionDetailDto - { - public long Id { get; set; } - public PersonDetailDto Person { get; set; } - public string DiagnosisResult { get; set; } - public string UserMedicinaAdvice { get; set; } - public DateTime? VisitDate { get; set; } - public List Herbs { get; set; } - public bool CanEdit { get; set; } - } - - // 人员详情DTO - public class PersonDetailDto - { - public long? Id { get; set; } - public string Name { get; set; } - public string Birthday { get; set; } - public decimal? Weight { get; set; } - public decimal? Height { get; set; } - public bool IsEmployee { get; set; } - public long? EmployeeId { get; set; } - public string EmployeeName { get; set; } - public long? RelationShip { get; set; } - public string RelationShipName { get; set; } - public int? Type { get; set; } - } - - // 处方药材DTO - public class PrescriptionHerbDto - { - public long MedicinalId { get; set; } - public string MedicinalName { get; set; } - public decimal AmountG { get; set; } - public string Note { get; set; } - } - - // DTOs(替换/合并到你的 DTO 定义处) - public class SavePrescriptionInput - { - public long? Id { get; set; } - public PersonInputDto Person { get; set; } - public string DiagnosisResult { get; set; } - public string UserMedicinaAdvice { get; set; } - public DateTime? VisitDate { get; set; } - public List Herbs { get; set; } - } - - // 人员输入 DTO(新增字段以支持前端发送临时员工信息) - public class PersonInputDto - { - public long? Id { get; set; } // 可能的已存在人员ID - public string TempId { get; set; } // 可选:前端临时 id(兼容旧流程) - public string Name { get; set; } - public string Birthday { get; set; } - public decimal? Weight { get; set; } - public decimal? Height { get; set; } - public bool IsEmployee { get; set; } - public long? RelationShip { get; set; } // 亲属关系 id(若为家属) - public long? EmployeeId { get; set; } // 关联员工 id(如果是家属) - /// - /// 当前关联的员工是否是前端临时新增(需要后端创建) - /// - public bool EmployeeIsTemp { get; set; } - /// - /// 当 EmployeeIsTemp 为 true 或者前端直接传了员工名字时,后端可用此字段创建员工 - /// - public string EmployeeName { get; set; } - public int? Type { get; set; } - } - // 处方药材输入DTO - public class PrescriptionHerbInputDto - { - public long Id { get; set; } - public decimal AmountG { get; set; } - public string Note { get; set; } - } - - // 人员DTO - public class PersonDto - { - public long Id { get; set; } - public string Name { get; set; } - public string Birthday { get; set; } - - public decimal? Height { get; set; } - - public long? RelationShip { get; set; } - public int? Type { get; set; } - } - - // 关系类型DTO - public class RelationTypeDto - { - public long Id { get; set; } - public string Name { get; set; } - } - -} diff --git a/SimpleAdmin.Application/Services/Prescription/IPrescriptionService.cs b/SimpleAdmin.Application/Services/Prescription/IPrescriptionService.cs deleted file mode 100644 index 0bce9c1..0000000 --- a/SimpleAdmin.Application/Services/Prescription/IPrescriptionService.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Text; -using System.Threading.Tasks; - -namespace SimpleAdmin.Application.Services.Prescription -{ - public interface IPrescriptionService : ITransient - { - /// - /// 获取处方列表,带筛选 - /// - /// 筛选条件 - /// - Task> GetPrescriptionList(PrescriptionQueryInput input); - - /// - /// 获取所有处方的成本 - /// - /// - Task GetAllPrescriptionTotalCost(); - - /// - /// 获取处方详情 - /// - /// 处方ID - /// - Task GetPrescriptionDetail(long id); - - /// - /// 保存处方(新增或编辑) - /// - /// 处方信息 - /// - Task SavePrescription(SavePrescriptionInput input); - - /// - /// 获取人员列表(员工和家属) - /// - /// 人员类型 - /// 员工ID(用于获取家属) - /// - Task> GetPersonList(PersonType? type, long? employeeId); - - - /// - /// 获取所有关系类型(写死在代码中) - /// - /// - Task> GetRelationTypes(); - } -} diff --git a/SimpleAdmin.Application/Services/Prescription/PrescriptionService.cs b/SimpleAdmin.Application/Services/Prescription/PrescriptionService.cs deleted file mode 100644 index 2506eea..0000000 --- a/SimpleAdmin.Application/Services/Prescription/PrescriptionService.cs +++ /dev/null @@ -1,892 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - - -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using Minio.DataModel; -using NewLife.Reflection; -using SimpleAdmin.Application.Entity; -using SimpleAdmin.Application.Services.Prescription; -using Yitter.IdGenerator; - -public class PrescriptionService : DbRepository, IPrescriptionService -{ - //public async Task> GetPrescriptionList(PrescriptionQueryInput input) - //{ - // var query = Context.Queryable() - // .LeftJoin((p, pe) => p.PersonId == pe.Id) - // .LeftJoin((p, pe, emp) => pe.EmployeeId != null && pe.EmployeeId == emp.Id) - // .WhereIF(!string.IsNullOrEmpty(input.PersonName), (p, pe, emp) => - // input.PersonName.Contains(pe.Name) || pe.Name.Contains(input.PersonName) || - // input.PersonName.Contains(emp.Name) || emp.Name.Contains(input.PersonName)) - // .WhereIF(input.PersonType.HasValue && input.PersonType == PersonType.Employee, (p, pe) => - // pe.EmployeeId == null) - // .WhereIF(input.PersonType.HasValue && input.PersonType != PersonType.Employee, (p, pe) => - // pe.EmployeeId != null); - - // try - // { - // // 获取处方基础信息(添加总成本属性) - // var prescriptionPage = await query.OrderByDescending((p, pe, emp) => p.CreateTime) - // .Select((p, pe, emp) => new PrescriptionDto - // { - // Id = p.Id, - // PersonId = p.PersonId, - // PersonName = pe.Name, - // PersonType = pe.EmployeeId != null ? PersonType.Relative : PersonType.Employee, - // VisitDate = p.VisitDate, - // CreateTime = p.CreateTime.Value, - // EmployeeName = emp.Name, - // CanEdit = false, - // TotalMedicineCost = 0 // 初始化总成本 - // }).ToPagedListAsync(input.PageNum, input.PageSize); - - // // 设置可编辑状态 - // foreach (var item in prescriptionPage.List) - // { - // if (item.CreateTime.Date == DateTime.Now.Date || UserManager.SuperAdmin) - // { - // item.CanEdit = true; - // } - // } - - // // 获取当前页所有处方的药材明细 - // var pidList = prescriptionPage.List.Select(a => a.Id).ToList(); - // var prescriptionHerbList = await Context.Queryable() - // .Where(a => pidList.Contains(a.PrescriptionId)) - // .ToListAsync(); - - // if (prescriptionHerbList.Any()) - // { - // // 1. 按【处方ID+药材ID】分组,统计每个处方中每种药材的总使用量 - // var prescriptionMedicinalUsage = prescriptionHerbList - // .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - // .Select(g => new - // { - // PrescriptionId = g.Key.PrescriptionId, - // MedicinalId = g.Key.MedicinalId, - // TotalUsedWeight = g.Sum(h => h.AmountG) // 同一处方中同一药材的总用量 - // }) - // .ToList(); - - // // 2. 收集所有涉及的药材ID,批量获取FIFO计算所需数据 - // var medicinalIds = prescriptionMedicinalUsage.Select(u => u.MedicinalId).Distinct().ToList(); - // var fifoData = await GetMedicinalFifoData(medicinalIds); - - // // 3. 按处方ID分组,计算每个处方的总成本 - // var groupedByPrescription = prescriptionMedicinalUsage - // .GroupBy(u => u.PrescriptionId) - // .ToDictionary(g => g.Key, g => g.ToList()); - - // // 4. 遍历处方,计算总成本 - // foreach (var prescription in prescriptionPage.List) - // { - // if (groupedByPrescription.TryGetValue(prescription.Id, out var usages)) - // { - // foreach (var usage in usages) - // { - // // 基于FIFO计算当前药材的使用成本 - // var herbCost = CalculateHerbCostByFifo( - // fifoData, - // usage.MedicinalId, - // usage.TotalUsedWeight - // ); - - // // 累加到处方总成本 - // prescription.TotalMedicineCost += herbCost; - // } - // } - // } - // } - // foreach (var item in prescriptionPage.List) - // { - // //家属成本多十个点 - // if (item.PersonType== PersonType.Relative) - // { - // item.TotalMedicineCost = Math.Round(item.TotalMedicineCost * (decimal)1.1, 2, MidpointRounding.AwayFromZero); - // } - // } - // return prescriptionPage; - // } - // catch (Exception ex) - // { - // Console.WriteLine($"错误: {ex.Message}"); - // throw; - // } - //} - - ///// - ///// 获取药材FIFO计算所需的基础数据(入库记录) - ///// - //private async Task>> GetMedicinalFifoData(List medicinalIds) - //{ - // if (!medicinalIds.Any()) - // return new Dictionary>(); - - // // 批量查询所有涉及药材的入库记录(按时间排序) - // var addLogs = await Context.Queryable() - // .Where(l => medicinalIds.Contains(l.MedicinalId)) - // .OrderBy(l => l.CreateTime) - // .Select(l => new MedicinalFifoRecord - // { - // MedicinalId = l.MedicinalId, - // AddWeight = l.AddWeight, - // UnitPrice = l.UnitPrice - // }) - // .ToListAsync(); - - // // 按药材ID分组 - // return addLogs.GroupBy(l => l.MedicinalId) - // .ToDictionary(g => g.Key, g => g.ToList()); - //} - - ///// - ///// 按FIFO规则计算单种药材的使用成本 - ///// - //private decimal CalculateHerbCostByFifo( - // Dictionary> fifoData, - // long medicinalId, - // decimal usedWeight) - //{ - // if (usedWeight <= 0 || !fifoData.TryGetValue(medicinalId, out var records) || !records.Any()) - // return 0; - - // decimal remainingToCalculate = usedWeight; - // decimal totalCost = 0; - - // // 按入库顺序依次消耗 - // foreach (var record in records) - // { - // if (remainingToCalculate <= 0) - // break; - - // if (record.AddWeight <= remainingToCalculate) - // { - // // 当前批次全部消耗 - // totalCost += record.AddWeight * record.UnitPrice; - // remainingToCalculate -= record.AddWeight; - // } - // else - // { - // // 消耗当前批次的部分量 - // totalCost += remainingToCalculate * record.UnitPrice; - // remainingToCalculate = 0; - // } - // } - // return Math.Round(totalCost, 2, MidpointRounding.AwayFromZero); - //} - - - public async Task> GetPrescriptionList(PrescriptionQueryInput input) - { - var query = Context.Queryable() - .LeftJoin((p, pe) => p.PersonId == pe.Id) - .LeftJoin((p, pe, emp) => pe.EmployeeId != null && pe.EmployeeId == emp.Id) - .WhereIF(!string.IsNullOrEmpty(input.PersonName), (p, pe, emp) => - input.PersonName.Contains(pe.Name) || pe.Name.Contains(input.PersonName) || - input.PersonName.Contains(emp.Name) || emp.Name.Contains(input.PersonName)) - .WhereIF(input.PersonType.HasValue && input.PersonType == PersonType.Employee, (p, pe) => - pe.EmployeeId == null) - .WhereIF(input.PersonType.HasValue && input.PersonType != PersonType.Employee, (p, pe) => - pe.EmployeeId != null); - - try - { - // 获取处方基础信息 - var prescriptionPage = await query.OrderByDescending((p, pe, emp) => p.CreateTime) - .Select((p, pe, emp) => new PrescriptionDto - { - Id = p.Id, - PersonId = p.PersonId, - PersonName = pe.Name, - PersonType = pe.EmployeeId != null ? PersonType.Relative : PersonType.Employee, - VisitDate = p.VisitDate, - CreateTime = p.CreateTime.Value, - EmployeeName = emp.Name, - CanEdit = false, - TotalMedicineCost = 0, - Type = pe.Type - }).ToPagedListAsync(input.PageNum, input.PageSize); - if (!prescriptionPage.List.Any()) return prescriptionPage; - // 获取当前页所有处方的 Id - var pidList = prescriptionPage.List.Select(a => a.Id).ToList(); - - // ------------------ “所有处方”按时间的消耗 ------------------ - - // 1) 取出所有处方 Id(按时间升序),用于按时间顺序模拟消耗 - var allPrescriptionIds = await Context.Queryable() - .OrderBy(p => p.CreateTime) - .Select(p => p.Id) - .ToListAsync(); - - // 2) 拉取所有处方对应的药材明细 - var allPrescriptionHerbList = await Context.Queryable() - .Where(ph => allPrescriptionIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - // 3) 按【处方ID+药材ID】分组,统计每个处方中每种药材的总使用量(全量) - var allUsageGroups = allPrescriptionHerbList - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - PrescriptionId = g.Key.PrescriptionId, - MedicinalId = g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - // 4) 收集所有涉及的药材 ID,批量获取 FIFO 入库数据 - var allMedicinalIds = allUsageGroups.Select(u => u.MedicinalId).Distinct().ToList(); - var fifoData = await GetMedicinalFifoData(allMedicinalIds); - - // 5) 为每个处方建立快速查找:PrescriptionId -> usages - var groupedByPrescriptionAll = allUsageGroups - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - // 6) 初始化 FIFO 偏移(累计消耗量)字典偏移字典 - var fifoOffsets = new Dictionary(); - - // 7) 模拟按时间顺序消耗所有处方,并把每张处方的成本记录到字典 - var prescriptionCostDict = new Dictionary(); - - foreach (var pid in allPrescriptionIds) - { - decimal presCost = 0; - - if (groupedByPrescriptionAll.TryGetValue(pid, out var usages)) - { - foreach (var usage in usages) - { - var herbCost = CalculateHerbCostByFifoWithOffset( - fifoData, - fifoOffsets, - usage.MedicinalId, - usage.TotalUsedWeight - ); - - presCost += herbCost; - } - } - - // 四舍五入到 4 位(在分处方层面保留更多精度,最后显示再 round 2 位) - prescriptionCostDict[pid] = Math.Round(presCost, 4, MidpointRounding.AwayFromZero); - } - //decimal all = 0; - // 8) 将计算结果映射回当前页的处方 - foreach (var item in prescriptionPage.List) - { - if (prescriptionCostDict.TryGetValue(item.Id, out var cost)) - { - item.TotalMedicineCost = cost; - } - // 设置 CanEdit - if (item.CreateTime.Date == DateTime.Now.Date || UserManager.SuperAdmin) - { - item.CanEdit = true; - } - //all += item.TotalMedicineCost; - // 家属和普通员工加价 10% - if (item.PersonType == PersonType.Relative || item.Type == 2) - { - item.TotalMedicineCost = Math.Round(item.TotalMedicineCost * 1.1m, 2, MidpointRounding.AwayFromZero); - } - else - { - item.TotalMedicineCost = Math.Round(item.TotalMedicineCost, 2, MidpointRounding.AwayFromZero); - } - - } - //var all= prescriptionPage.List.Sum(a => a.TotalMedicineCost); - //var cc = await GetAllPrescriptionTotalCost(); - return prescriptionPage; - } - catch (Exception ex) - { - Console.WriteLine($"错误: {ex.Message}"); - throw; - } - } - /// - /// 获取所有处方的总药材成本 - /// - /// - public async Task GetAllPrescriptionTotalCost() - { - // 1) 获取所有处方的 ID(按创建时间升序),并明确类型为 long - var allPrescriptionIds = await Context.Queryable() - .OrderBy(p => p.CreateTime) - .Select(p => p.Id) // 确保这里的 Id 类型是 long 或 long? - .ToListAsync(); - - if (!allPrescriptionIds.Any()) - return 0m; - - // 把 id 列表规范为 long 列表(处理可能的 nullable) - var allIdsLong = allPrescriptionIds.Select(id => Convert.ToInt64(id)).ToList(); - - // 2) 获取所有处方的药材使用明细 - var allPrescriptionHerbList = await Context.Queryable() - .Where(ph => allIdsLong.Contains(Convert.ToInt64(ph.PrescriptionId))) - .ToListAsync(); - - var allUsageGroups = allPrescriptionHerbList - .GroupBy(h => new { PrescriptionId = Convert.ToInt64(h.PrescriptionId), h.MedicinalId }) - .Select(g => new - { - PrescriptionId = g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - // 3) 获取所有药材的 FIFO 入库记录 - var allMedicinalIds = allUsageGroups.Select(u => u.MedicinalId).Distinct().ToList(); - var fifoData = await GetMedicinalFifoData(allMedicinalIds); - - // 4) 按处方构建使用分组(key 为 long) - var groupedByPrescriptionAll = allUsageGroups - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - // 5) FIFO 偏移量 - var fifoOffsets = new Dictionary(); - - decimal totalSum = 0m; - - // 6) 获取每张处方的人员类型(IsRelative: bool),并把 key 明确为 long,避免类型不匹配 - var personTmp = await Context.Queryable() - .LeftJoin((p, pe) => p.PersonId == pe.Id) - .Where(p => allIdsLong.Contains(Convert.ToInt64(p.Id))) - .Select((p, pe) => new - { - Id = p.Id, - IsRelative = pe.EmployeeId != null, - Type = pe.Type - }) - .ToListAsync(); - - // 明确转换 key 为 long(处理 nullable) - var personInfoDict = personTmp - .ToDictionary(x => Convert.ToInt64(x.Id), x => new { x.IsRelative, x.Type }); - - // 7) FIFO 成本计算(按时间顺序已由 allIdsLong 保持) - foreach (var pidObj in allIdsLong) - { - long pid = pidObj; // 明确 pid 是 long - - decimal presCost = 0m; - - if (groupedByPrescriptionAll.TryGetValue(pid, out var usages)) - { - foreach (var usage in usages) - { - var cost = CalculateHerbCostByFifoWithOffset( - fifoData, - fifoOffsets, - usage.MedicinalId, - usage.TotalUsedWeight - ); - - presCost += cost; - } - } - - // 处方级别保留 4 位小数 - presCost = Math.Round(presCost, 4, MidpointRounding.AwayFromZero); - - // 家属和普通员工加价 10% - personInfoDict.TryGetValue(pid, out var personInfo); - var isRelative = personInfo?.IsRelative ?? false; - var isOrdinary = personInfo?.Type == 2; - if (isRelative || isOrdinary) - { - presCost = Math.Round(presCost * 1.1m, 2, MidpointRounding.AwayFromZero); - } - else - { - presCost = Math.Round(presCost, 2, MidpointRounding.AwayFromZero); - } - - totalSum += presCost; - } - - return totalSum; - } - - - - - /// - /// 获取药材FIFO计算所需的基础数据(入库记录) - /// - private async Task>> GetMedicinalFifoData(List medicinalIds) - { - if (!medicinalIds.Any()) - return new Dictionary>(); - - // 批量查询所有涉及药材的入库记录(按时间排序) - var addLogs = await Context.Queryable() - .Where(l => medicinalIds.Contains(l.MedicinalId)) - .OrderBy(l => l.CreateTime) - .Select(l => new MedicinalFifoRecord - { - MedicinalId = l.MedicinalId, - AddWeight = l.AddWeight, - UnitPrice = l.UnitPrice - }) - .ToListAsync(); - - // 按药材ID分组 - return addLogs.GroupBy(l => l.MedicinalId) - .ToDictionary(g => g.Key, g => g.ToList()); - } - - /// - /// 按FIFO规则计算单种药材的使用成本(累计消耗) - /// - private decimal CalculateHerbCostByFifoWithOffset( - Dictionary> fifoData, - Dictionary fifoOffsets, - long medicinalId, - decimal usedWeight) - { - if (usedWeight <= 0 || !fifoData.TryGetValue(medicinalId, out var records) || !records.Any()) - return 0; - - decimal alreadyUsed = fifoOffsets.GetValueOrDefault(medicinalId, 0); - decimal remainingToUse = usedWeight; - decimal totalCost = 0; - - foreach (var record in records) - { - if (remainingToUse <= 0) - break; - - // 跳过已经消耗完的批次 - if (alreadyUsed >= record.AddWeight) - { - alreadyUsed -= record.AddWeight; - continue; - } - - // 当前批次可用量 - decimal available = record.AddWeight - alreadyUsed; - decimal toConsume = Math.Min(available, remainingToUse); - - totalCost += toConsume * record.UnitPrice; - remainingToUse -= toConsume; - alreadyUsed = 0; - - } - - // 更新累计消耗量 - fifoOffsets[medicinalId] = fifoOffsets.GetValueOrDefault(medicinalId, 0) + usedWeight; - - return Math.Round(totalCost, 4, MidpointRounding.AwayFromZero); - } - - - /// - /// 获取处方详情 - /// - /// - /// - /// - public async Task GetPrescriptionDetail(long id) - { - var prescription = await Context.Queryable() - .Where(p => p.Id == id) - .FirstAsync(); - - if (prescription == null) - { - throw Oops.Bah("处方不存在"); - } - - var person = await Context.Queryable() - .Where(pe => pe.Id == prescription.PersonId) - .FirstAsync(); - - var herbs = await Context.Queryable((ph, mt) => ph.MedicinalId == mt.Id) - .Where(ph => ph.PrescriptionId == id) - .Select((ph, mt) => new PrescriptionHerbDto - { - MedicinalId = mt.Id, - MedicinalName = mt.MedicinalName, - AmountG = ph.AmountG, - Note = ph.Note - }) - .ToListAsync(); - - // 判断是否是员工还是家属 - PersonDto employee = null; - if (person.EmployeeId.HasValue) - { - var empPerson = await Context.Queryable() - .Where(pe => pe.Id == person.EmployeeId) - .Select(pe => new PersonDto - { - Id = pe.Id, - Name = pe.Name - }) - .FirstAsync(); - - employee = empPerson; - } - var RelationShipName = await GetRelationTypes(); - return new PrescriptionDetailDto - { - Id = prescription.Id, - Person = new PersonDetailDto - { - Id = person.Id, - Name = person.Name, - Birthday = person.Birthday, - Weight = prescription.Weight, - Height = person.Height, - IsEmployee = !person.EmployeeId.HasValue, - EmployeeId = person.EmployeeId, - EmployeeName = employee?.Name, - RelationShip = person.RelationShip, - RelationShipName = RelationShipName.FirstOrDefault(t => t.Id == person.RelationShip)?.Name, - Type = person.Type - }, - DiagnosisResult = prescription.DiagnosisResult, - UserMedicinaAdvice = prescription.UserMedicinaAdvice, - VisitDate = prescription.VisitDate, - Herbs = herbs, - CanEdit = prescription.CreateTime.Value.Date == DateTime.Now.Date - }; - } - /// - /// 添加编辑处方记录 - /// - /// - /// - public async Task SavePrescription(SavePrescriptionInput input) - { - // 基础参数验证 - if (input == null) - throw Oops.Bah("输入参数不能为空"); - - if (input.Herbs == null || !input.Herbs.Any()) - throw Oops.Bah("处方药材不能为空"); - - await Context.Ado.BeginTranAsync(); - try - { - // 用于在方法内记录新创建的员工 id(如果需要) - long? createdEmployeeId = null; - - // ---------- 1. 处理前端在 person 中携带的“临时员工”(如果存在) ---------- - if (input.Person == null) - throw Oops.Bah("人员信息不能为空"); - - // 场景 A: 病人是家属(IsEmployee == false),但关联的员工是前端临时新增 - if (!input.Person.IsEmployee) - { - // 如果前端明确标记关联员工为临时新增(EmployeeIsTemp),需要先创建员工 - if (input.Person.EmployeeIsTemp) - { - if (string.IsNullOrWhiteSpace(input.Person.EmployeeName)) - throw Oops.Bah("标记了临时关联员工,但未提供员工姓名"); - - // 创建新员工记录(作为 Person 表的一条记录,RelationShip=null, EmployeeId=null) - var newEmp = new Person - { - Id = YitIdHelper.NextId(), - Name = input.Person.EmployeeName?.Trim(), - }; - await Context.Insertable(newEmp).ExecuteCommandAsync(); - createdEmployeeId = newEmp.Id; - } - else if (input.Person.EmployeeId.HasValue && input.Person.EmployeeId.Value > 0) - { - // 如果前端传的是已有员工 ID,校验该员工是否存在 - var exists = await Context.Queryable() - .AnyAsync(p => p.Id == input.Person.EmployeeId.Value); - if (!exists) - throw Oops.Bah($"关联的员工 ID={input.Person.EmployeeId.Value} 不存在"); - } - else if (!string.IsNullOrWhiteSpace(input.Person.EmployeeName)) - { - var newEmp = new Person - { - Id = YitIdHelper.NextId(), - Name = input.Person.EmployeeName.Trim(), - }; - await Context.Insertable(newEmp).ExecuteCommandAsync(); - createdEmployeeId = newEmp.Id; - } - else - { - // 没有绑定员工信息(既不是 temp,也没有 employeeId),则无法继续 - if (input.Person.Id == null || input.Person.Id <= 0) - throw Oops.Bah("家属未关联员工,请选择或新增关联员工"); - } - } - else - { - // 病人是公司员工(IsEmployee == true) - // 如果没有 Id,但前端同时将该员工标记为临时新增,或者传了 Name 而无 Id,则创建员工 - if ((!input.Person.Id.HasValue || input.Person.Id.Value <= 0) && - (!string.IsNullOrWhiteSpace(input.Person.Name) || input.Person.EmployeeIsTemp)) - { - // 如果前端对员工也标记了 EmployeeIsTemp 且提供了 EmployeeName,则优先使用 EmployeeName(兼容性) - string empNameForCreate = !string.IsNullOrWhiteSpace(input.Person.Name) ? input.Person.Name.Trim() : input.Person.EmployeeName?.Trim(); - if (string.IsNullOrWhiteSpace(empNameForCreate)) - throw Oops.Bah("新增员工时姓名不能为空"); - - var newEmp = new Person - { - Id = YitIdHelper.NextId(), - Name = empNameForCreate, - Birthday = input.Person.Birthday, - Height = input.Person.Height, - }; - await Context.Insertable(newEmp).ExecuteCommandAsync(); - // 将新创建的员工 id 作为主 person id(病人本身) - input.Person.Id = newEmp.Id; - } - else if (input.Person.Id.HasValue && input.Person.Id.Value > 0) - { - // 校验存在性 - var exists = await Context.Queryable().AnyAsync(p => p.Id == input.Person.Id.Value); - if (!exists) - throw Oops.Bah($"指定的人员 ID={input.Person.Id.Value} 不存在"); - } - } - - // ---------- 2. 确定主 personId(如果是临时创建的员工, input.Person.Id 已在上一步设置) ---------- - long personId; - if (input.Person.Id.HasValue && input.Person.Id.Value > 0) - { - personId = input.Person.Id.Value; - // 已存在的人员(或上一步创建的员工),我们仍然可以继续使用 Storageable 更新信息 - } - else - { - // 没有 Id,需新建主人员(可能是家属或员工) - if (string.IsNullOrWhiteSpace(input.Person.Name)) - throw Oops.Bah("新增人员信息不完整,姓名为必填项"); - - personId = YitIdHelper.NextId(); - } - - // ---------- 3. 保存/更新主人员信息(使用 Storageable,兼容插入或更新) ---------- - var mappedEmployeeId = input.Person.EmployeeId; - - // 如果之前创建了员工(createdEmployeeId),优先使用该 id 作为家属的 EmployeeId - if (createdEmployeeId.HasValue) - mappedEmployeeId = createdEmployeeId.Value; - - // 如果 person.IsEmployee == true,则 person.EmployeeId 应为 null(员工不需要关联员工) - if (input.Person.IsEmployee) - mappedEmployeeId = null; - - var dbPerson = await Context.Queryable().FirstAsync(p => p.Id == personId); - if (dbPerson != null) - { - dbPerson.Name = input.Person?.Name ?? dbPerson.Name; - dbPerson.Birthday = input.Person?.Birthday ?? dbPerson.Birthday; - dbPerson.Height = input.Person?.Height ?? dbPerson.Height; - dbPerson.RelationShip = input.Person?.RelationShip ?? dbPerson.RelationShip; - dbPerson.EmployeeId = mappedEmployeeId; - if (input.Person != null && input.Person.IsEmployee) - { - dbPerson.Type = input.Person?.Type; - } - else - { - dbPerson.Type = null; - } - await Context.Updateable(dbPerson).ExecuteCommandAsync(); - } - else - { - var person = new Person - { - Id = personId, - Name = input.Person?.Name, - Birthday = input.Person?.Birthday, - Height = input.Person?.Height, - RelationShip = input.Person?.RelationShip, - EmployeeId = mappedEmployeeId, - Type = input.Person.IsEmployee ? input.Person?.Type : null - }; - await Context.Insertable(person).ExecuteCommandAsync(); - } - - // ---------- 4. 处方保存/编辑逻辑---------- - Prescription prescription; - if (input.Id.HasValue) // 编辑 - { - prescription = await Context.Queryable() - .FirstAsync(p => p.Id == input.Id.Value); - - if (prescription == null) - throw Oops.Bah("处方不存在"); - - if (prescription.CreateTime.Value.Date != DateTime.Now.Date && !UserManager.SuperAdmin) - throw Oops.Bah("只能编辑当天的处方"); - - // 查询原有消耗记录并恢复库存 - var oldHerbs = await Context.Queryable() - .Where(ph => ph.PrescriptionId == input.Id.Value) - .ToListAsync(); - - if (oldHerbs.Count > 0) - { - foreach (var g in oldHerbs.GroupBy(x => x.MedicinalId)) - { - // 恢复库存(加回已消耗) - await Context.Updateable() - .SetColumns(m => new Medicinal { Number = m.Number + g.Sum(x => x.AmountG) }) - .Where(m => m.Id == g.Key) - .ExecuteCommandAsync(); - } - } - - // 删除原有处方药材 - await Context.Deleteable() - .Where(ph => ph.PrescriptionId == input.Id.Value) - .ExecuteCommandAsync(); - - // 更新处方 - prescription.PersonId = personId; - prescription.Weight = input.Person.Weight; - prescription.DiagnosisResult = input.DiagnosisResult; - prescription.UserMedicinaAdvice = input.UserMedicinaAdvice; - prescription.VisitDate = input.VisitDate ?? DateTime.Now; - await Context.Updateable(prescription).ExecuteCommandAsync(); - } - else // 新增 - { - var prescripId = YitIdHelper.NextId(); - prescription = new Prescription - { - Id = prescripId, - Weight = input.Person.Weight, - PersonId = personId, - DiagnosisResult = input.DiagnosisResult, - UserMedicinaAdvice = input.UserMedicinaAdvice, - VisitDate = input.VisitDate ?? DateTime.Now, - }; - await Context.Insertable(prescription).ExecuteCommandAsync(); - input.Id = prescripId; - } - - // ---------- 5. 校验库存 & 扣减 & 插入消耗记录 ---------- - var herbIds = input.Herbs.Select(h => h.Id).ToList(); - var medicinalList = await Context.Queryable() - .Where(m => herbIds.Contains(m.Id)) - .ToListAsync(); - List HerbsId = new List(); - foreach (var herb in input.Herbs) - { - var medicinal = medicinalList.FirstOrDefault(m => m.Id == herb.Id); - if (medicinal == null) - throw Oops.Bah($"药材[{herb.Id}]不存在"); - if (herb.AmountG <= 0) - throw Oops.Bah($"请填写正确的消耗量,药材[{medicinal.MedicinalName}]"); - if (medicinal.Number < herb.AmountG) - throw Oops.Bah($"药材[{medicinal.MedicinalName}]库存不足,当前库存: {medicinal.Number}g,需要: {herb.AmountG}g"); - if (HerbsId.Contains(herb.Id)) throw Oops.Bah($"请勿重复添加同一个药材【{medicinal.MedicinalName}】"); - HerbsId.Add(herb.Id); - medicinal.Number -= herb.AmountG; - } - - // 批量更新药材库存 - await Context.Updateable(medicinalList).ExecuteCommandAsync(); - - // 批量插入处方药材 - var prescriptionHerbs = input.Herbs.Select(h => new PrescriptionHerb - { - PrescriptionId = input.Id.Value, - MedicinalId = h.Id, - AmountG = h.AmountG, - Note = h.Note - }).ToList(); - await Context.Insertable(prescriptionHerbs).ExecuteCommandAsync(); - - await Context.Ado.CommitTranAsync(); - return input.Id.Value; - } - catch - { - await Context.Ado.RollbackTranAsync(); - throw; - } - } - - /// - /// 获取 人员下拉 - /// - /// - /// - /// - public async Task> GetPersonList(PersonType? type, long? employeeId) - { - var query = Context.Queryable(); - - // 筛选员工或家属 - if (type.HasValue) - { - if (type == PersonType.Employee) - { - query = query.Where(pe => pe.EmployeeId == null); - } - else if (type == PersonType.Relative && employeeId.HasValue) - { - query = query.Where(pe => pe.EmployeeId == employeeId); - } - } - - return await query.Select(pe => new PersonDto - { - Id = pe.Id, - Name = pe.Name, - Birthday = pe.Birthday, - Height = pe.Height, - RelationShip = pe.RelationShip, - Type = pe.Type - }).ToListAsync(); - } - /// - /// 获取关系下拉 - /// - /// - public async Task> GetRelationTypes() - { - var sysmodel = await Context.Queryable().FirstAsync(a => a.DictValue == "Relation"); - if (sysmodel != null) - { - return await Context.Queryable().Where(a => a.ParentId == sysmodel.Id).Select(pe => new RelationTypeDto - { - Id = int.Parse(pe.DictValue), - Name = pe.DictLabel, - }).ToListAsync(); - } - else - { - return new List - { - new RelationTypeDto { Id = 1, Name = "配偶" }, - new RelationTypeDto { Id = 2, Name = "子女" }, - new RelationTypeDto { Id = 3, Name = "父母" }, - new RelationTypeDto { Id = 4, Name = "兄弟姐妹" }, - new RelationTypeDto { Id = 5, Name = "其他" } - }; - } - } -} diff --git a/SimpleAdmin.Application/Services/Statistics/Dto/StatisticsDto.cs b/SimpleAdmin.Application/Services/Statistics/Dto/StatisticsDto.cs deleted file mode 100644 index 93c7653..0000000 --- a/SimpleAdmin.Application/Services/Statistics/Dto/StatisticsDto.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin - -namespace SimpleAdmin.Application.Services.Statistics -{ - /// - /// 年度统计数据 DTO(对应前端 YearlyStatisticsDto) - /// - public class YearlyStatisticsDto - { - /// 统计年份(如 "2025") - public string Year { get; set; } - - /// 处方总花费(元) - public decimal TotalCost { get; set; } - - /// 处方总数量(张) - public int TotalQty { get; set; } - - /// 员工处方花费(元) - public decimal StaffCost { get; set; } - - /// 家属处方花费(元) - public decimal FamilyCost { get; set; } - - /// 员工处方数量(张) - public int StaffQty { get; set; } - - /// 家属处方数量(张) - public int FamilyQty { get; set; } - - /// 药材耗材花费(元)—— 当年所有入库药材总价 - public decimal MaterialCost { get; set; } - - /// 服务人数(当年有过处方记录的不重复人员数) - public int ServiceCount { get; set; } - - // ---------- 同比趋势(百分比,正数为增长,负数为下降) ---------- - - /// 处方总花费同比趋势 (%) - public decimal TotalCostTrend { get; set; } - - /// 处方总数量同比趋势 (%) - public decimal TotalQtyTrend { get; set; } - - /// 药材花费同比趋势 (%) - public decimal MaterialCostTrend { get; set; } - - /// 服务人数同比趋势 (%) - public decimal ServiceCountTrend { get; set; } - } - - /// - /// 月度明细数据 DTO(对应前端 MonthlyDetailDto) - /// - public class MonthlyDetailDto - { - /// 月份显示(如 "1月") - public string Month { get; set; } - - /// 员工处方花费(元) - public decimal StaffCost { get; set; } - - /// 家属处方花费(元) - public decimal FamilyCost { get; set; } - - /// 员工处方数量(张) - public int StaffQty { get; set; } - - /// 家属处方数量(张) - public int FamilyQty { get; set; } - - /// 药材耗材花费(元)—— 当月入库总价 - public decimal MaterialCost { get; set; } - } - - /// - /// 全量总览 DTO(不区分年份,含剩余药材价值) - /// - public class TotalOverviewDto - { - /// 处方总花费(元,含所有年份) - public decimal TotalCost { get; set; } - - /// 处方总数量(张) - public int TotalQty { get; set; } - - /// 员工处方花费(元) - public decimal StaffCost { get; set; } - - /// 家属处方花费(元) - public decimal FamilyCost { get; set; } - - /// 员工处方数量(张) - public int StaffQty { get; set; } - - /// 家属处方数量(张) - public int FamilyQty { get; set; } - - /// 药材采购总花费(元,历史所有入库总额) - public decimal MaterialCost { get; set; } - - /// 累计服务人数(不重复人员) - public int ServiceCount { get; set; } - - /// 当前剩余药材库存价值(元,按最新入库单价估算) - public decimal RemainingMedicinalValue { get; set; } - } -} diff --git a/SimpleAdmin.Application/Services/Statistics/IStatisticsService.cs b/SimpleAdmin.Application/Services/Statistics/IStatisticsService.cs deleted file mode 100644 index 0c3a3ed..0000000 --- a/SimpleAdmin.Application/Services/Statistics/IStatisticsService.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin - -namespace SimpleAdmin.Application.Services.Statistics -{ - /// - /// 统计分析 Service 接口 - /// - public interface IStatisticsService : ITransient - { - /// - /// 获取全量总览数据(不区分年份,含剩余药材库存价值) - /// - Task GetTotalOverview(); - - /// - /// 获取指定年份的年度汇总统计数据(含同比趋势) - /// - /// 年份,如 2025 - Task GetYearlyStatistics(int year); - - /// - /// 获取指定年份的逐月明细数据(返回 12 条,无数据月份补零) - /// - /// 年份,如 2025 - Task> GetMonthlyDetails(int year); - } -} diff --git a/SimpleAdmin.Application/Services/Statistics/StatisticsService.cs b/SimpleAdmin.Application/Services/Statistics/StatisticsService.cs deleted file mode 100644 index 4391105..0000000 --- a/SimpleAdmin.Application/Services/Statistics/StatisticsService.cs +++ /dev/null @@ -1,545 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin - -using SimpleAdmin.Application.Entity; -using SimpleAdmin.Application.Services.Statistics; - -/// -/// 统计分析 Service 实现 -/// -public class StatisticsService : DbRepository, IStatisticsService -{ - // ───────────────────────────────────────────────────────────── - // 公开接口 - // ───────────────────────────────────────────────────────────── - - /// - public async Task GetTotalOverview() - { - // 1) 所有处方(按创建时间升序,FIFO 需要) - var prescriptionInfos = await Context.Queryable() - .LeftJoin((p, pe) => p.PersonId == pe.Id) - .OrderBy((p, pe) => p.CreateTime) - .Select((p, pe) => new - { - p.Id, - p.PersonId, - IsRelative = pe.EmployeeId != null, - Type = pe.Type - }) - .ToListAsync(); - - decimal staffCost = 0, familyCost = 0; - int staffQty = 0, familyQty = 0; - - if (prescriptionInfos.Any()) - { - var allIds = prescriptionInfos.Select(x => x.Id).ToList(); - - var allHerbs = await Context.Queryable() - .Where(ph => allIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - var usageGroups = allHerbs - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - var allMedicinalIds = usageGroups.Select(u => u.MedicinalId).Distinct().ToList(); - var fifoData = await GetFifoData(allMedicinalIds); - var fifoOffsets = new Dictionary(); - - var usageByPres = usageGroups - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - foreach (var pInfo in prescriptionInfos) - { - decimal cost = 0; - if (usageByPres.TryGetValue(pInfo.Id, out var usages)) - foreach (var u in usages) - cost += CalculateFifoCost(fifoData, fifoOffsets, u.MedicinalId, u.TotalUsedWeight); - - cost = Math.Round(cost, 4, MidpointRounding.AwayFromZero); - - if (pInfo.IsRelative) - { - familyCost += Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - familyQty++; - } - else if (pInfo.Type == 2) - { - staffCost += Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - staffQty++; - } - else - { - staffCost += Math.Round(cost, 2, MidpointRounding.AwayFromZero); - staffQty++; - } - } - } - - // 2) 药材采购总花费(历史所有入库总额) - var materialCost = await Context.Queryable() - .SumAsync(l => l.TotalPrice); - - // 3) 累计服务人数(不重复人员) - var serviceCount = prescriptionInfos.Select(x => x.PersonId).Distinct().Count(); - - // 4) 剩余药材库存价值:每种药材当前库存 × 最新入库单价 - var medicinals = await Context.Queryable() - .Where(m => m.Number > 0) - .Select(m => new { m.Id, m.Number }) - .ToListAsync(); - - decimal remainingValue = 0; - if (medicinals.Any()) - { - var medIds = medicinals.Select(m => m.Id).ToList(); - - // 取每种药材最新的一条入库记录单价 - var latestPrices = await Context.Queryable() - .Where(l => medIds.Contains(l.MedicinalId)) - .GroupBy(l => l.MedicinalId) - .Select(l => new - { - MedicinalId = l.MedicinalId, - LatestPrice = SqlFunc.AggregateMax(l.UnitPrice) - }) - .ToListAsync(); - - var priceDict = latestPrices.ToDictionary(x => x.MedicinalId, x => x.LatestPrice); - - foreach (var med in medicinals) - { - if (priceDict.TryGetValue(med.Id, out var price)) - remainingValue += Math.Round(med.Number * price, 2, MidpointRounding.AwayFromZero); - } - } - - return new TotalOverviewDto - { - TotalCost = Math.Round(staffCost + familyCost, 2), - TotalQty = staffQty + familyQty, - StaffCost = Math.Round(staffCost, 2), - FamilyCost = Math.Round(familyCost, 2), - StaffQty = staffQty, - FamilyQty = familyQty, - MaterialCost = Math.Round(materialCost, 2), - ServiceCount = serviceCount, - RemainingMedicinalValue = Math.Round(remainingValue, 2), - }; - } - - /// - public async Task GetYearlyStatistics(int year) - { - var currentYearData = await BuildYearData(year); - var lastYearData = await BuildYearData(year - 1); - - return new YearlyStatisticsDto - { - Year = year.ToString(), - TotalCost = currentYearData.TotalCost, - TotalQty = currentYearData.TotalQty, - StaffCost = currentYearData.StaffCost, - FamilyCost = currentYearData.FamilyCost, - StaffQty = currentYearData.StaffQty, - FamilyQty = currentYearData.FamilyQty, - MaterialCost = currentYearData.MaterialCost, - ServiceCount = currentYearData.ServiceCount, - - TotalCostTrend = CalcTrend(lastYearData.TotalCost, currentYearData.TotalCost), - TotalQtyTrend = CalcTrend(lastYearData.TotalQty, currentYearData.TotalQty), - MaterialCostTrend = CalcTrend(lastYearData.MaterialCost, currentYearData.MaterialCost), - ServiceCountTrend = CalcTrend(lastYearData.ServiceCount, currentYearData.ServiceCount), - }; - } - - /// - public async Task> GetMonthlyDetails(int year) - { - var start = new DateTime(year, 1, 1); - var end = new DateTime(year, 12, 31, 23, 59, 59); - - // 1) 当年所有处方(按时间升序,供 FIFO 用) - var prescriptionInfos = await Context.Queryable() - .LeftJoin((p, pe) => p.PersonId == pe.Id) - .Where((p, pe) => p.VisitDate >= start && p.VisitDate <= end) - .OrderBy((p, pe) => p.CreateTime) - .Select((p, pe) => new - { - p.Id, - p.VisitDate, - p.CreateTime, - IsRelative = pe.EmployeeId != null, - Type = pe.Type - }) - .ToListAsync(); - - if (!prescriptionInfos.Any()) - return BuildEmptyMonthList(); - - var allPrescriptionIds = prescriptionInfos.Select(x => x.Id).ToList(); - - // 2) 批量拉取处方药材明细 - var allHerbs = await Context.Queryable() - .Where(ph => allPrescriptionIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - // 3) 按 处方ID+药材ID 分组,得到每张处方消耗每种药材的总量 - var usageGroups = allHerbs - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - // 4) FIFO 入库数据 - var allMedicinalIds = usageGroups.Select(u => u.MedicinalId).Distinct().ToList(); - var fifoData = await GetFifoData(allMedicinalIds); - - // 5) 需要在"所有历史处方"维度跑 FIFO,才能保证成本正确(与 PrescriptionService 逻辑一致) - // 先把当年之前的"历史"也加进来跑偏移 - var historyIds = await Context.Queryable() - .Where(p => p.VisitDate < start) - .OrderBy(p => p.CreateTime) - .Select(p => p.Id) - .ToListAsync(); - - var fifoOffsets = new Dictionary(); - - // 先消耗历史处方(建立偏移量),不需要计入结果 - if (historyIds.Any()) - { - var historyHerbs = await Context.Queryable() - .Where(ph => historyIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - var historyUsage = historyHerbs - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - var historyByPres = historyUsage - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - foreach (var hid in historyIds) - { - if (!historyByPres.TryGetValue(hid, out var usages)) continue; - foreach (var u in usages) - CalculateFifoCost(fifoData, fifoOffsets, u.MedicinalId, u.TotalUsedWeight); - } - } - - // 6) 计算当年每张处方的成本,按月汇总 - var usageByPres = usageGroups - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - // 月度桶:1–12 - var monthlyStaffCost = new decimal[13]; - var monthlyFamilyCost = new decimal[13]; - var monthlyStaffQty = new int[13]; - var monthlyFamilyQty = new int[13]; - - var presInfoDict = prescriptionInfos.ToDictionary(x => x.Id); - - foreach (var pInfo in prescriptionInfos) - { - int month = pInfo.VisitDate?.Month ?? pInfo.CreateTime?.Month ?? 0; - if (month < 1 || month > 12) continue; - - decimal cost = 0m; - if (usageByPres.TryGetValue(pInfo.Id, out var usages)) - { - foreach (var u in usages) - cost += CalculateFifoCost(fifoData, fifoOffsets, u.MedicinalId, u.TotalUsedWeight); - } - cost = Math.Round(cost, 4, MidpointRounding.AwayFromZero); - - if (pInfo.IsRelative) - { - cost = Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - monthlyFamilyCost[month] += cost; - monthlyFamilyQty[month]++; - } - else if (pInfo.Type == 2) - { - cost = Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - monthlyStaffCost[month] += cost; - monthlyStaffQty[month]++; - } - else - { - cost = Math.Round(cost, 2, MidpointRounding.AwayFromZero); - monthlyStaffCost[month] += cost; - monthlyStaffQty[month]++; - } - } - - // 7) 药材花费:按入库记录的月份汇总当年花费 - var materialLogs = await Context.Queryable() - .Where(l => l.CreateTime >= start && l.CreateTime <= end) - .Select(l => new { l.CreateTime, l.TotalPrice }) - .ToListAsync(); - - var monthlyMaterialCost = new decimal[13]; - foreach (var log in materialLogs) - { - int month = log.CreateTime?.Month ?? 0; - if (month >= 1 && month <= 12) - monthlyMaterialCost[month] += log.TotalPrice; - } - - // 8) 组装返回结果 - var result = new List(12); - for (int m = 1; m <= 12; m++) - { - result.Add(new MonthlyDetailDto - { - Month = $"{m}月", - StaffCost = Math.Round(monthlyStaffCost[m], 2), - FamilyCost = Math.Round(monthlyFamilyCost[m], 2), - StaffQty = monthlyStaffQty[m], - FamilyQty = monthlyFamilyQty[m], - MaterialCost = Math.Round(monthlyMaterialCost[m], 2), - }); - } - return result; - } - - // ───────────────────────────────────────────────────────────── - // 私有辅助方法 - // ───────────────────────────────────────────────────────────── - - /// - /// 计算指定年份的聚合数据(用于年度统计与同比计算) - /// - private async Task<(decimal TotalCost, int TotalQty, decimal StaffCost, decimal FamilyCost, - int StaffQty, int FamilyQty, decimal MaterialCost, int ServiceCount)> BuildYearData(int year) - { - var start = new DateTime(year, 1, 1); - var end = new DateTime(year, 12, 31, 23, 59, 59); - - // 当年处方(按时间升序,FIFO 需要) - var prescriptionInfos = await Context.Queryable() - .LeftJoin((p, pe) => p.PersonId == pe.Id) - .Where((p, pe) => p.VisitDate >= start && p.VisitDate <= end) - .OrderBy((p, pe) => p.CreateTime) - .Select((p, pe) => new - { - p.Id, - p.PersonId, - IsRelative = pe.EmployeeId != null, - Type = pe.Type - }) - .ToListAsync(); - - if (!prescriptionInfos.Any()) - return (0, 0, 0, 0, 0, 0, 0, 0); - - var allPrescriptionIds = prescriptionInfos.Select(x => x.Id).ToList(); - - var allHerbs = await Context.Queryable() - .Where(ph => allPrescriptionIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - var usageGroups = allHerbs - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .ToList(); - - var allMedicinalIds = usageGroups.Select(u => u.MedicinalId).Distinct().ToList(); - var fifoData = await GetFifoData(allMedicinalIds); - - // 历史偏移量(当年之前的处方) - var historyIds = await Context.Queryable() - .Where(p => p.VisitDate < start) - .OrderBy(p => p.CreateTime) - .Select(p => p.Id) - .ToListAsync(); - - var fifoOffsets = new Dictionary(); - if (historyIds.Any()) - { - var historyHerbs = await Context.Queryable() - .Where(ph => historyIds.Contains(ph.PrescriptionId)) - .ToListAsync(); - - var historyUsage = historyHerbs - .GroupBy(h => new { h.PrescriptionId, h.MedicinalId }) - .Select(g => new - { - g.Key.PrescriptionId, - g.Key.MedicinalId, - TotalUsedWeight = g.Sum(h => h.AmountG) - }) - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - foreach (var hid in historyIds) - { - if (!historyUsage.TryGetValue(hid, out var usages)) continue; - foreach (var u in usages) - CalculateFifoCost(fifoData, fifoOffsets, u.MedicinalId, u.TotalUsedWeight); - } - } - - // 按处方计算成本 - var usageByPres = usageGroups - .GroupBy(u => u.PrescriptionId) - .ToDictionary(g => g.Key, g => g.ToList()); - - decimal staffCost = 0, familyCost = 0; - int staffQty = 0, familyQty = 0; - - foreach (var pInfo in prescriptionInfos) - { - decimal cost = 0; - if (usageByPres.TryGetValue(pInfo.Id, out var usages)) - foreach (var u in usages) - cost += CalculateFifoCost(fifoData, fifoOffsets, u.MedicinalId, u.TotalUsedWeight); - - cost = Math.Round(cost, 4, MidpointRounding.AwayFromZero); - - if (pInfo.IsRelative) - { - familyCost += Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - familyQty++; - } - else if (pInfo.Type == 2) - { - staffCost += Math.Round(cost * 1.1m, 2, MidpointRounding.AwayFromZero); - staffQty++; - } - else - { - staffCost += Math.Round(cost, 2, MidpointRounding.AwayFromZero); - staffQty++; - } - } - - // 药材花费:当年所有入库记录的总额 - var materialCost = await Context.Queryable() - .Where(l => l.CreateTime >= start && l.CreateTime <= end) - .SumAsync(l => l.TotalPrice); - - // 服务人数:当年有处方的不重复人员 - var serviceCount = prescriptionInfos.Select(x => x.PersonId).Distinct().Count(); - - return ( - Math.Round(staffCost + familyCost, 2), - staffQty + familyQty, - Math.Round(staffCost, 2), - Math.Round(familyCost, 2), - staffQty, - familyQty, - Math.Round(materialCost, 2), - serviceCount - ); - } - - /// - /// 读取 FIFO 入库数据(按时间升序) - /// - private async Task>> GetFifoData(List medicinalIds) - { - if (!medicinalIds.Any()) - return new Dictionary>(); - - var logs = await Context.Queryable() - .Where(l => medicinalIds.Contains(l.MedicinalId)) - .OrderBy(l => l.CreateTime) - .Select(l => new MedicinalFifoRecord - { - MedicinalId = l.MedicinalId, - AddWeight = l.AddWeight, - UnitPrice = l.UnitPrice - }) - .ToListAsync(); - - return logs.GroupBy(l => l.MedicinalId) - .ToDictionary(g => g.Key, g => g.ToList()); - } - - /// - /// 按 FIFO 规则(含累计偏移)计算单次消耗成本,并推进偏移量 - /// - private static decimal CalculateFifoCost( - Dictionary> fifoData, - Dictionary fifoOffsets, - long medicinalId, - decimal usedWeight) - { - if (usedWeight <= 0 || !fifoData.TryGetValue(medicinalId, out var records) || !records.Any()) - return 0; - - decimal alreadyUsed = fifoOffsets.GetValueOrDefault(medicinalId, 0); - decimal remainingToUse = usedWeight; - decimal totalCost = 0; - - foreach (var record in records) - { - if (remainingToUse <= 0) break; - - if (alreadyUsed >= record.AddWeight) - { - alreadyUsed -= record.AddWeight; - continue; - } - - decimal available = record.AddWeight - alreadyUsed; - decimal toConsume = Math.Min(available, remainingToUse); - - totalCost += toConsume * record.UnitPrice; - remainingToUse -= toConsume; - alreadyUsed = 0; - } - - fifoOffsets[medicinalId] = fifoOffsets.GetValueOrDefault(medicinalId, 0) + usedWeight; - return Math.Round(totalCost, 4, MidpointRounding.AwayFromZero); - } - - /// 计算同比增涨率(%),基期为 0 时返回 0 - private static decimal CalcTrend(T baseVal, T currentVal) where T : struct, IConvertible - { - decimal b = Convert.ToDecimal(baseVal); - decimal c = Convert.ToDecimal(currentVal); - if (b == 0) return 0; - return Math.Round((c - b) / b * 100, 1, MidpointRounding.AwayFromZero); - } - - /// 返回全零的 12 个月明细列表 - private static List BuildEmptyMonthList() - { - var list = new List(12); - for (int m = 1; m <= 12; m++) - list.Add(new MonthlyDetailDto { Month = $"{m}月" }); - return list; - } -} diff --git a/SimpleAdmin.Application/SimpleAdmin.Application.xml b/SimpleAdmin.Application/SimpleAdmin.Application.xml index 939e70e..a803db0 100644 --- a/SimpleAdmin.Application/SimpleAdmin.Application.xml +++ b/SimpleAdmin.Application/SimpleAdmin.Application.xml @@ -54,288 +54,11 @@ 排序码 - - - 药材 - - - - - 数量(g) - - - - - 药材关联id - - - - - 添加重量(g) - - - - - 药材单价 - - - - - 总价 - - - - - 若非空,表示此 person 是某员工的家属 - - - - 单位 cm,保留两位小数 - - - 单位 kg,保留两位小数 - - - 消耗克数,单位 g - 系统配置 - - - 未找到下拉框的时候传这个值代表添加新的药材 - - - - - 获取药材列表,带筛选 - - 药材名称筛选 - 页码 - 页大小 - - - - - 获取药材消耗记录 - - 药材ID - - - - - 获取药材下拉 - - - - - - 获取药材添加记录 - - 药材ID - - - - - 添加药材 - - 添加信息 - - - - - 修改药材添加记录(仅当天可修改) - - 记录ID - 修改信息 - - - - - 删除药材添加记录(仅当天可删除) - - 记录ID - - - - - 关联的员工名称 - - - - - 当前关联的员工是否是前端临时新增(需要后端创建) - - - - - 当 EmployeeIsTemp 为 true 或者前端直接传了员工名字时,后端可用此字段创建员工 - - - - - 获取处方列表,带筛选 - - 筛选条件 - - - - - 获取所有处方的成本 - - - - - - 获取处方详情 - - 处方ID - - - - - 保存处方(新增或编辑) - - 处方信息 - - - - - 获取人员列表(员工和家属) - - 人员类型 - 员工ID(用于获取家属) - - - - - 获取所有关系类型(写死在代码中) - - - - - - 年度统计数据 DTO(对应前端 YearlyStatisticsDto) - - - - 统计年份(如 "2025") - - - 处方总花费(元) - - - 处方总数量(张) - - - 员工处方花费(元) - - - 家属处方花费(元) - - - 员工处方数量(张) - - - 家属处方数量(张) - - - 药材耗材花费(元)—— 当年所有入库药材总价 - - - 服务人数(当年有过处方记录的不重复人员数) - - - 处方总花费同比趋势 (%) - - - 处方总数量同比趋势 (%) - - - 药材花费同比趋势 (%) - - - 服务人数同比趋势 (%) - - - - 月度明细数据 DTO(对应前端 MonthlyDetailDto) - - - - 月份显示(如 "1月") - - - 员工处方花费(元) - - - 家属处方花费(元) - - - 员工处方数量(张) - - - 家属处方数量(张) - - - 药材耗材花费(元)—— 当月入库总价 - - - - 全量总览 DTO(不区分年份,含剩余药材价值) - - - - 处方总花费(元,含所有年份) - - - 处方总数量(张) - - - 员工处方花费(元) - - - 家属处方花费(元) - - - 员工处方数量(张) - - - 家属处方数量(张) - - - 药材采购总花费(元,历史所有入库总额) - - - 累计服务人数(不重复人员) - - - 当前剩余药材库存价值(元,按最新入库单价估算) - - - - 统计分析 Service 接口 - - - - - 获取全量总览数据(不区分年份,含剩余药材库存价值) - - - - - 获取指定年份的年度汇总统计数据(含同比趋势) - - 年份,如 2025 - - - - 获取指定年份的逐月明细数据(返回 12 条,无数据月份补零) - - 年份,如 2025 - 机构服务 @@ -878,128 +601,5 @@ - - - 获取药材下拉 - - - - - - - 获取药材添加记录 - - - - - - - 添加药材 - - - - - - - 修改药材添加记录 - - - - - - - - 删除药材添加记录 - - - - - - - - 批量计算:使用成本、剩余价值、总使用量(先进先出法) - - 需要计算的药材ID列表 - - - - 获取所有处方的总药材成本 - - - - - - 获取药材FIFO计算所需的基础数据(入库记录) - - - - - 按FIFO规则计算单种药材的使用成本(累计消耗) - - - - - 获取处方详情 - - - - - - - - 添加编辑处方记录 - - - - - - - 获取 人员下拉 - - - - - - - - 获取关系下拉 - - - - - - 统计分析 Service 实现 - - - - - - - - - - - - - - 计算指定年份的聚合数据(用于年度统计与同比计算) - - - - - 读取 FIFO 入库数据(按时间升序) - - - - - 按 FIFO 规则(含累计偏移)计算单次消耗成本,并推进偏移量 - - - - 计算同比增涨率(%),基期为 0 时返回 0 - - - 返回全零的 12 个月明细列表 - diff --git a/SimpleAdmin.SqlSugar/SqlSugar.Development.json b/SimpleAdmin.SqlSugar/SqlSugar.Development.json index a945d35..65efa72 100644 --- a/SimpleAdmin.SqlSugar/SqlSugar.Development.json +++ b/SimpleAdmin.SqlSugar/SqlSugar.Development.json @@ -5,9 +5,9 @@ "ConnectionStrings": [ { "ConfigId": "SimpleAdmin", //租户ID - "ConnectionString": "AllowLoadLocalInfile=true;Server=116.168.197.2;User ID=admin;Password=so^867z$4S;Port=16306;Database=WeiBingJu;CharSet=utf8mb4;pooling=true;SslMode=None;min pool size=1;Connection Timeout=30;Pooling=false", //连接字符串 - "DbType": "MySql", //数据库类型 WeiBingJu - "IsAutoCloseConnection": true //是否自动释放 weibingjutest + "ConnectionString": "AllowLoadLocalInfile=true;Server=116.168.197.2;User ID=admin;Password=so^867z$4S;Port=16306;Database=OnboardX;CharSet=utf8mb4;pooling=true;SslMode=None;min pool size=1;Connection Timeout=30;Pooling=false", //连接字符串 + "DbType": "MySql", //数据库类型 + "IsAutoCloseConnection": true //是否自动释放 } // { // "ConfigId": "SimpleAdmin", //租户ID diff --git a/SimpleAdmin.SqlSugar/SqlSugar.Production.json b/SimpleAdmin.SqlSugar/SqlSugar.Production.json index 94418c9..85d62ac 100644 --- a/SimpleAdmin.SqlSugar/SqlSugar.Production.json +++ b/SimpleAdmin.SqlSugar/SqlSugar.Production.json @@ -5,7 +5,7 @@ "ConnectionStrings": [ { "ConfigId": "SimpleAdmin", //租户ID - "ConnectionString": "AllowLoadLocalInfile=true;Server=116.168.197.2;User ID=admin;Password=so^867z$4S;Port=16306;Database=WeiBingJu;CharSet=utf8mb4;pooling=true;SslMode=None;min pool size=1;Connection Timeout=30;Pooling=false", //连接字符串 + "ConnectionString": "AllowLoadLocalInfile=true;Server=116.168.197.2;User ID=admin;Password=so^867z$4S;Port=16306;Database=OnboardX;CharSet=utf8mb4;pooling=true;SslMode=None;min pool size=1;Connection Timeout=30;Pooling=false", //连接字符串 "DbType": "MySql", //数据库类型 "IsAutoCloseConnection": true //是否自动释放 } diff --git a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/MedicinalController.cs b/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/MedicinalController.cs deleted file mode 100644 index 6033c42..0000000 --- a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/MedicinalController.cs +++ /dev/null @@ -1,88 +0,0 @@ - -namespace SimpleAdmin.Web.Core; - -/// -/// 药材管理 -/// -[ApiDescriptionSettings("Application", Tag = "药材管理")] -[Route("biz/weibingju/medicinal")] -[RolePermission] -public class MedicinalController : IDynamicApiController -{ - private readonly IMedicinalService _medicinalService; - - public MedicinalController(IMedicinalService medicinalService) - { - _medicinalService = medicinalService; - } - - /// - /// 获取药材列表 - /// - [HttpGet("list")] - [DisplayName("获取药材列表")] - public async Task GetList([FromQuery] string medicinalName, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10) - { - return await _medicinalService.GetMedicinalList(medicinalName, pageNum, pageSize); - } - - /// - /// 获取药材消耗记录 - /// - [HttpGet("consumption-records")] - [DisplayName("获取药材消耗记录")] - public async Task GetConsumptionRecords([FromQuery] long id, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10) - { - return await _medicinalService.GetConsumptionRecords(id, pageNum, pageSize); - } - - /// - /// 获取药材下拉 - /// - [HttpGet("getmedicinaldictlist")] - [DisplayName("获取药材下拉")] - public async Task GetMedicinalDictList() - { - return await _medicinalService.GetMedicinalDictList(); - } - - /// - /// 获取药材添加记录 - /// - [HttpGet("addition-records")] - [DisplayName("获取药材添加记录")] - public async Task GetAdditionRecords(long id, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10) - { - return await _medicinalService.GetAdditionRecords(id, pageNum, pageSize); - } - - /// - /// 添加药材 - /// - [HttpPost("add")] - [DisplayName("添加药材")] - public async Task AddMedicinal([FromBody] AddMedicinalInput input) - { - return await _medicinalService.AddMedicinal(input); - } - - /// - /// 修改药材添加记录 - /// - [HttpPost("addition-records")] - [DisplayName("修改药材添加记录")] - public async Task UpdateAdditionRecord([FromBody] UpdateMedicinalAddLogInput input) - { - return await _medicinalService.UpdateAdditionRecord(input); - } - - /// - /// 删除药材添加记录 - /// - [HttpPost("addition-delete")] - [DisplayName("删除药材添加记录")] - public async Task DeleteAdditionRecord(DeleteMedicinalLog input) - { - return await _medicinalService.DeleteAdditionRecord(input.Id); - } -} diff --git a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/PrescriptionController.cs b/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/PrescriptionController.cs deleted file mode 100644 index 6b86a28..0000000 --- a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/PrescriptionController.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin -// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 -// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。 -// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。 - -namespace SimpleAdmin.Web.Core; - -/// -/// 药材管理 -/// -[ApiDescriptionSettings("Application", Tag = "处方管理")] -[Route("biz/weibingju/prescription")] -[RolePermission] -public class PrescriptionController : IDynamicApiController -{ - private readonly IPrescriptionService _service; - - public PrescriptionController(IPrescriptionService service) - { - _service = service; - } - - /// - /// 获取处方列表 - /// - [HttpGet("list")] - [DisplayName("获取处方列表")] - public async Task GetList([FromQuery] PrescriptionQueryInput input) - { - return await _service.GetPrescriptionList(input); - } - - /// - /// 获取处方总列表使用成本 - /// - [HttpGet("gettotalcost")] - [DisplayName("获取处方总列表使用成本")] - public async Task GetAllPrescriptionTotalCost() - { - return await _service.GetAllPrescriptionTotalCost(); - } - - /// - /// 获取处方详情 - /// - [HttpGet("getprescriptiondetile")] - [DisplayName("获取处方详情")] - public async Task GetDetail(long id) - { - return await _service.GetPrescriptionDetail(id); - } - - /// - /// 保存处方(新增或编辑) - /// - [HttpPost("add")] - [DisplayName("保存处方(新增或编辑)")] - public async Task SavePrescription([FromBody] SavePrescriptionInput input) - { - return await _service.SavePrescription(input); - } - - /// - /// 获取人员列表 - /// - [HttpGet("persons")] - [DisplayName("获取人员列表")] - public async Task GetPersonList([FromQuery] PersonType? type, [FromQuery] long? employeeId) - { - return await _service.GetPersonList(type, employeeId); - } - - /// - /// 获取关系类型 - /// - [HttpGet("relation-types")] - [DisplayName("获取关系类型")] - public async Task GetRelationTypes() - { - return await _service.GetRelationTypes(); - } -} diff --git a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/StatisticsController.cs b/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/StatisticsController.cs deleted file mode 100644 index 2bfd80f..0000000 --- a/SimpleAdmin.Web.Core/Controllers/Application/WeiBingJu/StatisticsController.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 -// -// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: -// 1.请不要删除和修改根目录下的LICENSE文件。 -// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 -// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin - -using MoYu.FriendlyException; -using SimpleAdmin.Application.Services.Statistics; - -namespace SimpleAdmin.Web.Core; - -/// -/// 统计分析 -/// -[ApiDescriptionSettings("Application", Tag = "统计分析")] -[Route("biz/weibingju/statistics")] -[RolePermission] -public class StatisticsController : IDynamicApiController -{ - private readonly IStatisticsService _service; - - public StatisticsController(IStatisticsService service) - { - _service = service; - } - - /// - /// 获取全量总览数据(不区分年份,含剩余药材库存价值) - /// - [HttpGet("overview")] - [DisplayName("获取全量总览数据")] - public async Task GetTotalOverview() - { - return await _service.GetTotalOverview(); - } - - /// - /// 获取年度统计数据(含同比趋势) - /// - [HttpGet("yearly")] - [DisplayName("获取年度统计数据")] - public async Task GetYearlyStatistics([FromQuery] string year) - { - if (!int.TryParse(year, out int yearInt) || yearInt < 2000 || yearInt > 2100) - throw Oops.Bah("年份参数不合法"); - - return await _service.GetYearlyStatistics(yearInt); - } - - /// - /// 获取月度明细数据(返回 12 个月,无数据月份自动补零) - /// - [HttpGet("monthly")] - [DisplayName("获取月度明细数据")] - public async Task GetMonthlyDetails([FromQuery] string year) - { - if (!int.TryParse(year, out int yearInt) || yearInt < 2000 || yearInt > 2100) - throw Oops.Bah("年份参数不合法"); - - return await _service.GetMonthlyDetails(yearInt); - } -} diff --git a/SimpleAdmin.Web.Core/GlobalUsing.cs b/SimpleAdmin.Web.Core/GlobalUsing.cs index 4ef2f44..aba71bf 100644 --- a/SimpleAdmin.Web.Core/GlobalUsing.cs +++ b/SimpleAdmin.Web.Core/GlobalUsing.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 +// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 // // SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: // 1.请不要删除和修改根目录下的LICENSE文件。 @@ -40,7 +40,3 @@ global using Microsoft.AspNetCore.Hosting; global using IP2Region.Net.Abstractions; global using IP2Region.Net.XDB; global using NewLife; -global using SimpleAdmin.Application.Services.Medicinal; -global using SimpleAdmin.Application.Services.Medicinal.Dto; -global using SimpleAdmin.Application.Services.Prescription; -global using SimpleAdmin.Application.Services.Prescription.Dto; diff --git a/SimpleAdmin.Web.Core/SimpleAdmin.Web.Core.xml b/SimpleAdmin.Web.Core/SimpleAdmin.Web.Core.xml index d5f8800..9804993 100644 --- a/SimpleAdmin.Web.Core/SimpleAdmin.Web.Core.xml +++ b/SimpleAdmin.Web.Core/SimpleAdmin.Web.Core.xml @@ -345,101 +345,6 @@ - - - 药材管理 - - - - - 获取药材列表 - - - - - 获取药材消耗记录 - - - - - 获取药材下拉 - - - - - 获取药材添加记录 - - - - - 添加药材 - - - - - 修改药材添加记录 - - - - - 删除药材添加记录 - - - - - 药材管理 - - - - - 获取处方列表 - - - - - 获取处方总列表使用成本 - - - - - 获取处方详情 - - - - - 保存处方(新增或编辑) - - - - - 获取人员列表 - - - - - 获取关系类型 - - - - - 统计分析 - - - - - 获取全量总览数据(不区分年份,含剩余药材库存价值) - - - - - 获取年度统计数据(含同比趋势) - - - - - 获取月度明细数据(返回 12 个月,无数据月份自动补零) - - B端登录控制器