删除以前的业务代码
This commit is contained in:
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 药材
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "药材")]
|
|
||||||
public string MedicinalName { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 数量(g)
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "数量(g)")]
|
|
||||||
public decimal Number { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 药材关联id
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "药材关联id")]
|
|
||||||
public long MedicinalId { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 添加重量(g)
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "添加重量(g)")]
|
|
||||||
public decimal AddWeight { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 药材单价
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "药材单价")]
|
|
||||||
public decimal UnitPrice { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 总价
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(ColumnDescription = "总价")]
|
|
||||||
public decimal TotalPrice { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 若非空,表示此 person 是某员工的家属
|
|
||||||
/// </summary>
|
|
||||||
[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; }
|
|
||||||
|
|
||||||
/// <summary>单位 cm,保留两位小数</summary>
|
|
||||||
[SugarColumn(ColumnDescription = "身高(cm)", IsNullable = true)]
|
|
||||||
public decimal? Height { get; set; }
|
|
||||||
|
|
||||||
[SugarColumn(ColumnDescription = "1领导,2普通员工,3其他", IsNullable = true)]
|
|
||||||
public int? Type { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>单位 kg,保留两位小数</summary>
|
|
||||||
[SugarColumn(ColumnDescription = "体重(kg)", IsNullable = true)]
|
|
||||||
public decimal? Weight { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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; }
|
|
||||||
|
|
||||||
/// <summary>消耗克数,单位 g</summary>
|
|
||||||
[SugarColumn(ColumnDescription = "消耗(g)")]
|
|
||||||
public decimal AmountG { get; set; }
|
|
||||||
|
|
||||||
[SugarColumn(Length = 500, IsNullable = true, ColumnDescription = "用量说明/备注")]
|
|
||||||
public string Note { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
|
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
|
||||||
//
|
//
|
||||||
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
|
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
|
||||||
// 1.请不要删除和修改根目录下的LICENSE文件。
|
// 1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
@@ -23,7 +23,3 @@ global using SimpleAdmin.SqlSugar;
|
|||||||
global using SimpleAdmin.System;
|
global using SimpleAdmin.System;
|
||||||
global using SqlSugar;
|
global using SqlSugar;
|
||||||
global using System.Reflection;
|
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;
|
|
||||||
|
|||||||
@@ -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; }
|
|
||||||
/// <summary>
|
|
||||||
/// 未找到下拉框的时候传这个值代表添加新的药材
|
|
||||||
/// </summary>
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材列表,带筛选
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">药材名称筛选</param>
|
|
||||||
/// <param name="page">页码</param>
|
|
||||||
/// <param name="size">页大小</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<SqlSugarPagedList<MedicinalDto>> GetMedicinalList(string medicinalName, int page, int size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材消耗记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="medicinalId">药材ID</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<SqlSugarPagedList<MedicinalConsumptionRecordDto>> GetConsumptionRecords(long medicinalId, int page, int size);
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材下拉
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<List<MedicinalDto>> GetMedicinalDictList();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="medicinalId">药材ID</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<SqlSugarPagedList<MedicinalAddLogDto>> GetAdditionRecords(long medicinalId, int page, int size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加药材
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">添加信息</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> AddMedicinal(AddMedicinalInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 修改药材添加记录(仅当天可修改)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">记录ID</param>
|
|
||||||
/// <param name="input">修改信息</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> UpdateAdditionRecord(UpdateMedicinalAddLogInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除药材添加记录(仅当天可删除)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">记录ID</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<bool> DeleteAdditionRecord(long id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Medicinal>, IMedicinalService
|
|
||||||
{
|
|
||||||
private readonly ISysUserService _sysUserService;
|
|
||||||
private readonly IDictService _dictService;
|
|
||||||
public MedicinalService(ISysUserService sysUserService, IDictService dictService)
|
|
||||||
{
|
|
||||||
_sysUserService = sysUserService;
|
|
||||||
_dictService = dictService;
|
|
||||||
}
|
|
||||||
public async Task<SqlSugarPagedList<MedicinalDto>> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材下拉
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<MedicinalDto>> 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();
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材消耗记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="medicinalId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <summary>
|
|
||||||
public async Task<SqlSugarPagedList<MedicinalConsumptionRecordDto>> GetConsumptionRecords(long medicinalId, int page, int size)
|
|
||||||
{
|
|
||||||
return await Context.Queryable<PrescriptionHerb>()
|
|
||||||
// 先关联处方
|
|
||||||
.LeftJoin<Prescription>((ph, p) => ph.PrescriptionId == p.Id)
|
|
||||||
// 再关联就诊人
|
|
||||||
.LeftJoin<Person>((ph, p, pe) => p.PersonId == pe.Id)
|
|
||||||
// 再关联员工
|
|
||||||
.LeftJoin<Person>((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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="medicinalId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<SqlSugarPagedList<MedicinalAddLogDto>> GetAdditionRecords(long medicinalId, int page, int size)
|
|
||||||
{
|
|
||||||
var returnList = await Context.Queryable<MedicinalAddLog>()
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 添加药材
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> AddMedicinal(AddMedicinalInput input)
|
|
||||||
{
|
|
||||||
if (input.TotalPrice <= 0 || input.AddWeight <= 0) throw Oops.Bah("请填写正确的金额!");
|
|
||||||
// 开启事务
|
|
||||||
await Context.Ado.BeginTranAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 检查药材是否已存在
|
|
||||||
var existing = await Context.Queryable<Medicinal>()
|
|
||||||
.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<Medicinal>()
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 修改药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public async Task<bool> UpdateAdditionRecord(UpdateMedicinalAddLogInput input)
|
|
||||||
{
|
|
||||||
if(input.TotalPrice<=0 || input.AddWeight<=0) throw Oops.Bah("请填写正确的金额!");
|
|
||||||
var log = await Context.Queryable<MedicinalAddLog>().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<Medicinal>()
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 删除药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public async Task<bool> DeleteAdditionRecord(long id)
|
|
||||||
{
|
|
||||||
var log = await Context.Queryable<MedicinalAddLog>().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<Medicinal>()
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 批量计算:使用成本、剩余价值、总使用量(先进先出法)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="medicinalIds">需要计算的药材ID列表</param>
|
|
||||||
private async Task<Dictionary<long, (
|
|
||||||
decimal usedCost,//预估花费
|
|
||||||
decimal remainingValue,//预估剩余价值
|
|
||||||
decimal totalUsedWeight//使用总量
|
|
||||||
)>> BatchCalculateCostAndValue(List<long> medicinalIds)
|
|
||||||
{
|
|
||||||
var result = new Dictionary<long, (decimal, decimal, decimal)>();
|
|
||||||
if (!medicinalIds.Any()) return result;
|
|
||||||
|
|
||||||
// 1. 批量查询所有药材的【当前库存】
|
|
||||||
var medicinals = await Context.Queryable<Medicinal>()
|
|
||||||
.Where(m => medicinalIds.Contains(m.Id))
|
|
||||||
.Select(m => new { m.Id, m.Number }) // Number = 当前库存
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// 2. 批量查询所有药材的【入库记录】
|
|
||||||
var allAddLogs = await Context.Queryable<MedicinalAddLog>()
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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; }
|
|
||||||
/// <summary>
|
|
||||||
/// 关联的员工名称
|
|
||||||
/// </summary>
|
|
||||||
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<PrescriptionHerbDto> 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<PrescriptionHerbInputDto> 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(如果是家属)
|
|
||||||
/// <summary>
|
|
||||||
/// 当前关联的员工是否是前端临时新增(需要后端创建)
|
|
||||||
/// </summary>
|
|
||||||
public bool EmployeeIsTemp { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 当 EmployeeIsTemp 为 true 或者前端直接传了员工名字时,后端可用此字段创建员工
|
|
||||||
/// </summary>
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方列表,带筛选
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">筛选条件</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<SqlSugarPagedList<PrescriptionDto>> GetPrescriptionList(PrescriptionQueryInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有处方的成本
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<decimal> GetAllPrescriptionTotalCost();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方详情
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">处方ID</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<PrescriptionDetailDto> GetPrescriptionDetail(long id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存处方(新增或编辑)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">处方信息</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<long> SavePrescription(SavePrescriptionInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取人员列表(员工和家属)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">人员类型</param>
|
|
||||||
/// <param name="employeeId">员工ID(用于获取家属)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<List<PersonDto>> GetPersonList(PersonType? type, long? employeeId);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有关系类型(写死在代码中)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<List<RelationTypeDto>> GetRelationTypes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Prescription>, IPrescriptionService
|
|
||||||
{
|
|
||||||
//public async Task<SqlSugarPagedList<PrescriptionDto>> GetPrescriptionList(PrescriptionQueryInput input)
|
|
||||||
//{
|
|
||||||
// var query = Context.Queryable<Prescription>()
|
|
||||||
// .LeftJoin<Person>((p, pe) => p.PersonId == pe.Id)
|
|
||||||
// .LeftJoin<Person>((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<PrescriptionHerb>()
|
|
||||||
// .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;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 获取药材FIFO计算所需的基础数据(入库记录)
|
|
||||||
///// </summary>
|
|
||||||
//private async Task<Dictionary<long, List<MedicinalFifoRecord>>> GetMedicinalFifoData(List<long> medicinalIds)
|
|
||||||
//{
|
|
||||||
// if (!medicinalIds.Any())
|
|
||||||
// return new Dictionary<long, List<MedicinalFifoRecord>>();
|
|
||||||
|
|
||||||
// // 批量查询所有涉及药材的入库记录(按时间排序)
|
|
||||||
// var addLogs = await Context.Queryable<MedicinalAddLog>()
|
|
||||||
// .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());
|
|
||||||
//}
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 按FIFO规则计算单种药材的使用成本
|
|
||||||
///// </summary>
|
|
||||||
//private decimal CalculateHerbCostByFifo(
|
|
||||||
// Dictionary<long, List<MedicinalFifoRecord>> 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<SqlSugarPagedList<PrescriptionDto>> GetPrescriptionList(PrescriptionQueryInput input)
|
|
||||||
{
|
|
||||||
var query = Context.Queryable<Prescription>()
|
|
||||||
.LeftJoin<Person>((p, pe) => p.PersonId == pe.Id)
|
|
||||||
.LeftJoin<Person>((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<Prescription>()
|
|
||||||
.OrderBy(p => p.CreateTime)
|
|
||||||
.Select(p => p.Id)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// 2) 拉取所有处方对应的药材明细
|
|
||||||
var allPrescriptionHerbList = await Context.Queryable<PrescriptionHerb>()
|
|
||||||
.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<long, decimal>();
|
|
||||||
|
|
||||||
// 7) 模拟按时间顺序消耗所有处方,并把每张处方的成本记录到字典
|
|
||||||
var prescriptionCostDict = new Dictionary<long, decimal>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有处方的总药材成本
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<decimal> GetAllPrescriptionTotalCost()
|
|
||||||
{
|
|
||||||
// 1) 获取所有处方的 ID(按创建时间升序),并明确类型为 long
|
|
||||||
var allPrescriptionIds = await Context.Queryable<Prescription>()
|
|
||||||
.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<PrescriptionHerb>()
|
|
||||||
.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<long, decimal>();
|
|
||||||
|
|
||||||
decimal totalSum = 0m;
|
|
||||||
|
|
||||||
// 6) 获取每张处方的人员类型(IsRelative: bool),并把 key 明确为 long,避免类型不匹配
|
|
||||||
var personTmp = await Context.Queryable<Prescription>()
|
|
||||||
.LeftJoin<Person>((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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材FIFO计算所需的基础数据(入库记录)
|
|
||||||
/// </summary>
|
|
||||||
private async Task<Dictionary<long, List<MedicinalFifoRecord>>> GetMedicinalFifoData(List<long> medicinalIds)
|
|
||||||
{
|
|
||||||
if (!medicinalIds.Any())
|
|
||||||
return new Dictionary<long, List<MedicinalFifoRecord>>();
|
|
||||||
|
|
||||||
// 批量查询所有涉及药材的入库记录(按时间排序)
|
|
||||||
var addLogs = await Context.Queryable<MedicinalAddLog>()
|
|
||||||
.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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 按FIFO规则计算单种药材的使用成本(累计消耗)
|
|
||||||
/// </summary>
|
|
||||||
private decimal CalculateHerbCostByFifoWithOffset(
|
|
||||||
Dictionary<long, List<MedicinalFifoRecord>> fifoData,
|
|
||||||
Dictionary<long, decimal> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方详情
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public async Task<PrescriptionDetailDto> GetPrescriptionDetail(long id)
|
|
||||||
{
|
|
||||||
var prescription = await Context.Queryable<Prescription>()
|
|
||||||
.Where(p => p.Id == id)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (prescription == null)
|
|
||||||
{
|
|
||||||
throw Oops.Bah("处方不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
var person = await Context.Queryable<Person>()
|
|
||||||
.Where(pe => pe.Id == prescription.PersonId)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
var herbs = await Context.Queryable<PrescriptionHerb, Medicinal>((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<Person>()
|
|
||||||
.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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 添加编辑处方记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<long> 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<Person>()
|
|
||||||
.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<Person>().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<Person>().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<Prescription>()
|
|
||||||
.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<PrescriptionHerb>()
|
|
||||||
.Where(ph => ph.PrescriptionId == input.Id.Value)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
if (oldHerbs.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var g in oldHerbs.GroupBy(x => x.MedicinalId))
|
|
||||||
{
|
|
||||||
// 恢复库存(加回已消耗)
|
|
||||||
await Context.Updateable<Medicinal>()
|
|
||||||
.SetColumns(m => new Medicinal { Number = m.Number + g.Sum(x => x.AmountG) })
|
|
||||||
.Where(m => m.Id == g.Key)
|
|
||||||
.ExecuteCommandAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除原有处方药材
|
|
||||||
await Context.Deleteable<PrescriptionHerb>()
|
|
||||||
.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<Medicinal>()
|
|
||||||
.Where(m => herbIds.Contains(m.Id))
|
|
||||||
.ToListAsync();
|
|
||||||
List<long> HerbsId = new List<long>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取 人员下拉
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="employeeId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<PersonDto>> GetPersonList(PersonType? type, long? employeeId)
|
|
||||||
{
|
|
||||||
var query = Context.Queryable<Person>();
|
|
||||||
|
|
||||||
// 筛选员工或家属
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取关系下拉
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<RelationTypeDto>> GetRelationTypes()
|
|
||||||
{
|
|
||||||
var sysmodel = await Context.Queryable<SysDict>().FirstAsync(a => a.DictValue == "Relation");
|
|
||||||
if (sysmodel != null)
|
|
||||||
{
|
|
||||||
return await Context.Queryable<SysDict>().Where(a => a.ParentId == sysmodel.Id).Select(pe => new RelationTypeDto
|
|
||||||
{
|
|
||||||
Id = int.Parse(pe.DictValue),
|
|
||||||
Name = pe.DictLabel,
|
|
||||||
}).ToListAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new List<RelationTypeDto>
|
|
||||||
{
|
|
||||||
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 = "其他" }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 年度统计数据 DTO(对应前端 YearlyStatisticsDto)
|
|
||||||
/// </summary>
|
|
||||||
public class YearlyStatisticsDto
|
|
||||||
{
|
|
||||||
/// <summary>统计年份(如 "2025")</summary>
|
|
||||||
public string Year { get; set; }
|
|
||||||
|
|
||||||
/// <summary>处方总花费(元)</summary>
|
|
||||||
public decimal TotalCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>处方总数量(张)</summary>
|
|
||||||
public int TotalQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方花费(元)</summary>
|
|
||||||
public decimal StaffCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方花费(元)</summary>
|
|
||||||
public decimal FamilyCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方数量(张)</summary>
|
|
||||||
public int StaffQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方数量(张)</summary>
|
|
||||||
public int FamilyQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>药材耗材花费(元)—— 当年所有入库药材总价</summary>
|
|
||||||
public decimal MaterialCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>服务人数(当年有过处方记录的不重复人员数)</summary>
|
|
||||||
public int ServiceCount { get; set; }
|
|
||||||
|
|
||||||
// ---------- 同比趋势(百分比,正数为增长,负数为下降) ----------
|
|
||||||
|
|
||||||
/// <summary>处方总花费同比趋势 (%)</summary>
|
|
||||||
public decimal TotalCostTrend { get; set; }
|
|
||||||
|
|
||||||
/// <summary>处方总数量同比趋势 (%)</summary>
|
|
||||||
public decimal TotalQtyTrend { get; set; }
|
|
||||||
|
|
||||||
/// <summary>药材花费同比趋势 (%)</summary>
|
|
||||||
public decimal MaterialCostTrend { get; set; }
|
|
||||||
|
|
||||||
/// <summary>服务人数同比趋势 (%)</summary>
|
|
||||||
public decimal ServiceCountTrend { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 月度明细数据 DTO(对应前端 MonthlyDetailDto)
|
|
||||||
/// </summary>
|
|
||||||
public class MonthlyDetailDto
|
|
||||||
{
|
|
||||||
/// <summary>月份显示(如 "1月")</summary>
|
|
||||||
public string Month { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方花费(元)</summary>
|
|
||||||
public decimal StaffCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方花费(元)</summary>
|
|
||||||
public decimal FamilyCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方数量(张)</summary>
|
|
||||||
public int StaffQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方数量(张)</summary>
|
|
||||||
public int FamilyQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>药材耗材花费(元)—— 当月入库总价</summary>
|
|
||||||
public decimal MaterialCost { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 全量总览 DTO(不区分年份,含剩余药材价值)
|
|
||||||
/// </summary>
|
|
||||||
public class TotalOverviewDto
|
|
||||||
{
|
|
||||||
/// <summary>处方总花费(元,含所有年份)</summary>
|
|
||||||
public decimal TotalCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>处方总数量(张)</summary>
|
|
||||||
public int TotalQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方花费(元)</summary>
|
|
||||||
public decimal StaffCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方花费(元)</summary>
|
|
||||||
public decimal FamilyCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>员工处方数量(张)</summary>
|
|
||||||
public int StaffQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>家属处方数量(张)</summary>
|
|
||||||
public int FamilyQty { get; set; }
|
|
||||||
|
|
||||||
/// <summary>药材采购总花费(元,历史所有入库总额)</summary>
|
|
||||||
public decimal MaterialCost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>累计服务人数(不重复人员)</summary>
|
|
||||||
public int ServiceCount { get; set; }
|
|
||||||
|
|
||||||
/// <summary>当前剩余药材库存价值(元,按最新入库单价估算)</summary>
|
|
||||||
public decimal RemainingMedicinalValue { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 统计分析 Service 接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IStatisticsService : ITransient
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取全量总览数据(不区分年份,含剩余药材库存价值)
|
|
||||||
/// </summary>
|
|
||||||
Task<TotalOverviewDto> GetTotalOverview();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定年份的年度汇总统计数据(含同比趋势)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="year">年份,如 2025</param>
|
|
||||||
Task<YearlyStatisticsDto> GetYearlyStatistics(int year);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定年份的逐月明细数据(返回 12 条,无数据月份补零)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="year">年份,如 2025</param>
|
|
||||||
Task<List<MonthlyDetailDto>> GetMonthlyDetails(int year);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 统计分析 Service 实现
|
|
||||||
/// </summary>
|
|
||||||
public class StatisticsService : DbRepository<Prescription>, IStatisticsService
|
|
||||||
{
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
|
||||||
// 公开接口
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async Task<TotalOverviewDto> GetTotalOverview()
|
|
||||||
{
|
|
||||||
// 1) 所有处方(按创建时间升序,FIFO 需要)
|
|
||||||
var prescriptionInfos = await Context.Queryable<Prescription>()
|
|
||||||
.LeftJoin<Person>((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<PrescriptionHerb>()
|
|
||||||
.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<long, decimal>();
|
|
||||||
|
|
||||||
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<MedicinalAddLog>()
|
|
||||||
.SumAsync(l => l.TotalPrice);
|
|
||||||
|
|
||||||
// 3) 累计服务人数(不重复人员)
|
|
||||||
var serviceCount = prescriptionInfos.Select(x => x.PersonId).Distinct().Count();
|
|
||||||
|
|
||||||
// 4) 剩余药材库存价值:每种药材当前库存 × 最新入库单价
|
|
||||||
var medicinals = await Context.Queryable<Medicinal>()
|
|
||||||
.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<MedicinalAddLog>()
|
|
||||||
.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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async Task<YearlyStatisticsDto> 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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async Task<List<MonthlyDetailDto>> 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<Prescription>()
|
|
||||||
.LeftJoin<Person>((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<PrescriptionHerb>()
|
|
||||||
.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<Prescription>()
|
|
||||||
.Where(p => p.VisitDate < start)
|
|
||||||
.OrderBy(p => p.CreateTime)
|
|
||||||
.Select(p => p.Id)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var fifoOffsets = new Dictionary<long, decimal>();
|
|
||||||
|
|
||||||
// 先消耗历史处方(建立偏移量),不需要计入结果
|
|
||||||
if (historyIds.Any())
|
|
||||||
{
|
|
||||||
var historyHerbs = await Context.Queryable<PrescriptionHerb>()
|
|
||||||
.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<MedicinalAddLog>()
|
|
||||||
.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<MonthlyDetailDto>(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
|
||||||
// 私有辅助方法
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 计算指定年份的聚合数据(用于年度统计与同比计算)
|
|
||||||
/// </summary>
|
|
||||||
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<Prescription>()
|
|
||||||
.LeftJoin<Person>((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<PrescriptionHerb>()
|
|
||||||
.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<Prescription>()
|
|
||||||
.Where(p => p.VisitDate < start)
|
|
||||||
.OrderBy(p => p.CreateTime)
|
|
||||||
.Select(p => p.Id)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var fifoOffsets = new Dictionary<long, decimal>();
|
|
||||||
if (historyIds.Any())
|
|
||||||
{
|
|
||||||
var historyHerbs = await Context.Queryable<PrescriptionHerb>()
|
|
||||||
.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<MedicinalAddLog>()
|
|
||||||
.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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 读取 FIFO 入库数据(按时间升序)
|
|
||||||
/// </summary>
|
|
||||||
private async Task<Dictionary<long, List<MedicinalFifoRecord>>> GetFifoData(List<long> medicinalIds)
|
|
||||||
{
|
|
||||||
if (!medicinalIds.Any())
|
|
||||||
return new Dictionary<long, List<MedicinalFifoRecord>>();
|
|
||||||
|
|
||||||
var logs = await Context.Queryable<MedicinalAddLog>()
|
|
||||||
.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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 按 FIFO 规则(含累计偏移)计算单次消耗成本,并推进偏移量
|
|
||||||
/// </summary>
|
|
||||||
private static decimal CalculateFifoCost(
|
|
||||||
Dictionary<long, List<MedicinalFifoRecord>> fifoData,
|
|
||||||
Dictionary<long, decimal> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>计算同比增涨率(%),基期为 0 时返回 0</summary>
|
|
||||||
private static decimal CalcTrend<T>(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>返回全零的 12 个月明细列表</summary>
|
|
||||||
private static List<MonthlyDetailDto> BuildEmptyMonthList()
|
|
||||||
{
|
|
||||||
var list = new List<MonthlyDetailDto>(12);
|
|
||||||
for (int m = 1; m <= 12; m++)
|
|
||||||
list.Add(new MonthlyDetailDto { Month = $"{m}月" });
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,288 +54,11 @@
|
|||||||
排序码
|
排序码
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:SimpleAdmin.Application.Entity.Medicinal.MedicinalName">
|
|
||||||
<summary>
|
|
||||||
药材
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.Medicinal.Number">
|
|
||||||
<summary>
|
|
||||||
数量(g)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.MedicinalAddLog.MedicinalId">
|
|
||||||
<summary>
|
|
||||||
药材关联id
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.MedicinalAddLog.AddWeight">
|
|
||||||
<summary>
|
|
||||||
添加重量(g)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.MedicinalAddLog.UnitPrice">
|
|
||||||
<summary>
|
|
||||||
药材单价
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.MedicinalAddLog.TotalPrice">
|
|
||||||
<summary>
|
|
||||||
总价
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.Person.EmployeeId">
|
|
||||||
<summary>
|
|
||||||
若非空,表示此 person 是某员工的家属
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.Person.Height">
|
|
||||||
<summary>单位 cm,保留两位小数</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.Prescription.Weight">
|
|
||||||
<summary>单位 kg,保留两位小数</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Entity.PrescriptionHerb.AmountG">
|
|
||||||
<summary>消耗克数,单位 g</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.ApplicationSettingsOptions">
|
<member name="T:SimpleAdmin.Application.ApplicationSettingsOptions">
|
||||||
<summary>
|
<summary>
|
||||||
系统配置
|
系统配置
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:SimpleAdmin.Application.Services.Medicinal.Dto.AddMedicinalInput.MedicinalName">
|
|
||||||
<summary>
|
|
||||||
未找到下拉框的时候传这个值代表添加新的药材
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.GetMedicinalList(System.String,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材列表,带筛选
|
|
||||||
</summary>
|
|
||||||
<param name="name">药材名称筛选</param>
|
|
||||||
<param name="page">页码</param>
|
|
||||||
<param name="size">页大小</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.GetConsumptionRecords(System.Int64,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材消耗记录
|
|
||||||
</summary>
|
|
||||||
<param name="medicinalId">药材ID</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.GetMedicinalDictList">
|
|
||||||
<summary>
|
|
||||||
获取药材下拉
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.GetAdditionRecords(System.Int64,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材添加记录
|
|
||||||
</summary>
|
|
||||||
<param name="medicinalId">药材ID</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.AddMedicinal(SimpleAdmin.Application.Services.Medicinal.Dto.AddMedicinalInput)">
|
|
||||||
<summary>
|
|
||||||
添加药材
|
|
||||||
</summary>
|
|
||||||
<param name="input">添加信息</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.UpdateAdditionRecord(SimpleAdmin.Application.Services.Medicinal.Dto.UpdateMedicinalAddLogInput)">
|
|
||||||
<summary>
|
|
||||||
修改药材添加记录(仅当天可修改)
|
|
||||||
</summary>
|
|
||||||
<param name="id">记录ID</param>
|
|
||||||
<param name="input">修改信息</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Medicinal.IMedicinalService.DeleteAdditionRecord(System.Int64)">
|
|
||||||
<summary>
|
|
||||||
删除药材添加记录(仅当天可删除)
|
|
||||||
</summary>
|
|
||||||
<param name="id">记录ID</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Prescription.Dto.PrescriptionDto.EmployeeName">
|
|
||||||
<summary>
|
|
||||||
关联的员工名称
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Prescription.Dto.PersonInputDto.EmployeeIsTemp">
|
|
||||||
<summary>
|
|
||||||
当前关联的员工是否是前端临时新增(需要后端创建)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Prescription.Dto.PersonInputDto.EmployeeName">
|
|
||||||
<summary>
|
|
||||||
当 EmployeeIsTemp 为 true 或者前端直接传了员工名字时,后端可用此字段创建员工
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.GetPrescriptionList(SimpleAdmin.Application.Services.Prescription.Dto.PrescriptionQueryInput)">
|
|
||||||
<summary>
|
|
||||||
获取处方列表,带筛选
|
|
||||||
</summary>
|
|
||||||
<param name="input">筛选条件</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.GetAllPrescriptionTotalCost">
|
|
||||||
<summary>
|
|
||||||
获取所有处方的成本
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.GetPrescriptionDetail(System.Int64)">
|
|
||||||
<summary>
|
|
||||||
获取处方详情
|
|
||||||
</summary>
|
|
||||||
<param name="id">处方ID</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.SavePrescription(SimpleAdmin.Application.Services.Prescription.Dto.SavePrescriptionInput)">
|
|
||||||
<summary>
|
|
||||||
保存处方(新增或编辑)
|
|
||||||
</summary>
|
|
||||||
<param name="input">处方信息</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.GetPersonList(System.Nullable{SimpleAdmin.Application.Services.Prescription.Dto.PersonType},System.Nullable{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
获取人员列表(员工和家属)
|
|
||||||
</summary>
|
|
||||||
<param name="type">人员类型</param>
|
|
||||||
<param name="employeeId">员工ID(用于获取家属)</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Prescription.IPrescriptionService.GetRelationTypes">
|
|
||||||
<summary>
|
|
||||||
获取所有关系类型(写死在代码中)
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto">
|
|
||||||
<summary>
|
|
||||||
年度统计数据 DTO(对应前端 YearlyStatisticsDto)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.Year">
|
|
||||||
<summary>统计年份(如 "2025")</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.TotalCost">
|
|
||||||
<summary>处方总花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.TotalQty">
|
|
||||||
<summary>处方总数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.StaffCost">
|
|
||||||
<summary>员工处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.FamilyCost">
|
|
||||||
<summary>家属处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.StaffQty">
|
|
||||||
<summary>员工处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.FamilyQty">
|
|
||||||
<summary>家属处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.MaterialCost">
|
|
||||||
<summary>药材耗材花费(元)—— 当年所有入库药材总价</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.ServiceCount">
|
|
||||||
<summary>服务人数(当年有过处方记录的不重复人员数)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.TotalCostTrend">
|
|
||||||
<summary>处方总花费同比趋势 (%)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.TotalQtyTrend">
|
|
||||||
<summary>处方总数量同比趋势 (%)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.MaterialCostTrend">
|
|
||||||
<summary>药材花费同比趋势 (%)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.YearlyStatisticsDto.ServiceCountTrend">
|
|
||||||
<summary>服务人数同比趋势 (%)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto">
|
|
||||||
<summary>
|
|
||||||
月度明细数据 DTO(对应前端 MonthlyDetailDto)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.Month">
|
|
||||||
<summary>月份显示(如 "1月")</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.StaffCost">
|
|
||||||
<summary>员工处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.FamilyCost">
|
|
||||||
<summary>家属处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.StaffQty">
|
|
||||||
<summary>员工处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.FamilyQty">
|
|
||||||
<summary>家属处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.MonthlyDetailDto.MaterialCost">
|
|
||||||
<summary>药材耗材花费(元)—— 当月入库总价</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto">
|
|
||||||
<summary>
|
|
||||||
全量总览 DTO(不区分年份,含剩余药材价值)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.TotalCost">
|
|
||||||
<summary>处方总花费(元,含所有年份)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.TotalQty">
|
|
||||||
<summary>处方总数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.StaffCost">
|
|
||||||
<summary>员工处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.FamilyCost">
|
|
||||||
<summary>家属处方花费(元)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.StaffQty">
|
|
||||||
<summary>员工处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.FamilyQty">
|
|
||||||
<summary>家属处方数量(张)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.MaterialCost">
|
|
||||||
<summary>药材采购总花费(元,历史所有入库总额)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.ServiceCount">
|
|
||||||
<summary>累计服务人数(不重复人员)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:SimpleAdmin.Application.Services.Statistics.TotalOverviewDto.RemainingMedicinalValue">
|
|
||||||
<summary>当前剩余药材库存价值(元,按最新入库单价估算)</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.Services.Statistics.IStatisticsService">
|
|
||||||
<summary>
|
|
||||||
统计分析 Service 接口
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Statistics.IStatisticsService.GetTotalOverview">
|
|
||||||
<summary>
|
|
||||||
获取全量总览数据(不区分年份,含剩余药材库存价值)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Statistics.IStatisticsService.GetYearlyStatistics(System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取指定年份的年度汇总统计数据(含同比趋势)
|
|
||||||
</summary>
|
|
||||||
<param name="year">年份,如 2025</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Application.Services.Statistics.IStatisticsService.GetMonthlyDetails(System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取指定年份的逐月明细数据(返回 12 条,无数据月份补零)
|
|
||||||
</summary>
|
|
||||||
<param name="year">年份,如 2025</param>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Application.IOrgService">
|
<member name="T:SimpleAdmin.Application.IOrgService">
|
||||||
<summary>
|
<summary>
|
||||||
机构服务
|
机构服务
|
||||||
@@ -878,128 +601,5 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="services"></param>
|
<param name="services"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:MedicinalService.GetMedicinalDictList">
|
|
||||||
<summary>
|
|
||||||
获取药材下拉
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<!-- Badly formed XML comment ignored for member "M:MedicinalService.GetConsumptionRecords(System.Int64,System.Int32,System.Int32)" -->
|
|
||||||
<member name="M:MedicinalService.GetAdditionRecords(System.Int64,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材添加记录
|
|
||||||
</summary>
|
|
||||||
<param name="medicinalId"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:MedicinalService.AddMedicinal(SimpleAdmin.Application.Services.Medicinal.Dto.AddMedicinalInput)">
|
|
||||||
<summary>
|
|
||||||
添加药材
|
|
||||||
</summary>
|
|
||||||
<param name="input"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:MedicinalService.UpdateAdditionRecord(SimpleAdmin.Application.Services.Medicinal.Dto.UpdateMedicinalAddLogInput)">
|
|
||||||
<summary>
|
|
||||||
修改药材添加记录
|
|
||||||
</summary>
|
|
||||||
<param name="input"></param>
|
|
||||||
<returns></returns>
|
|
||||||
<exception cref="T:System.Exception"></exception>
|
|
||||||
</member>
|
|
||||||
<member name="M:MedicinalService.DeleteAdditionRecord(System.Int64)">
|
|
||||||
<summary>
|
|
||||||
删除药材添加记录
|
|
||||||
</summary>
|
|
||||||
<param name="id"></param>
|
|
||||||
<returns></returns>
|
|
||||||
<exception cref="T:System.Exception"></exception>
|
|
||||||
</member>
|
|
||||||
<member name="M:MedicinalService.BatchCalculateCostAndValue(System.Collections.Generic.List{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
批量计算:使用成本、剩余价值、总使用量(先进先出法)
|
|
||||||
</summary>
|
|
||||||
<param name="medicinalIds">需要计算的药材ID列表</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.GetAllPrescriptionTotalCost">
|
|
||||||
<summary>
|
|
||||||
获取所有处方的总药材成本
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.GetMedicinalFifoData(System.Collections.Generic.List{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
获取药材FIFO计算所需的基础数据(入库记录)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.CalculateHerbCostByFifoWithOffset(System.Collections.Generic.Dictionary{System.Int64,System.Collections.Generic.List{SimpleAdmin.Application.Services.Prescription.Dto.MedicinalFifoRecord}},System.Collections.Generic.Dictionary{System.Int64,System.Decimal},System.Int64,System.Decimal)">
|
|
||||||
<summary>
|
|
||||||
按FIFO规则计算单种药材的使用成本(累计消耗)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.GetPrescriptionDetail(System.Int64)">
|
|
||||||
<summary>
|
|
||||||
获取处方详情
|
|
||||||
</summary>
|
|
||||||
<param name="id"></param>
|
|
||||||
<returns></returns>
|
|
||||||
<exception cref="T:System.Exception"></exception>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.SavePrescription(SimpleAdmin.Application.Services.Prescription.Dto.SavePrescriptionInput)">
|
|
||||||
<summary>
|
|
||||||
添加编辑处方记录
|
|
||||||
</summary>
|
|
||||||
<param name="input"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.GetPersonList(System.Nullable{SimpleAdmin.Application.Services.Prescription.Dto.PersonType},System.Nullable{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
获取 人员下拉
|
|
||||||
</summary>
|
|
||||||
<param name="type"></param>
|
|
||||||
<param name="employeeId"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:PrescriptionService.GetRelationTypes">
|
|
||||||
<summary>
|
|
||||||
获取关系下拉
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="T:StatisticsService">
|
|
||||||
<summary>
|
|
||||||
统计分析 Service 实现
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.GetTotalOverview">
|
|
||||||
<inheritdoc/>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.GetYearlyStatistics(System.Int32)">
|
|
||||||
<inheritdoc/>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.GetMonthlyDetails(System.Int32)">
|
|
||||||
<inheritdoc/>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.BuildYearData(System.Int32)">
|
|
||||||
<summary>
|
|
||||||
计算指定年份的聚合数据(用于年度统计与同比计算)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.GetFifoData(System.Collections.Generic.List{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
读取 FIFO 入库数据(按时间升序)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.CalculateFifoCost(System.Collections.Generic.Dictionary{System.Int64,System.Collections.Generic.List{SimpleAdmin.Application.Services.Prescription.Dto.MedicinalFifoRecord}},System.Collections.Generic.Dictionary{System.Int64,System.Decimal},System.Int64,System.Decimal)">
|
|
||||||
<summary>
|
|
||||||
按 FIFO 规则(含累计偏移)计算单次消耗成本,并推进偏移量
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.CalcTrend``1(``0,``0)">
|
|
||||||
<summary>计算同比增涨率(%),基期为 0 时返回 0</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:StatisticsService.BuildEmptyMonthList">
|
|
||||||
<summary>返回全零的 12 个月明细列表</summary>
|
|
||||||
</member>
|
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
"ConnectionStrings": [
|
"ConnectionStrings": [
|
||||||
{
|
{
|
||||||
"ConfigId": "SimpleAdmin", //租户ID
|
"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", //数据库类型 WeiBingJu
|
"DbType": "MySql", //数据库类型
|
||||||
"IsAutoCloseConnection": true //是否自动释放 weibingjutest
|
"IsAutoCloseConnection": true //是否自动释放
|
||||||
}
|
}
|
||||||
// {
|
// {
|
||||||
// "ConfigId": "SimpleAdmin", //租户ID
|
// "ConfigId": "SimpleAdmin", //租户ID
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"ConnectionStrings": [
|
"ConnectionStrings": [
|
||||||
{
|
{
|
||||||
"ConfigId": "SimpleAdmin", //租户ID
|
"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", //数据库类型
|
"DbType": "MySql", //数据库类型
|
||||||
"IsAutoCloseConnection": true //是否自动释放
|
"IsAutoCloseConnection": true //是否自动释放
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
|
|
||||||
namespace SimpleAdmin.Web.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 药材管理
|
|
||||||
/// </summary>
|
|
||||||
[ApiDescriptionSettings("Application", Tag = "药材管理")]
|
|
||||||
[Route("biz/weibingju/medicinal")]
|
|
||||||
[RolePermission]
|
|
||||||
public class MedicinalController : IDynamicApiController
|
|
||||||
{
|
|
||||||
private readonly IMedicinalService _medicinalService;
|
|
||||||
|
|
||||||
public MedicinalController(IMedicinalService medicinalService)
|
|
||||||
{
|
|
||||||
_medicinalService = medicinalService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材列表
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("list")]
|
|
||||||
[DisplayName("获取药材列表")]
|
|
||||||
public async Task<dynamic> GetList([FromQuery] string medicinalName, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10)
|
|
||||||
{
|
|
||||||
return await _medicinalService.GetMedicinalList(medicinalName, pageNum, pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材消耗记录
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("consumption-records")]
|
|
||||||
[DisplayName("获取药材消耗记录")]
|
|
||||||
public async Task<dynamic> GetConsumptionRecords([FromQuery] long id, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10)
|
|
||||||
{
|
|
||||||
return await _medicinalService.GetConsumptionRecords(id, pageNum, pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材下拉
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("getmedicinaldictlist")]
|
|
||||||
[DisplayName("获取药材下拉")]
|
|
||||||
public async Task<dynamic> GetMedicinalDictList()
|
|
||||||
{
|
|
||||||
return await _medicinalService.GetMedicinalDictList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("addition-records")]
|
|
||||||
[DisplayName("获取药材添加记录")]
|
|
||||||
public async Task<dynamic> GetAdditionRecords(long id, [FromQuery] int pageNum = 1, [FromQuery] int pageSize = 10)
|
|
||||||
{
|
|
||||||
return await _medicinalService.GetAdditionRecords(id, pageNum, pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加药材
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("add")]
|
|
||||||
[DisplayName("添加药材")]
|
|
||||||
public async Task<dynamic> AddMedicinal([FromBody] AddMedicinalInput input)
|
|
||||||
{
|
|
||||||
return await _medicinalService.AddMedicinal(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 修改药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("addition-records")]
|
|
||||||
[DisplayName("修改药材添加记录")]
|
|
||||||
public async Task<dynamic> UpdateAdditionRecord([FromBody] UpdateMedicinalAddLogInput input)
|
|
||||||
{
|
|
||||||
return await _medicinalService.UpdateAdditionRecord(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除药材添加记录
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("addition-delete")]
|
|
||||||
[DisplayName("删除药材添加记录")]
|
|
||||||
public async Task<dynamic> DeleteAdditionRecord(DeleteMedicinalLog input)
|
|
||||||
{
|
|
||||||
return await _medicinalService.DeleteAdditionRecord(input.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 药材管理
|
|
||||||
/// </summary>
|
|
||||||
[ApiDescriptionSettings("Application", Tag = "处方管理")]
|
|
||||||
[Route("biz/weibingju/prescription")]
|
|
||||||
[RolePermission]
|
|
||||||
public class PrescriptionController : IDynamicApiController
|
|
||||||
{
|
|
||||||
private readonly IPrescriptionService _service;
|
|
||||||
|
|
||||||
public PrescriptionController(IPrescriptionService service)
|
|
||||||
{
|
|
||||||
_service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方列表
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("list")]
|
|
||||||
[DisplayName("获取处方列表")]
|
|
||||||
public async Task<dynamic> GetList([FromQuery] PrescriptionQueryInput input)
|
|
||||||
{
|
|
||||||
return await _service.GetPrescriptionList(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方总列表使用成本
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("gettotalcost")]
|
|
||||||
[DisplayName("获取处方总列表使用成本")]
|
|
||||||
public async Task<dynamic> GetAllPrescriptionTotalCost()
|
|
||||||
{
|
|
||||||
return await _service.GetAllPrescriptionTotalCost();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取处方详情
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("getprescriptiondetile")]
|
|
||||||
[DisplayName("获取处方详情")]
|
|
||||||
public async Task<dynamic> GetDetail(long id)
|
|
||||||
{
|
|
||||||
return await _service.GetPrescriptionDetail(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存处方(新增或编辑)
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("add")]
|
|
||||||
[DisplayName("保存处方(新增或编辑)")]
|
|
||||||
public async Task<dynamic> SavePrescription([FromBody] SavePrescriptionInput input)
|
|
||||||
{
|
|
||||||
return await _service.SavePrescription(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取人员列表
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("persons")]
|
|
||||||
[DisplayName("获取人员列表")]
|
|
||||||
public async Task<dynamic> GetPersonList([FromQuery] PersonType? type, [FromQuery] long? employeeId)
|
|
||||||
{
|
|
||||||
return await _service.GetPersonList(type, employeeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取关系类型
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("relation-types")]
|
|
||||||
[DisplayName("获取关系类型")]
|
|
||||||
public async Task<dynamic> GetRelationTypes()
|
|
||||||
{
|
|
||||||
return await _service.GetRelationTypes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 统计分析
|
|
||||||
/// </summary>
|
|
||||||
[ApiDescriptionSettings("Application", Tag = "统计分析")]
|
|
||||||
[Route("biz/weibingju/statistics")]
|
|
||||||
[RolePermission]
|
|
||||||
public class StatisticsController : IDynamicApiController
|
|
||||||
{
|
|
||||||
private readonly IStatisticsService _service;
|
|
||||||
|
|
||||||
public StatisticsController(IStatisticsService service)
|
|
||||||
{
|
|
||||||
_service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取全量总览数据(不区分年份,含剩余药材库存价值)
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("overview")]
|
|
||||||
[DisplayName("获取全量总览数据")]
|
|
||||||
public async Task<dynamic> GetTotalOverview()
|
|
||||||
{
|
|
||||||
return await _service.GetTotalOverview();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取年度统计数据(含同比趋势)
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("yearly")]
|
|
||||||
[DisplayName("获取年度统计数据")]
|
|
||||||
public async Task<dynamic> GetYearlyStatistics([FromQuery] string year)
|
|
||||||
{
|
|
||||||
if (!int.TryParse(year, out int yearInt) || yearInt < 2000 || yearInt > 2100)
|
|
||||||
throw Oops.Bah("年份参数不合法");
|
|
||||||
|
|
||||||
return await _service.GetYearlyStatistics(yearInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取月度明细数据(返回 12 个月,无数据月份自动补零)
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("monthly")]
|
|
||||||
[DisplayName("获取月度明细数据")]
|
|
||||||
public async Task<dynamic> GetMonthlyDetails([FromQuery] string year)
|
|
||||||
{
|
|
||||||
if (!int.TryParse(year, out int yearInt) || yearInt < 2000 || yearInt > 2100)
|
|
||||||
throw Oops.Bah("年份参数不合法");
|
|
||||||
|
|
||||||
return await _service.GetMonthlyDetails(yearInt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
|
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
|
||||||
//
|
//
|
||||||
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
|
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
|
||||||
// 1.请不要删除和修改根目录下的LICENSE文件。
|
// 1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
@@ -40,7 +40,3 @@ global using Microsoft.AspNetCore.Hosting;
|
|||||||
global using IP2Region.Net.Abstractions;
|
global using IP2Region.Net.Abstractions;
|
||||||
global using IP2Region.Net.XDB;
|
global using IP2Region.Net.XDB;
|
||||||
global using NewLife;
|
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;
|
|
||||||
|
|||||||
@@ -345,101 +345,6 @@
|
|||||||
<param name="input"></param>
|
<param name="input"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:SimpleAdmin.Web.Core.MedicinalController">
|
|
||||||
<summary>
|
|
||||||
药材管理
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.GetList(System.String,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材列表
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.GetConsumptionRecords(System.Int64,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材消耗记录
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.GetMedicinalDictList">
|
|
||||||
<summary>
|
|
||||||
获取药材下拉
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.GetAdditionRecords(System.Int64,System.Int32,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
获取药材添加记录
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.AddMedicinal(SimpleAdmin.Application.Services.Medicinal.Dto.AddMedicinalInput)">
|
|
||||||
<summary>
|
|
||||||
添加药材
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.UpdateAdditionRecord(SimpleAdmin.Application.Services.Medicinal.Dto.UpdateMedicinalAddLogInput)">
|
|
||||||
<summary>
|
|
||||||
修改药材添加记录
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.MedicinalController.DeleteAdditionRecord(SimpleAdmin.Application.Services.Medicinal.Dto.DeleteMedicinalLog)">
|
|
||||||
<summary>
|
|
||||||
删除药材添加记录
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Web.Core.PrescriptionController">
|
|
||||||
<summary>
|
|
||||||
药材管理
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.GetList(SimpleAdmin.Application.Services.Prescription.Dto.PrescriptionQueryInput)">
|
|
||||||
<summary>
|
|
||||||
获取处方列表
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.GetAllPrescriptionTotalCost">
|
|
||||||
<summary>
|
|
||||||
获取处方总列表使用成本
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.GetDetail(System.Int64)">
|
|
||||||
<summary>
|
|
||||||
获取处方详情
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.SavePrescription(SimpleAdmin.Application.Services.Prescription.Dto.SavePrescriptionInput)">
|
|
||||||
<summary>
|
|
||||||
保存处方(新增或编辑)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.GetPersonList(System.Nullable{SimpleAdmin.Application.Services.Prescription.Dto.PersonType},System.Nullable{System.Int64})">
|
|
||||||
<summary>
|
|
||||||
获取人员列表
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.PrescriptionController.GetRelationTypes">
|
|
||||||
<summary>
|
|
||||||
获取关系类型
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Web.Core.StatisticsController">
|
|
||||||
<summary>
|
|
||||||
统计分析
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.StatisticsController.GetTotalOverview">
|
|
||||||
<summary>
|
|
||||||
获取全量总览数据(不区分年份,含剩余药材库存价值)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.StatisticsController.GetYearlyStatistics(System.String)">
|
|
||||||
<summary>
|
|
||||||
获取年度统计数据(含同比趋势)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:SimpleAdmin.Web.Core.StatisticsController.GetMonthlyDetails(System.String)">
|
|
||||||
<summary>
|
|
||||||
获取月度明细数据(返回 12 个月,无数据月份自动补零)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:SimpleAdmin.Web.Core.AuthBController">
|
<member name="T:SimpleAdmin.Web.Core.AuthBController">
|
||||||
<summary>
|
<summary>
|
||||||
B端登录控制器
|
B端登录控制器
|
||||||
|
|||||||
Reference in New Issue
Block a user