diff --git a/MasaBlazorApp3.sln b/MasaBlazorApp3.sln new file mode 100644 index 0000000..3049405 --- /dev/null +++ b/MasaBlazorApp3.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34024.191 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasaBlazorApp3", "MasaBlazorApp3\MasaBlazorApp3.csproj", "{B589889C-FAEB-4394-A21D-DDCADF39382D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Debug|x64.ActiveCfg = Debug|x64 + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Debug|x64.Build.0 = Debug|x64 + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Release|Any CPU.Build.0 = Release|Any CPU + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Release|x64.ActiveCfg = Release|x64 + {B589889C-FAEB-4394-A21D-DDCADF39382D}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {304B4C57-445A-464F-829B-444D21AFE355} + EndGlobalSection +EndGlobal diff --git a/MasaBlazorApp3/App.razor b/MasaBlazorApp3/App.razor new file mode 100644 index 0000000..f132fb4 --- /dev/null +++ b/MasaBlazorApp3/App.razor @@ -0,0 +1,15 @@ +@namespace MasaBlazorApp3 + + + + + + + + +

抱歉,找不到此页面。

+
+
+
+ + diff --git a/MasaBlazorApp3/DataAccess/AppDataConnection.cs b/MasaBlazorApp3/DataAccess/AppDataConnection.cs new file mode 100644 index 0000000..1b4da17 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/AppDataConnection.cs @@ -0,0 +1,41 @@ +using Google.Protobuf.Compiler; +using LinqToDB; +using LinqToDB.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MasaBlazorApp3.Pojo; + +namespace MasaBlazorApp3.DataAccess +{ + public class AppDataConnection : DataConnection + { + public AppDataConnection(DataOptions options) + : base(options.Options) + { + } + + public ITable User => this.GetTable(); + public ITable Role => this.GetTable(); + public ITable ChannelList => this.GetTable(); + public ITable ChannelStock => this.GetTable(); + public ITable DrugInfo => this.GetTable(); + public ITable DrugManuNo => this.GetTable(); + public ITable OrderInfo => this.GetTable(); + public ITable OrderDetail => this.GetTable(); + public ITable MachineRecord => this.GetTable(); + public ITable InOutInvoice => this.GetTable(); + public ITable AccountBook => this.GetTable(); + public ITable SettingManu => this.GetTable(); + public ITable Plan => this.GetTable(); + public ITable PlanDetails => this.GetTable(); + public ITable AccountBookG2 => this.GetTable(); + public ITable HkcChangeShifts => this.GetTable(); + public ITable HkcChangeShiftsDetail => this.GetTable(); + + + + } +} diff --git a/MasaBlazorApp3/DataAccess/ChannelStockWidthDrawerInfo.cs b/MasaBlazorApp3/DataAccess/ChannelStockWidthDrawerInfo.cs new file mode 100644 index 0000000..916e3e2 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/ChannelStockWidthDrawerInfo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess +{ + public class ChannelStockWidthDrawerInfo + { + //抽屉信息(抽屉号,抽屉类型) + public List> DrawerInfo { get; set; } + + public List ChannelStocks { get; set; } = new List(); + } +} diff --git a/MasaBlazorApp3/DataAccess/ChannelStockWithDrawerCount.cs b/MasaBlazorApp3/DataAccess/ChannelStockWithDrawerCount.cs new file mode 100644 index 0000000..4c7e67f --- /dev/null +++ b/MasaBlazorApp3/DataAccess/ChannelStockWithDrawerCount.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess +{ + public class ChannelStockWithDrawerCount + { + public int[] DrawerArray { get; set; } + public List ChannelStocks { get; set; } = new List(); + } +} diff --git a/MasaBlazorApp3/DataAccess/CheckInfo.cs b/MasaBlazorApp3/DataAccess/CheckInfo.cs new file mode 100644 index 0000000..5c788b3 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/CheckInfo.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess +{ + public class CheckInfo + { + public string StrInfo { get; set; } + public List TEntity { get; set; } = new List(); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IChannelListDao.cs b/MasaBlazorApp3/DataAccess/Dao/IChannelListDao.cs new file mode 100644 index 0000000..6caa546 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IChannelListDao.cs @@ -0,0 +1,104 @@ +using System; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Vo; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IChannelListDao + { + public Task> GetAllChannelList(int DrawerType, string drugName, int? take, int? skip); + + public Task> GetChannelStockByDrugId(string DrugId); + public Task> GetChannelListByDrawerNo(int DrawerNo); + public Task> GetChannelStockByDrawerNo(int DrawerNo, int Quantity = 0); + + + public Task> GetAllDrugChannelStock(); + + public Task> GetAllDrugChannelList(); + + public Task DrawerOperationFinish(List Stocks, int type,BoxModel boxNum,List channelLists); + + public Task UnBind(string id); + + public Task Bind(ChannelStock Stock); + + + Task> GetAllChannelListWithDrug(int DrawerType, string drugName, int? take, int? skip); + + Task> GetChannelStockByDrawerNoWithDrawers(int DrawerNo, int Quantity = 0); + + //盘点 + public Task DrawerCheckFinish(List Stocks); + //抽屉获取库存数据--药品绑定 + Task> GetChannelStockByBiaoDing(int DrawerNo, int Quantity=0); + //手术室药盒获取绑定数据 + Task> GetAllChannelListWithPlan(int? take, int? skip); + /// + /// 手术室药盒绑定套餐 + /// + /// + Task BindBox(ChannelList list, Plan plan); + /// + /// 手术室药盒绑定套餐 + /// + /// + Task BindBox(ChannelList channelList); + /// + /// 手术室药盒解绑套餐 + /// + /// + /// + Task UnBindBox(ChannelList list); + //获取手术室药盒中所有要补药的数据 + Task> GetAllBoxAddDrug(int? take, int? skip); + //手术室药盒补药获取毒麻柜中的药品信息 + Task> getTakeInfoByBox(ChannelList cl); + //手术室药盒补药完成 + Task BoxTakeFinish(List datas, ChannelList boxChannelList); + //手术室药盒入库 + Task> GetBoxWaitInfo(int? take, int? skip); + // 药盒入库弹窗页面获取要入库的药品明细信息 + Task> GetBoxAddToBox(ChannelList cl); + //手术室药盒入库获取待入库明细 + Task> getBoxWaitByBox(ChannelList cl, int? take, int? skip); + // 手术室药盒待入库明细入库完成 + Task BoxAddBoxFinish(ChannelList boxChannelList); + + //手术室药盒获取药盒药品及库存信息 + Task> GetBoxDrugInfo(string DrawerNo, int? take, int? skip); + //药盒移库时获取选中药盒号的药品信息 + Task> GetChannelStockByDrug(ChannelStock cs, string drawerNo,int? take, int? skip); + + /// + /// 药盒交换药品获取所有除本药盒外的所有药盒号 + /// + /// + /// + Task GetDrawerNum(ChannelStock channelStock); + + /// + /// 药盒移除药品,获取所有除本药盒外的所有包含该药品的药盒号 + /// + /// + /// + Task GetDrawerNumForRemove(ChannelStock channelStock); + + //手术室药盒交换药品完成 + Task BoxReplaceFinish(ChannelStock stock, List Stocks); + //手术室药盒移出药品完成 + Task BoxRemoveFinish(ChannelStock stock, string SelectedDrawerNo, int removeQuantity); + + Task> GetAllBox(); + //根据药盒查询药品信息 + Task> GetChannelStockByBox(int BoxNum); + //根据套餐下无库存的药箱 + Task> GetChannelStockByPlan(string plan); + //手术室药盒获取绑定数据 + Task> GetAllChannelList(); + //抽屉取药向药盒加药校验药盒中是否存在该药 + Task> CheckBoxDrugInfo(BoxModel BoxNum,List channelStockList); + //药箱中的药移入到抽屉 + Task RemoveDrugToDrawerFinish(string SelectedDrawerNo, ChannelStock channelStock, int quantity); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IDrugInfoDao.cs b/MasaBlazorApp3/DataAccess/Dao/IDrugInfoDao.cs new file mode 100644 index 0000000..abd2f98 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IDrugInfoDao.cs @@ -0,0 +1,36 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IDrugInfoDao + { + Task> GetAllDrugAndStock(); + + Task> GetAllDrugAndStockByBox(BoxModel boxModel); + + + Task> GetAllDrug(); + + + Task> GetAllDrug(string drugId, string drugName, int? take, int? skip); + + + //Task> GetAllDrugAndStockList(); + + Task GetDrugManuNo(string drugId, string manuNo); + + + //添加药品信息 + int AddDrugInfo(DrugInfo drugInfo); + + //删除药品信息 + Task DeleteDrugInfo(string drugId); + //修改药品信息 + Task UpdateDrugInfo(DrugInfo drugInfo); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IDrugManuNoDao.cs b/MasaBlazorApp3/DataAccess/Dao/IDrugManuNoDao.cs new file mode 100644 index 0000000..953cd58 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IDrugManuNoDao.cs @@ -0,0 +1,19 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IDrugManuNoDao + { + //添加批次 + int AddDrugManuNo(DrugManuNo drugManuNo); + //修改批次 + bool UpdateDrugManuNo(DrugManuNo drugManuNo); + //删除批次 + bool DeleteDrugManuNo(string id); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IHkcChangeShiftsDao.cs b/MasaBlazorApp3/DataAccess/Dao/IHkcChangeShiftsDao.cs new file mode 100644 index 0000000..d82de55 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IHkcChangeShiftsDao.cs @@ -0,0 +1,16 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IHkcChangeShiftsDao + { + //查询交接班记录 + public Task> GetChangeShiftRecordAsync(DateTime start, DateTime end, int? take, int? skip); + + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IInOutInvoiceDao.cs b/MasaBlazorApp3/DataAccess/Dao/IInOutInvoiceDao.cs new file mode 100644 index 0000000..182c63d --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IInOutInvoiceDao.cs @@ -0,0 +1,23 @@ +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Vo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IInOutInvoiceDao + { + Task> GetAllInvoiceByType(string invoiceNo, DateTime invoiceDate, int? take, int? skip, int type); + + Task> getTakeInfoByInvoiceNo(string invoiceNo); + Task> getAddInfoByInvoiceNo(string invoiceNo); + + Task InvoiceOutFinish(List data); + + + Task InvoiceAddFinish(List data); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IMachineRecordDao.cs b/MasaBlazorApp3/DataAccess/Dao/IMachineRecordDao.cs new file mode 100644 index 0000000..cfbbd47 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IMachineRecordDao.cs @@ -0,0 +1,30 @@ +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Vo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IMachineRecordDao + { + int InsertMachineRecord(MachineRecord record); + + Task> GetMachineRecordAsync(DateTime start, DateTime end, int operatorId, string drugId, int type, int? take, int? skip); + + Task> GetCanReturnRecords(DateTime start, DateTime end, int operatorId, string drugId, int? take, int? skip); + + Task>>> getReturnDrugInfoByRecords(List records); + + Task ReturnDrugFinish(List>> datas); + + Task> GetReturnEmpty(); + + Task> getReturnEmptyInfoByRecords(ChannelStock records); + + Task ReturnEmptyFinish(List datas,ChannelStock channelStock); + Task> GetReturnEmptyWithCanReturnQuantiy(); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IOrderInfoDao.cs b/MasaBlazorApp3/DataAccess/Dao/IOrderInfoDao.cs new file mode 100644 index 0000000..7179393 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IOrderInfoDao.cs @@ -0,0 +1,53 @@ +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Vo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IOrderInfoDao + { + public Task> GetAllOrderInfo(string OrderrNo,DateTime OrderDate, int? take, int? skip); + //导入处方查询数据 + public Task> GetAllOrderInfoForImport(string name, string OrderrNo, DateTime OrderDate, BoxModel boxModel, int? take, int? skip); + + public Task> GetAllCanReturnOrderInfo(string OrderrNo, DateTime OrderDate, int? take, int? skip); + + public Task> getDetailByOrderNo(string OrderrNo); + + + public Task> getTakeInfoByOrderNo(string OrderrNo); + + public Task OrderTakeFinish(List datas); + + + public Task OrderReturnFinish(List> datas, string OrderrNo); + + public Task>> getReturnInfoByOrderNo(string OrderrNo); + //获取药盒中的用药信息 + public Task> GetAllOrderInfoByBox(int box,string OrderrNo, DateTime OrderDate, int? take, int? skip); + //获取待处理处方中的麻醉师 + public Task> GetAllOrderInfo(string Name, string BoxNum, string PatientName,string OrderrNo, DateTime? OrderDate, int? take, int? skip); + + public Task> GetAllOrderInfoDrugByBox(BoxModel boxNum, string roomName, DateTime? OrderDate); + //获取麻醉师信息 + public Task> GetAnaesthetistName(); + //获取麻醉师单对应的手术间号 + public Task> GetOperationNum(int boxColor); + //获取麻醉师单对应的手术间号(查询全部手术间已绑套餐的手术间) + public Task> GetAllBindOperationNum(); + //获取所有药盒号 + public Task> GetDrawerNum(string machineId); + /// 获取指定药盒号 + public Task> GetDrawerNumByOperationNum(string machineId, List operationNum); + //核对处方 + public Task CheckOrderInfo(IList selectedOrderInfos, BoxModel boxModel); + //查询药品对应的库位 drawerType=1药品库位,其他则是回收库位 + public Task> GetStockByDRrug(string drugId, string manuNo, int drawerType); + //核对处方通过库位下的药品 + public Task CheckOrderInfoByChannelStock(IList csList, BoxModel boxModel); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IPlanDao.cs b/MasaBlazorApp3/DataAccess/Dao/IPlanDao.cs new file mode 100644 index 0000000..a56866f --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IPlanDao.cs @@ -0,0 +1,71 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IPlanDao + { + + /// + /// 获取所有套餐数据 + /// + /// + Task> GetAllPlanInfo(); + /// + /// 根据套餐ID获取套餐数据 + /// + /// + /// + Task GetPlanById(int Id); + /// + /// 新增套餐 + /// + /// + /// + Task InsertPlanInfo(Plan plan); + /// + /// 更新套餐 + /// + /// + /// + Task UpdatePlanInfo(Plan plan); + /// + /// 删除套餐 + /// + /// + /// + Task DeletePlanInfo(int planID); + /// + /// 向套餐添加药品 + /// + /// + /// + Task AddPlanDetail(PlanDetails details); + /// + /// 修改套餐中的药品 + /// + /// + /// + Task UpdatePlanDetail(PlanDetails details); + //查询要删除的套餐下是否有绑定,且绑定有库存 + Task CheckPlanBind(int planId); + //查询要删除的药品是否有绑定且库存大于0 + Task CheckPlanDetailBind(PlanDetails planDetail); + /// + /// 删除套餐中的药品 + /// + /// + /// + Task DeletePlanDetail(PlanDetails planID); + /// + /// 根据套餐明细获取套餐 + /// + /// + /// + bool CheckDrugById(PlanDetails details); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IReportDataDao.cs.cs b/MasaBlazorApp3/DataAccess/Dao/IReportDataDao.cs.cs new file mode 100644 index 0000000..7bf9a04 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IReportDataDao.cs.cs @@ -0,0 +1,23 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IReportDataDao + { + //获取库存导出数据 + Task> GetStockExportData(string drugName); + //专用账册导出数据 + Task> GetAccountExportData(DateTime? startDate, DateTime? endDate, string drugName); + //手术室患者麻醉药品使用登记本主表数据 + Task> GetOrderInfoParentData(DateTime? startDate); + //手术室患者麻醉药品使用登记本 + Task> GetOrderInfoData(DateTime? startDate); + //请领登记表导出 + Task> GetApplyInfoDate(DateTime searchDate); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IRoleDao.cs b/MasaBlazorApp3/DataAccess/Dao/IRoleDao.cs new file mode 100644 index 0000000..c1574d1 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IRoleDao.cs @@ -0,0 +1,18 @@ +using MasaBlazorApp3.Pojo; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IRoleDao + { + int InsertRole(Role role); + Task GetRoleById(int id); + + bool UpdateRole(Role role); + bool DeleteRole(int id); + + Task> GetRolesByName(string name, int? take, int? skip); + + Task> GetAllRoles(); + + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/ISelfTakeDao.cs b/MasaBlazorApp3/DataAccess/Dao/ISelfTakeDao.cs new file mode 100644 index 0000000..987fdef --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/ISelfTakeDao.cs @@ -0,0 +1,17 @@ +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Vo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + interface ISelfTakeDao + { + Task> GetChannelStocksByDrug(List drugInfos); + Task> getTakeInfoByOrderNo(List orderDetails); + Task OrderTakeFinish(List datas,OrderInfo order); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/ISettingManuDao.cs b/MasaBlazorApp3/DataAccess/Dao/ISettingManuDao.cs new file mode 100644 index 0000000..36545dc --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/ISettingManuDao.cs @@ -0,0 +1,14 @@ +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + interface ISettingManuDao + { + public Task> GetMenuItemsAsync(); + } +} diff --git a/MasaBlazorApp3/DataAccess/Dao/IUserDao.cs b/MasaBlazorApp3/DataAccess/Dao/IUserDao.cs new file mode 100644 index 0000000..8b12b3c --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Dao/IUserDao.cs @@ -0,0 +1,29 @@ +using MasaBlazorApp3.Pojo; + +namespace MasaBlazorApp3.DataAccess.Dao +{ + public interface IUserDao + { + int InsertUser(User user); + + Task> GetAllByNickname(string nickname, int? take, int? skip); + + User GetById(int id); + + User GetByUsername(string username); + + bool UpdateUser(User user); + + bool DeleteeUser(int id); + //重置用户密码 + bool ResetPassword(int id); + + Task UpdateSign(int id, string sign); + + bool UpdateUserPassword(User user); + //查询当前值班信息 + HkcChangeShifts GetOnDuty(); + //保存交接班信息 + Task UpdateChangeShift(HkcChangeShifts changeShift, HkcChangeShifts changeShiftNew); + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/ChannelListDao.cs b/MasaBlazorApp3/DataAccess/Impl/ChannelListDao.cs new file mode 100644 index 0000000..828ac64 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/ChannelListDao.cs @@ -0,0 +1,2386 @@ + +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using Mysqlx.Crud; +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class ChannelListDao : IChannelListDao + { + + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private GlobalStateService _globalStateService; + private readonly PortUtil _portUtil; + + private readonly ILog logger = LogManager.GetLogger(typeof(ChannelListDao)); + private readonly IServiceProvider _serviceProvider; + public ChannelListDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService, PortUtil portUtil) + { + _globalStateService = globalStateService; + _connection = connection; + _setting = setting.Value; + _portUtil = portUtil; + } + + public async Task> GetAllChannelList(int DrawerType, string drugName, int? take, int? skip) + { + + var query = _connection.ChannelStock.AsQueryable(); + + if (DrawerType != 0) + { + query = query.Where(cl => cl.DrawerType == DrawerType); + } + + if (!String.IsNullOrEmpty(drugName)) + { + query = query.Where(cl => cl.Drug.DrugName.Equals(drugName)); + } + + //query = query.Where(cl => !String.IsNullOrEmpty(cl.DrugId)); + query = query.Where(cl => cl.MachineId == _setting.machineId); + + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(cl => cl.Drug) + .LoadWith(cl => cl.Drug.Manus) + .LoadWith(cl => cl.drugManuNo) + .OrderBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + } + + public async Task> GetChannelStockByDrugId(string DrugId) + { + var query = _connection.ChannelStock.AsQueryable(); + + + return await query + .LoadWith(cs => cs.Drug) + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId == DrugId) + .Where(cs => cs.MachineId == _setting.machineId) + //.Where(cs => cs.Quantity > 0) + .OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> GetChannelStockByDrawerNo(int DrawerNo, int Quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable() + .LoadWith(cs => cs.Drug) + .LoadWith(cs => cs.drugManuNo) + .LoadWith(cs => cs.Drug.Manus) + .Where(cs => cs.DrawerNo == DrawerNo) + .Where(cs => cs.DrugId != String.Empty) + .Where(cs => cs.DrawerType == 1) + .Where(cs => cs.MachineId == _setting.machineId); + + if (Quantity > 0) + { + query = query.Where(cs => cs.Quantity > 0); + } + return await query + .OrderBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> GetChannelListByDrawerNo(int DrawerNo) + { + var query = _connection.ChannelList.AsQueryable(); + + + return await query + .LoadWith(cl => cl.Drug) + .LoadWith(cl => cl.ChannelStocks.Where(cs => cs.Quantity > 0)) + .Where(cl => cl.DrawerNo == DrawerNo) + .Where(cl => cl.DrawerType == 1) + .Where(cl => cl.MachineId == _setting.machineId) + .OrderBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .ToListAsync(); + } + + public async Task> GetAllDrugChannelStock() + { + var query = _connection.ChannelStock.AsQueryable(); + + + return await query + .LoadWith(cs => cs.Drug) + .Where(cs => !String.IsNullOrEmpty(cs.DrugId)) + .Where(cs => cs.DrawerType == 1) + .Where(cs => cs.MachineId == _setting.machineId) + .OrderBy((cs) => cs.DrugId) + .ThenBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> GetAllDrugChannelList() + { + var query = _connection.ChannelList.AsQueryable(); + + + return await query + .LoadWith(cl => cl.Drug) + .LoadWith(cl => cl.ChannelStocks) + .Where(cl => !String.IsNullOrEmpty(cl.DrugId)) + .Where(cl => cl.DrawerType == 1) + .Where(cl => cl.MachineId == _setting.machineId) + .OrderBy((cl) => cl.DrugId) + .ThenBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .ToListAsync(); + } + + public async Task DrawerOperationFinish(List Stocks, int type, BoxModel boxModel, List channelLists) + { + try + { + _connection.BeginTransaction(); + + string InvoiceId = "DRAWER_" + CurrentTimeMillis(); + var flag = true; + for (var i = 0; i < Stocks.Count; i++) + { + var stock = Stocks[i]; + + //var ManuNo = !stock.drugManuNo.ManuNo.Equals(stock.ManuNo) ? stock.drugManuNo.ManuNo : stock.ManuNo; + //var EffDate = !stock.drugManuNo.ManuNo.Equals(stock.ManuNo) ? stock.drugManuNo.EffDate : stock.EffDate; + var ManuNo = stock.ManuNo; + var EffDate = stock.EffDate; + if (!DateTime.TryParse(stock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (stock.ManuNo != null) + { + string[] idate = stock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Replace(" ", "").Trim())) + { + switch (iS.Replace(" ", "").Trim().Length) + { + case 4: + EffDate = iS.Replace(" ", "").Trim(); + break; + case 2: + EffDate += "-" + iS.Replace(" ", "").Trim(); + break; + case 1: + EffDate += "-0" + iS.Replace(" ", "").Trim(); + break; + } + } + } + + + } + } + else + { + EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + + // 出入库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo, + DrugId = stock.DrugId, + ManuNo = ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = type, + Quantity = type == 1 ? stock.AddQuantity : stock.TakeQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = InvoiceId, + Status = type == 1 ? 0 : (boxModel != null) ? 0 : 2, + BoxDrawer = boxModel == null ? 0 : boxModel.BoxName, + BoxColNo = boxModel == null ? 0 : boxModel.BoxNo + }); + // 更新库存 + var stockQ = _connection.ChannelStock.Where(cs => cs.Id == stock.Id) + .Set(cs => cs.Quantity, type == 1 ? stock.Quantity + stock.AddQuantity : stock.Quantity - stock.TakeQuantity); + // 入库时如果库存为0则有可能会修改批次效期进行保存 + if (type == 1 && stock.Quantity == 0 && !stock.drugManuNo.ManuNo.Equals(stock.ManuNo)) + { + stockQ = stockQ.Set(cs => cs.ManuNo, stock.drugManuNo.ManuNo).Set(cs => cs.EffDate, stock.drugManuNo.EffDate?.ToString("yyyy-MM-dd")).Set(cs => cs.Dmnguid, stock.drugManuNo.Id); + } + int r = stockQ.Update(); + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(stock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = stock.DrugId, + ManuNo = ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = type, + OutQuantity = stock.TakeQuantity, + AddQuantity = stock.AddQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == stock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = InvoiceId + }); + if (mid > 0 && r > 0 && acid > 0) + { + + } + else + { + flag = false; + break; + } + } + if (flag) + { + + if (boxModel != null) + { + //抽屉给药盒补药 + var BoxChannelStock = Stocks.GroupBy(cs => new { cs.DrugId, cs.ManuNo, cs.EffDate }).Select(cs => new + { + cs.Key.DrugId, + cs.Key.ManuNo, + cs.Key.EffDate, + total = cs.Sum(it => it.TakeQuantity) + }).ToList(); + foreach (var item in BoxChannelStock) + { + //查询本次加药的药盒里是否有该药品批次库存,有则累计加数量,无则insert记录 + ChannelStock cs = _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == boxModel.BoxName && cs.ColNo == boxModel.BoxNo && cs.DrugId == item.DrugId && cs.ManuNo == item.ManuNo).FirstOrDefault(); + if (cs != null) + { + //存在批次库存,更改数量 + cs.Quantity += item.total; + int iUpdate = await _connection.UpdateAsync(cs); + } + else + { + //不存在批次库存,插入一条批次数据 + // 保存账册 + //查询新加的药是否是已绑定的套餐,是则将基数写入,不是则基数记为零 + int baseQuantity = 0; + string listId = string.Empty; + ChannelStock csBase = _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == boxModel.BoxName && cs.ColNo == boxModel.BoxNo && cs.DrugId == item.DrugId).FirstOrDefault(); + if (csBase != null) + { + baseQuantity = csBase.CheckQuantity; + listId = csBase.ListId; + } + int acid = _connection.InsertWithInt32Identity(new ChannelStock() + { + Id = "DM5_" + Guid.NewGuid().ToString(), + ListId = listId, + MachineId = _setting.boxMachineId, + DrugId = item.DrugId, + ManuNo = item.ManuNo, + EffDate = item.EffDate, + DrawerNo = boxModel.BoxName, + ColNo = boxModel.BoxNo, + Quantity = item.total, + BaseQuantity = baseQuantity + }); + } + //将库存数加入channel_list表 + ChannelList clList = _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.boxMachineId) && cl.DrawerNo == boxModel.BoxName && cl.ColNo == boxModel.BoxNo).FirstOrDefault(); + if (clList != null) + { + clList.TotalQuantity += item.total; + int iUpdate = await _connection.UpdateAsync(clList); + if (iUpdate <= 0) + { + logger.Info($"抽屉加药记录药盒{boxModel.BoxName}-{boxModel.BoxNo}总库存失败,加药数量{item.total}"); + } + } + //药盒中是否有未绑套餐且库存为0的数据,有则删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == boxModel.BoxName && cs.ColNo == boxModel.BoxNo && cs.Quantity <= 0).Delete(); + //删除药盒中已绑套餐中同一药品多批次且库存为0的第一条数据 + List delChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == boxModel.BoxName && cs.ColNo == boxModel.BoxNo && cs.DrugId == item.DrugId).ToListAsync(); + if (delChannelStock != null && delChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + //for (int i = 1; i < delChannelStock.Count; i++) + //{ + // _connection.Delete(delChannelStock[i]); + //} + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = delChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (delChannelStock.Count == del.Count) + { + for (int j = 1; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + else + { + for (int j = 0; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + } + } + } + } + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error($"抽屉{(type == 1 ? "加药" : "取药")}操作完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + public long CurrentTimeMillis() + { + return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; + } + + public async Task UnBind(string id) + { + var r = await _connection.ChannelStock + .Where(cs => cs.Id == id) + .Set(cs => cs.DrugId, String.Empty) + .Set(cs => cs.Dmnguid, String.Empty) + .Set(cs => cs.EffDate, String.Empty) + .Set(cs => cs.ManuNo, String.Empty) + .UpdateAsync(); + return r > 0; + } + + public async Task Bind(ChannelStock Stock) + { + var q = _connection.ChannelStock + .Where(cs => cs.Id == Stock.Id) + .Set(cs => cs.Dmnguid, Stock.drugManuNo?.Id ?? String.Empty) + .Set(cs => cs.EffDate, Stock.drugManuNo?.EffDate.Value.ToString("yyyy-MM-dd") ?? String.Empty) + .Set(cs => cs.ManuNo, Stock.drugManuNo?.ManuNo ?? String.Empty); + + if (Stock.Drug != null && !Stock.Drug.DrugId.Equals(Stock.DrugId)) + { + q = q.Set(cs => cs.DrugId, Stock.Drug?.DrugId); + } + + var r = await q.UpdateAsync(); + return r > 0; + } + public async Task> GetAllChannelListWithDrug(int DrawerType, string drugName, int? take, int? skip) + { + + var query = _connection.ChannelStock.AsQueryable(); + + if (DrawerType != 0) + { + query = query.Where(cl => cl.DrawerType == DrawerType); + } + + if (!String.IsNullOrEmpty(drugName)) + { + query = query.Where(cl => cl.Drug.DrugName.Equals(drugName)); + } + + //query = query.Where(cl => !String.IsNullOrEmpty(cl.DrugId)); + query = query.Where(cl => cl.MachineId == _setting.machineId); + + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(cl => cl.Drug) + .LoadWith(cl => cl.Drug.Manus) + .LoadWith(cl => cl.drugManuNo) + .OrderBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + var other = _connection.DrugInfo.AsQueryable(); + List drugInfos = await other + .LoadWith(di => di.Manus) + .OrderBy((di) => di.DrugId) + .ToListAsync(); + + return new PageMultiData() + { + + TotalDesserts = pagedData, + Desserts = list, + Other = drugInfos + }; + } + //抽屉加药、取药获取数据 + public async Task> GetChannelStockByDrawerNoWithDrawers(int DrawerNo, int Quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable() + .LoadWith(cs => cs.Drug) + .LoadWith(cs => cs.drugManuNo) + .LoadWith(cs => cs.Drug.Manus) + .Where(cs => cs.DrawerNo == DrawerNo) + .Where(cs => cs.DrugId != String.Empty) + //.Where(cs => cs.DrawerType == 1) + .Where(cs => cs.MachineId == _setting.machineId); + + if (Quantity > 0) + { + query = query.Where(cs => cs.Quantity > 0); + } + int[] ints = _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId).GroupBy(cs => cs.DrawerNo).Select(cs => cs.Key).ToArray(); + List channelStocks = await query + .OrderBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + return new ChannelStockWithDrawerCount() { DrawerArray = ints, ChannelStocks = channelStocks }; + } + //盘点 + public async Task DrawerCheckFinish(List Stocks) + { + try + { + _connection.BeginTransaction(); + + string InvoiceId = "CHECK_" + CurrentTimeMillis(); + var flag = true; + for (var i = 0; i < Stocks.Count; i++) + { + var stock = Stocks[i]; + + //var ManuNo = !stock.drugManuNo.ManuNo.Equals(stock.ManuNo) ? stock.drugManuNo.ManuNo : stock.ManuNo; + //var EffDate = !stock.drugManuNo.ManuNo.Equals(stock.ManuNo) ? stock.drugManuNo.EffDate : stock.EffDate; + var ManuNo = stock.ManuNo; + var EffDate = stock.EffDate; + if (!DateTime.TryParse(stock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (stock.ManuNo != null) + { + string[] idate = stock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Replace(" ", "").Trim())) + { + switch (iS.Replace(" ", "").Trim().Length) + { + case 4: + EffDate = iS.Replace(" ", "").Trim(); + break; + case 2: + EffDate += "-" + iS.Replace(" ", "").Trim(); + break; + case 1: + EffDate += "-0" + iS.Replace(" ", "").Trim(); + break; + } + } + } + + + } + } + else + { + EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + // 出入库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo, + DrugId = stock.DrugId, + ManuNo = ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 4, + Quantity = stock.CheckQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = InvoiceId + }); + // 更新库存 + var stockQ = _connection.ChannelStock.Where(cs => cs.Id == stock.Id) + .Set(cs => cs.Quantity, stock.CheckQuantity) + .Set(cs => cs.ManuNo, ManuNo) + .Set(cs => cs.EffDate, EffDate) + .Set(cs => cs.Dmnguid, stock.drugManuNo?.Id); + + int r = stockQ.Update(); + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(stock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = stock.DrugId, + ManuNo = ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 3, + OutQuantity = stock.TakeQuantity, + AddQuantity = stock.AddQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == stock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = InvoiceId + }); + if (mid > 0 && r > 0 && acid > 0) + { + //根据抽屉类型判断是否需要写标签 + if (stock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(stock.CheckQuantity, stock.DrawerNo, stock.ColNo); + } + } + else + { + flag = false; + break; + } + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error($"抽屉盘点操作完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + //抽屉获取库存数据--药品绑定 + public async Task> GetChannelStockByBiaoDing(int DrawerNo, int Quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable() + .LoadWith(cs => cs.Drug) + .LoadWith(cs => cs.drugManuNo) + .LoadWith(cs => cs.Drug.Manus) + .Where(cs => cs.DrawerType == 1) + .Where(cs => cs.MachineId == _setting.machineId); + + if (DrawerNo > 0) + { + query = query.Where(cs => cs.DrawerNo == DrawerNo); + } + int[] ints = _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId).GroupBy(cs => cs.DrawerNo).Select(cs => cs.Key).ToArray(); + + + List channelStocks = await query + .OrderBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + return new ChannelStockWithDrawerCount() { DrawerArray = ints, ChannelStocks = channelStocks }; + } + //手术室药盒获取绑定数据 + public async Task> GetAllChannelListWithPlan(int? take, int? skip) + { + + var query = _connection.ChannelList.AsQueryable() + .Where(cl => cl.MachineId == _setting.boxMachineId); + //.LoadWith(cl=>cl.PlanInfo); + + + int pagedData = await query.CountAsync(); + + List list = await query + .OrderBy((cl) => cl.DrawerNo) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + if (list != null && list.Count > 0) + { + for (int i = 0; i < list.Count; i++) + { + if (!string.IsNullOrEmpty(list[i].DrugId)) + { + list[i].PlanInfo = _connection.Plan.AsQueryable().Where(p => p.Id == Convert.ToInt32(list[i].DrugId)).FirstOrDefault(); + } + list[i].BoxDisabled = list[i].TotalQuantity > 0 ? true : false; + } + } + + var other = _connection.Plan.AsQueryable().Where(p => p.UseState == 1 && p._PlanDetails.Count > 0); + List planInfos = await other + .LoadWith(p => p._PlanDetails.Where(pd => pd.UseState == 1)) + .OrderBy((p) => p.Id) + .ToListAsync(); + if (planInfos != null && planInfos.Count > 0) + { + for (int i = 0; i < planInfos.Count(); i++) + { + for (int j = 0; j < planInfos[i]._PlanDetails.Count(); j++) + { + planInfos[i]._PlanDetails[j]._DrugInfo = + _connection.DrugInfo.AsQueryable().Where(di => di.DrugId == planInfos[i]._PlanDetails[j].DrugId).First(); + + } + } + } + + return new PageMultiData() + { + + TotalDesserts = pagedData, + Desserts = list, + Other = planInfos + }; + } + /// + /// 手术室药盒绑定套餐 + /// + /// + public async Task BindBox(ChannelList list, Plan plan) + { + try + { + _connection.BeginTransaction(); + bool bFlag = true; + + var q = _connection.ChannelList + .Where(cs => cs.Id == list.Id).Set(cs => cs.DrugId, plan.Id.ToString()); + //将套餐中的药品信息写入channelStock + //查询套餐中药品信息 + var query = _connection.PlanDetails.AsQueryable().Where(p => p.PlanId == plan.Id && p.UseState == 1); + List planInfos = await query.ToListAsync(); + if (planInfos != null && planInfos.Count > 0) + { + for (int i = 0; i < planInfos.Count; i++) + { + int mid = await _connection.InsertAsync(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + ListId = list.Id, + MachineId = list.MachineId, + DrawerNo = list.DrawerNo, + ColNo = list.ColNo, + DrugId = planInfos[i].DrugId.ToString(), + BaseQuantity = planInfos[i].BaseQuantity, + //BoxState = 1 + }); + if (mid > 0) + { + bFlag = true; + } + else + { + bFlag = false; + break; + } + } + } + var r = await q.UpdateAsync(); + if (bFlag && r > 0) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = list.DrawerNo, + ColNo = list.ColNo, + DrugId = list.DrugId, + OperationTime = DateTime.Now, + Type = 55, + Quantity = list.TotalQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"药盒{list.DrawerNo}绑定套餐{list.DrugId}", + //GetId = operationVo.data.Id + }); + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + return false; + } + } + catch (Exception ex) + { + _connection.RollbackTransaction(); + logger.Info($"绑定套餐异常{ex.Message}"); + return false; + } + } + /// + /// 手术室药盒绑定套餐 + /// + /// + public async Task BindBox(ChannelList list) + { + try + { + _connection.BeginTransaction(); + bool bFlag = true; + + var q = _connection.ChannelList + .Where(cs => cs.Id == list.Id).Set(cs => cs.DrugId, list.PlanInfo.Id.ToString()); + //将套餐中的药品信息写入channelStock + //查询套餐中药品信息 + var query = _connection.PlanDetails.AsQueryable().Where(p => p.PlanId == list.PlanInfo.Id && p.UseState == 1); + List planInfos = await query.ToListAsync(); + if (planInfos != null && planInfos.Count > 0) + { + for (int i = 0; i < planInfos.Count; i++) + { + int mid = await _connection.InsertAsync(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + ListId = list.Id, + MachineId = list.MachineId, + DrawerNo = list.DrawerNo, + ColNo = list.ColNo, + DrugId = planInfos[i].DrugId.ToString(), + BaseQuantity = planInfos[i].BaseQuantity, + //BoxState = 1 + }); + if (mid > 0) + { + bFlag = true; + } + else + { + bFlag = false; + break; + } + } + } + var r = await q.UpdateAsync(); + if (bFlag && r > 0) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = list.DrawerNo, + ColNo = list.ColNo, + DrugId = list.DrugId, + OperationTime = DateTime.Now, + Type = 55, + Quantity = list.TotalQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"药盒{list.DrawerNo}绑定套餐{list.DrugId}", + //GetId = operationVo.data.Id + }); + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + return false; + } + } + catch (Exception ex) + { + _connection.RollbackTransaction(); + logger.Info($"绑定套餐异常{ex.Message}"); + return false; + } + } + /// + /// 手术室药盒解绑套餐 + /// + /// + /// + public async Task UnBindBox(ChannelList list) + { + try + { + _connection.BeginTransaction(); + + var r = await _connection.ChannelList + .Where(cs => cs.Id == list.Id) + .Set(cs => cs.DrugId, String.Empty) + .UpdateAsync(); + int iCount = await _connection.ChannelStock.Where(cs => cs.ListId == list.Id).CountAsync(); + int cs = 0; + if (iCount > 0) + { + cs = await _connection.ChannelStock.Where(cs => cs.ListId == list.Id).DeleteAsync(); + } + if (r > 0 && (iCount > 0 && cs > 0 || iCount <= 0)) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = list.DrawerNo, + ColNo = list.ColNo, + DrugId = list.DrugId, + OperationTime = DateTime.Now, + Type = 56, + Quantity = list.TotalQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"药盒{list.DrawerNo}解绑套餐{list.DrugId}", + //GetId = operationVo.data.Id + }); + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + return false; + } + } + catch (Exception ex) + { + _connection.RollbackTransaction(); + logger.Info($"手术室药盒解绑异常:{ex.Message}"); + return false; + } + } + //获取手术室药盒中所有要补药的数据 + public async Task> GetAllBoxAddDrug(int? take, int? skip) + { + try + { + List channelLists = new List(); + var query = _connection.ChannelStock//.AsQueryable() + .Where(cs => cs.MachineId == _setting.boxMachineId) + .GroupBy(cs => new { cs.DrawerNo, cs.ColNo, cs.DrugId }) + .Select(g => new + { + DrawerNo = g.Key.DrawerNo, + DrugId = g.Key.DrugId, + ColNo = g.Key.ColNo, + sumQuantity = g.Sum(cs => cs.Quantity), + baseQuantity = g.Max(cs => cs.BaseQuantity), + sumAdd = g.Sum(cs => cs.AddToQuantity) + }).Where(x => x.baseQuantity > x.sumQuantity + x.sumAdd) + .ToList(); + + var queryChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId == _setting.boxMachineId) + .LoadWith(cs => cs.Drug).ToList(); + + + var queryList = await _connection.ChannelList.AsQueryable().Where(cl => cl.MachineId == _setting.boxMachineId).ToListAsync(); + for (int i = 0; i < queryList.Count; i++) + { + foreach (var item in query) + { + if (queryList[i].DrawerNo == item.DrawerNo && queryList[i].ColNo == item.ColNo) + { + ChannelStock stock = queryChannelStock.Where(cs => cs.DrawerNo == item.DrawerNo && cs.ColNo == item.ColNo && cs.DrugId == item.DrugId && cs.BaseQuantity > item.sumQuantity).FirstOrDefault(); + if (stock != null) + { + stock.NeedQuantity = stock.BaseQuantity - item.sumQuantity; + queryList[i].ChannelStocks.Add(stock); + } + } + } + if (queryList[i].ChannelStocks != null && queryList[i].ChannelStocks.Count > 0) + { + channelLists.Add(queryList[i]); + } + } + + //if (query != null && query.Count > 0) + //{ + // var queryList = await _connection.ChannelList.AsQueryable().Where(cl => cl.MachineId == _setting.boxMachineId).ToListAsync(); + // for (int i = 0; i < queryList.Count; i++) + // { + // foreach (var item in query) + // { + // if (queryList[i].DrawerNo == item.DrawerNo) + + // { + // ChannelStock? stock = _connection.ChannelStock.AsQueryable() + // .Where(cs => cs.MachineId == _setting.boxMachineId && cs.DrawerNo == item.DrawerNo && cs.DrugId == item.DrugId).LoadWith(cs => cs.Drug).FirstOrDefault(); + // stock.NeedQuantity = item.baseQuantity - item.sumQuantity; + // queryList[i].ChannelStocks.Add(stock); + // } + // } + // if (queryList[i].ChannelStocks != null && queryList[i].ChannelStocks.Count > 0) + // { + // channelLists.Add(queryList[i]); + // } + // } + //} + + + int pagedData = channelLists.Count; + + + + + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = channelLists + }; + } + catch (Exception ex) + { + logger.Info($"获取药盒中补药数据失败{ex.Message}"); + return null; + } + } + + //手术室药盒补药获取毒麻柜中的药品信息 + public async Task> getTakeInfoByBox(ChannelList cl) + { + try + { + List tempData = new(); + List tempData2 = new(); + var flag = true; + for (int i = 0; i < cl.ChannelStocks.Count; i++) + { + ChannelStock boxCs = cl.ChannelStocks[i]; + // 当前药品取药数量 + var Quantity = boxCs.NeedQuantity; + List stockList = await _connection.ChannelStock + .Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 1 && cs.DrugId == boxCs.DrugId && cs.Quantity > 0 && cs.ManuNo != null) + .AsQueryable() + .OrderBy(cs => new { cs.EffDate, cs.Quantity }).ToListAsync(); + + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + + tempData2.Add(new BoxTakeVo() + { + Drug = boxCs.Drug, + StockQuantity = total, + Quantity = Quantity + }); + + if (flag) + { + // 盘点库存是否足够 + if (total >= Quantity) + { + + for (var j = 0; Quantity > 0; j++) + { + ChannelStock stock = stockList[j]; + if (Quantity > stock.Quantity) + { + // 取药数量大于库存 + tempData.Add(new BoxTakeVo() + { + Drug = boxCs.Drug, + BoxDetail = boxCs, + ChannelStock = stock, + StockQuantity = total, + Quantity = stock.Quantity, + }); + Quantity -= stock.Quantity; + } + else + { + //取药数量小于库存 + tempData.Add(new BoxTakeVo() + { + Drug = boxCs.Drug, + BoxDetail = boxCs, + ChannelStock = stock, + StockQuantity = total, + Quantity = Quantity, + }); + Quantity = 0; + } + } + } + else + { + // 库存不足 + flag = false; + } + } + } + if (flag) + { + tempData.Sort((s1, s3) => + { + int i = s1.ChannelStock.DrawerNo.CompareTo(s3.ChannelStock.DrawerNo); + if (i == 0) + { + return s1.ChannelStock.ColNo.CompareTo(s3.ChannelStock.ColNo); + } + return i; + }); + return tempData; + } + else + { + return tempData2; + } + + } + catch (Exception ex) + { + logger.Info($"获取数据异常{ex.Message}"); + return null; + } + } + //手术室药盒补药完成 + public async Task BoxTakeFinish(List datas, ChannelList boxChannelList) + { + + try + { + _connection.BeginTransaction(); + var flag = true; + for (var i = 0; i < datas.Count; i++) + { + var boxTakeVo = datas[i]; + var EffDate = boxTakeVo.ChannelStock.EffDate; + if (!DateTime.TryParse(boxTakeVo.ChannelStock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (boxTakeVo.ChannelStock.EffDate != null) + { + string[] idate = boxTakeVo.ChannelStock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Trim())) + { + switch (iS.Trim().Length) + { + case 4: + EffDate = iS.Trim(); + break; + case 2: + EffDate += "-" + iS.Trim(); + break; + case 1: + EffDate += "-0" + iS.Trim(); + break; + } + } + } + } + } + else + { + EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + // 出库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = boxTakeVo.ChannelStock.DrawerNo, + ColNo = boxTakeVo.ChannelStock.ColNo, + DrugId = boxTakeVo.ChannelStock.DrugId, + ManuNo = boxTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + Status = 2,//给交接柜补药不需要还药或还空瓶 + Quantity = boxTakeVo.GetQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = boxTakeVo.BoxDetail.Id.ToString(), + }); + // 更新库存 + int r = _connection.ChannelStock.Where(cs => cs.Id == boxTakeVo.ChannelStock.Id) + .Set(cs => cs.Quantity, boxTakeVo.ChannelStock.Quantity - boxTakeVo.GetQuantity) + .Update(); + #region 保存账册,给药盒补药不记录出库账册 + // 获取更新完库存之后的药品库存 + //List list = await _connection.ChannelStock.AsQueryable() + // .InnerJoin( + // _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + // (cs, cl) => cs.ListId == cl.Id, + // (cs, cl) => cs + // ) + // .Where(cs => cs.DrugId.Equals(boxTakeVo.ChannelStock.DrugId)) + // .ToListAsync(); + // 保存账册,给药盒补药不记录出库账册 + //int acid = _connection.InsertWithInt32Identity(new AccountBook() + //{ + // MachineId = _setting.machineId, + // DrugId = boxTakeVo.ChannelStock.DrugId, + // ManuNo = boxTakeVo.ChannelStock.ManuNo, + // EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + // OperationTime = DateTime.Now, + // Type = 2, + // OutQuantity = boxTakeVo.GetQuantity, + // AddQuantity = 0, + // Operator = _globalStateService.Operator.Id, + // Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + // ManuStock = list.Where(it => it.ManuNo == boxTakeVo.ChannelStock.ManuNo).Sum(it => it.Quantity), + // TotalStock = list.Sum(it => it.Quantity), + // //InvoiceId = orderTakeVo.OrderDetail.Id.ToString() + //}); + #endregion + //查询药盒中是否有该批次药品,有则把对应数量累加,无则insert + ChannelStock? BoxChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == boxTakeVo.BoxDetail.DrawerNo && cs.ColNo == boxTakeVo.BoxDetail.ColNo && cs.DrugId == boxTakeVo.ChannelStock.DrugId && cs.ManuNo == boxTakeVo.ChannelStock.ManuNo && cs.EffDate == EffDate).FirstOrDefault(); + int boxID = 0; + if (BoxChannelStock != null) + { + //BoxChannelStock.AddToQuantity += boxTakeVo.GetQuantity; + //BoxChannelStock.BoxState = 2; + //改为直接加到药盒库存中 + BoxChannelStock.Quantity += boxTakeVo.GetQuantity; + boxID = await _connection.UpdateAsync(BoxChannelStock); + } + else + { + //更新药盒中的药品数量 + boxID = _connection.Insert(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + ListId = boxTakeVo.BoxDetail.ListId, + MachineId = _setting.boxMachineId, + DrawerNo = boxTakeVo.BoxDetail.DrawerNo, + ColNo = boxTakeVo.BoxDetail.ColNo, + //AddToQuantity = boxTakeVo.Quantity,//boxTakeVo.GetQuantity, + //NeedQuantity = 0, + Quantity = boxTakeVo.GetQuantity, + DrugId = boxTakeVo.ChannelStock.DrugId, + ManuNo = boxTakeVo.ChannelStock.ManuNo, + EffDate = EffDate, + BaseQuantity = boxTakeVo.BoxDetail.BaseQuantity, + BoardType = boxTakeVo.BoxDetail.BoardType, + //BoxState = 2, //补药完成 + FillTime = DateTime.Now + }); + } + // 手术室药盒入库记录 + int boxMId = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = boxTakeVo.BoxDetail.DrawerNo, + ColNo = boxTakeVo.BoxDetail.ColNo, + DrugId = boxTakeVo.ChannelStock.DrugId, + ManuNo = boxTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 1, + Quantity = boxTakeVo.GetQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = boxTakeVo.ChannelStock.Id.ToString(), + }); + int delResutl = await _connection.ChannelStock.Where(cs => cs.MachineId == boxTakeVo.BoxDetail.MachineId && cs.DrugId == boxTakeVo.BoxDetail.DrugId && cs.DrawerNo == boxTakeVo.BoxDetail.DrawerNo && cs.ColNo == boxTakeVo.BoxDetail.ColNo && cs.ManuNo == null).DeleteAsync(); + if (mid > 0 && r > 0 && boxID > 0 && boxMId > 0) + { + if (boxTakeVo.ChannelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(boxTakeVo.ChannelStock.Quantity - boxTakeVo.GetQuantity, boxTakeVo.ChannelStock.DrawerNo, boxTakeVo.ChannelStock.ColNo); + } + + } + else + { + flag = false; + break; + } + } + if (flag) + { + int totalQuantity = boxChannelList.TotalQuantity + datas.Sum(it => it.GetQuantity); + int list = _connection.ChannelList.Where(cl => cl.Id == boxChannelList.Id) + .Set(cl => cl.TotalQuantity, totalQuantity) + .Update(); + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("处方取药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + + //手术室药盒入库 + public async Task> GetBoxWaitInfo(int? take, int? skip) + { + try + { + List channelLists = new List(); + var query = _connection.ChannelStock//.AsQueryable() + .Where(cs => cs.MachineId == _setting.boxMachineId) + .GroupBy(cs => new { cs.DrawerNo, cs.DrugId }) + .Select(g => new + { + DrawerNo = g.Key.DrawerNo, + DrugId = g.Key.DrugId, + sumQuantity = g.Sum(cs => cs.Quantity), + baseQuantity = g.Max(cs => cs.BaseQuantity), + AddToQuantity = g.Sum(cs => cs.AddToQuantity) + }).Where(x => x.baseQuantity > x.sumQuantity) + .ToList(); + + var queryChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId == _setting.boxMachineId && cs.BoxState == 2) + .LoadWith(cs => cs.Drug).ToList(); + + + var queryList = await _connection.ChannelList.AsQueryable().Where(cl => cl.MachineId == _setting.boxMachineId).ToListAsync(); + for (int i = 0; i < queryList.Count; i++) + { + foreach (var item in query) + { + if (queryList[i].DrawerNo == item.DrawerNo) + { + ChannelStock? stock = queryChannelStock.Where(cs => cs.DrawerNo == item.DrawerNo && cs.DrugId == item.DrugId && cs.BaseQuantity > item.sumQuantity).FirstOrDefault(); + if (stock != null) + { + stock.NeedQuantity = stock.BaseQuantity - item.sumQuantity; + stock.AddToQuantity = item.AddToQuantity; + queryList[i].ChannelStocks.Add(stock); + } + } + } + if (queryList[i].ChannelStocks != null && queryList[i].ChannelStocks.Count > 0) + { + channelLists.Add(queryList[i]); + } + } + int pagedData = channelLists.Count; + + + + + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = channelLists + }; + } + catch (Exception ex) + { + logger.Info($"获取药盒中补药数据失败{ex.Message}"); + return null; + } + } + // 药盒入库弹窗页面获取要入库的药品明细信息 + public async Task> GetBoxAddToBox(ChannelList cl) + { + if (cl != null) + { + List manuNosList = new List(); + foreach (var item in cl.ChannelStocks) + { + List manuList = new List(); + List csList = _connection.ChannelStock.Where(cs => cs.DrawerNo == item.DrawerNo && cs.DrugId == item.DrugId && cs.BoxState == 2).ToList(); + for (int i = 0; i < csList.Count; i++) + { + var existingItem = manuList.FirstOrDefault(item => item.DrugId == csList[i].DrugId && item.ManuNo == csList[i].ManuNo && item.EffDate.ToString() == csList[i].EffDate); + if (existingItem != null) + { + existingItem.Quantity += csList[i].AddToQuantity; + } + else + { + DrugManuNo manu = new DrugManuNo(); + manu.DrugId = csList[i].DrugId; + manu.ManuNo = csList[i].ManuNo; + manu.EffDate = Convert.ToDateTime(csList[i].EffDate); + manu.Quantity = csList[i].AddToQuantity; + manuList.Add(manu); + } + } + item.drugManuNoList = manuList; + } + } + return cl.ChannelStocks; + } + //手术室药盒入库获取待入库明细 + public async Task> getBoxWaitByBox(ChannelList cl, int? take, int? skip) + { + try + { + List tempData = new(); + List tempData2 = new(); + var flag = true; + for (int i = 0; i < cl.ChannelStocks.Count; i++) + { + ChannelStock boxCs = cl.ChannelStocks[i]; + // 当前药品取药数量 + var Quantity = boxCs.NeedQuantity; + List stockList = await _connection.ChannelStock + .Where(cs => cs.MachineId == _setting.boxMachineId && cs.DrugId == boxCs.DrugId && cs.Quantity > 0 && cs.ManuNo != null) + .AsQueryable() + .Skip((int)skip) + .Take((int)take) + .OrderBy(cs => cs.EffDate).ToListAsync(); + + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + + tempData2.Add(new BoxTakeVo() + { + Drug = boxCs.Drug, + StockQuantity = total, + Quantity = Quantity + }); + } + return tempData; + + } + catch (Exception ex) + { + logger.Info($"获取数据异常{ex.Message}"); + return null; + } + } + // 手术室药盒待入库明细入库完成 + public async Task BoxAddBoxFinish(ChannelList boxChannelList) + { + try + { + _connection.BeginTransaction(); + bool flag = true; + int totalQuantity = 0; + for (var i = 0; i < boxChannelList.ChannelStocks.Count; i++) + { + for (int j = 0; j < boxChannelList.ChannelStocks[i].drugManuNoList.Count; j++) + { + var EffDate = boxChannelList.ChannelStocks[i].drugManuNoList[j].EffDate?.ToString("yyyy-MM-dd"); + //效期转换出错 + //if (boxChannelList.ChannelStocks[i].EffDate != null) + //{ + // string[] idate = boxChannelList.ChannelStocks[i].EffDate.Split('/'); + // foreach (string iS in idate) + // { + // if (!string.IsNullOrEmpty(iS.Trim())) + // { + // switch (iS.Trim().Length) + // { + // case 4: + // EffDate = iS.Trim(); + // break; + // case 2: + // EffDate += "-" + iS.Trim(); + // break; + // case 1: + // EffDate += "-0" + iS.Trim(); + // break; + // } + // } + // } + //} + // 手术室药盒入库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + DrawerNo = boxChannelList.ChannelStocks[i].DrawerNo, + DrugId = boxChannelList.ChannelStocks[i].DrugId, + ManuNo = boxChannelList.ChannelStocks[i].drugManuNoList[j].ManuNo, + EffDate = boxChannelList.ChannelStocks[i].drugManuNoList[j].EffDate,//!String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 1, + Quantity = boxChannelList.ChannelStocks[i].drugManuNoList[j].Quantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = boxChannelList.ChannelStocks[i].Id.ToString(), + }); + // 更新库存 + ChannelStock? updateChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.DrawerNo == boxChannelList.ChannelStocks[i].DrawerNo && cs.DrugId == boxChannelList.ChannelStocks[i].drugManuNoList[j].DrugId && cs.ManuNo == boxChannelList.ChannelStocks[i].drugManuNoList[j].ManuNo && cs.EffDate == EffDate) + .FirstOrDefault(); + int r = 0; + if (updateChannelStock != null) + { + updateChannelStock.Quantity = updateChannelStock.Quantity + boxChannelList.ChannelStocks[i].drugManuNoList[j].Quantity; + updateChannelStock.AddToQuantity = 0; + updateChannelStock.NeedQuantity = 0; + updateChannelStock.BoxState = 0; + //updateChannelStock.EffDate = EffDate?.ToString("yyyy-MM-dd"); + //updateChannelStock.ManuNo = boxChannelList.ChannelStocks[i].drugManuNoList[j].ManuNo; + r = _connection.Update(updateChannelStock); + + } + + //totalQuantity += _connection.PlanDetails.Where(p => p.PlanId == Convert.ToInt32(boxChannelList.DrugId) && p.DrugId == boxChannelList.ChannelStocks[i].DrugId).Sum(p => p.BaseQuantity); + totalQuantity += boxChannelList.ChannelStocks[i].drugManuNoList[j].Quantity; + + if (!(mid > 0 && (updateChannelStock == null || r > 0))) + { + flag = false; + break; + } + + } + } + if (flag) + { + boxChannelList.TotalQuantity += totalQuantity; + int updateResult = _connection + .Update(boxChannelList); + if (updateResult > 0) + { + _connection.CommitTransaction(); + } + else + { + flag = false; + _connection.RollbackTransaction(); + } + } + else + { + _connection.RollbackTransaction(); + } + return flag; + } + catch (Exception ex) + { + logger.Info($"手术室药盒待入库明细入库完成操作异常:{ex.Message}"); + return false; + } + } + + //手术室药盒获取药盒药品及库存信息 + public async Task> GetBoxDrugInfo(string strDrawerNoCol, int? take, int? skip) + { + if (!string.IsNullOrEmpty(strDrawerNoCol)) + { + int drawerNo = 0; + int colNo = 0; + var spl = strDrawerNoCol.Split('-'); + if (spl != null && spl.Count() > 0) + { + drawerNo = Convert.ToInt32(spl[0]); + colNo = Convert.ToInt32(spl[1]); + } + + var query = _connection.PlanDetails.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId == _setting.boxMachineId && cl.DrawerNo.Equals(drawerNo) && cl.ColNo.Equals(colNo)), + (pd, cl) => pd.PlanId.ToString() == cl.DrugId, + (pd, cl) => pd).Where(pd => pd.UseState == 1); + + //查询不在套餐中的药 + List outOfPlanStock = await _connection.ChannelStock + .Where(cs => cs.MachineId == _setting.boxMachineId && cs.DrawerNo.Equals(drawerNo) && cs.ColNo.Equals(colNo) && string.IsNullOrEmpty(cs.ListId)) + .LoadWith(cs => cs.Drug) + .LoadWith(cs => cs.Drug.Manus) + .ToListAsync(); + List outOfPlanDetailList = new(); + if (outOfPlanStock != null && outOfPlanStock.Count > 0) + { + for (int i = 0; i < outOfPlanStock.Count; i++) + { + outOfPlanDetailList.Add(new PlanDetails() + { + _DrugInfo = outOfPlanStock[i].Drug, + channelStocks = outOfPlanStock, + _ManuNo = null + }); + + } + } + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(pd => pd._DrugInfo) + //.LoadWith(pd => cl._PlanDetails._DrugInfo) + .OrderBy((pd) => pd.DrugId) + //.ThenBy((cl) => cl.ColNo) + //.Skip((int)skip) + //.Take((int)take) + .ToListAsync(); + if (list != null && list.Count > 0) + { + for (int i = 0; i < list.Count; i++) + { + list[i].channelStocks = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId == _setting.boxMachineId && cs.DrawerNo == drawerNo && cs.ColNo == colNo && cs.DrugId == list[i].DrugId) + .LoadWith(cs => cs.Drug) + .LoadWith(cs => cs.Drug.Manus) + .ToList(); + } + } + if (outOfPlanDetailList != null && outOfPlanDetailList.Count > 0) + { + for (int i = 0; i < outOfPlanDetailList.Count; i++) + { + list.Add(outOfPlanDetailList[i]); + } + } + + //List list = await query + // .LoadWith(cl => cl.Drug) + // .LoadWith(cl => cl.Drug.Manus) + // .LoadWith(cl => cl.drugManuNo) + // .OrderBy((cl) => cl.DrawerNo) + // .ThenBy((cl) => cl.ColNo) + // .Skip((int)skip) + // .Take((int)take) + // .ToListAsync(); + + + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + } + else + { + return null; + } + } + //药盒移库时获取选中药盒号的药品信息 + public async Task> GetChannelStockByDrug(ChannelStock cs, string strDrawerNoCol, int? take, int? skip) + { + try + { + int drawerNo = 0; + int colNo = 0; + var spl = strDrawerNoCol.Split('-'); + if (spl != null && spl.Count() > 0) + { + drawerNo = Convert.ToInt32(spl[0]); + if (drawerNo > 30) + { + colNo = Convert.ToInt32(spl[1]); + } + else + { + colNo = Convert.ToInt32(spl[1] == "白" ? 1 : 2); + } + } + //else if (strDrawerNoCol.Length > 0) + //{ + // switch (strDrawerNoCol) + // { + // case "胃镜药盒": + // drawerNo = 31; + // colNo = 1; + // break; + // case "导管药盒": + // drawerNo = 32; + // colNo = 1; + // break; + // case "生殖药盒": + // drawerNo = 33; + // colNo = 1; + // break; + // case "妇门药盒": + // drawerNo = 34; + // colNo = 1; + // break; + // case "急诊药盒": + // drawerNo = 99; + // colNo = 1; + // break; + // case "恢复室药盒": + // drawerNo = 111; + // colNo = 1; + // break; + // } + //} + + var query = _connection.ChannelStock.AsQueryable().Where(c => c.MachineId == _setting.boxMachineId && c.DrawerNo.Equals(drawerNo) && c.ColNo.Equals(colNo) && c.DrugId.Equals(cs.DrugId) && c.ManuNo != cs.ManuNo); + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(cs => cs.Drug) + .OrderBy((cs) => cs.DrugId) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + + + + } + catch (Exception ex) + { + logger.Info($"药盒移库时获取选中药盒号的药品信息异常:{ex.Message}"); + return null; + } + } + + + /// + /// 药盒交换药品获取所有除本药盒外的所有药盒号 + /// + /// + /// + public async Task GetDrawerNum(ChannelStock channelStock) + { + //string[] stringArray = _connection.ChannelStock.Where(cs => cs.MachineId == channelStock.MachineId && cs.DrugId == channelStock.DrugId && cs.DrawerNo != channelStock.DrawerNo && !string.IsNullOrEmpty(cs.ManuNo) && cs.ManuNo != channelStock.ManuNo) + // .GroupBy(cs => new { cs.DrawerNo, cs.ColNo }).Select(cs => cs.Key.DrawerNo == 99 ? "急诊药盒" : cs.Key.DrawerNo == 111 ? "恢复室药盒" : cs.Key.DrawerNo == 31 ? "胃镜药盒" : cs.Key.DrawerNo == 32 ? "导管药盒" : cs.Key.DrawerNo == 33 ? "生殖药盒" : cs.Key.DrawerNo == 34 ? "妇门药盒" : cs.Key.DrawerNo.ToString() + "-" + (cs.Key.ColNo == 1 ? "白" : "绿")).ToArray(); + //return stringArray; + string[] stringArray = _connection.ChannelStock.Where(cs => cs.MachineId == channelStock.MachineId && cs.DrugId == channelStock.DrugId && !string.IsNullOrEmpty(cs.ManuNo) && cs.ManuNo != channelStock.ManuNo && (cs.DrawerNo == channelStock.DrawerNo && cs.ColNo != channelStock.ColNo || cs.DrawerNo != channelStock.DrawerNo)) + .GroupBy(cs => new { cs.DrawerNo, cs.ColNo }) + .Select(cs => cs.Key.DrawerNo == 99 ? "急诊药盒" : cs.Key.DrawerNo == 111 ? "恢复室药盒" : cs.Key.DrawerNo == 31 ? "胃镜药盒" : cs.Key.DrawerNo == 32 ? "导管药盒" : cs.Key.DrawerNo == 33 ? "生殖药盒" : cs.Key.DrawerNo == 34 ? "妇门药盒" : cs.Key.DrawerNo.ToString() + "-" + (cs.Key.ColNo == 1 ? "白" : "绿")).ToArray(); + return stringArray; + } + /// + /// 药盒移除药品,获取所有除本药盒外的所有包含该药品的药盒号 + /// + /// + /// + public async Task GetDrawerNumForRemove(ChannelStock channelStock) + { + string[] stringArray = _connection.ChannelStock.Where(cs => cs.MachineId == channelStock.MachineId && (cs.DrawerNo == channelStock.DrawerNo && cs.ColNo != channelStock.ColNo || cs.DrawerNo != channelStock.DrawerNo)) + .GroupBy(cs => new { cs.DrawerNo, cs.ColNo }) + .Select(cs => cs.Key.DrawerNo == 99 ? "急诊药盒" : cs.Key.DrawerNo == 111 ? "恢复室药盒" : cs.Key.DrawerNo == 31 ? "胃镜药盒" : cs.Key.DrawerNo == 32 ? "导管药盒" : cs.Key.DrawerNo == 33 ? "生殖药盒" : cs.Key.DrawerNo == 34 ? "妇门药盒" : cs.Key.DrawerNo.ToString() + "-" + (cs.Key.ColNo == 1 ? "白" : "绿")).ToArray(); + string[] stringDrawer = _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrugId == channelStock.DrugId && cs.ManuNo == channelStock.ManuNo).Select(cs => cs.Location).ToArray(); + string[] resultArr = stringArray.Concat(stringDrawer).ToArray(); + return resultArr; + } + //手术室药盒交换药品完成 + public async Task BoxReplaceFinish(ChannelStock stock, List stockList) + { + try + { + bool flag = true; + _connection.BeginTransaction(); + for (int i = 0; i < stockList.Count; i++) + { + //查询出药的药盒是否有该批次的药品 + ChannelStock replace1ChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.DrugId == stockList[i].DrugId && cs.ManuNo == stockList[i].ManuNo) + .FirstOrDefault(); + if (replace1ChannelStock != null) + { + //如果有该批次的药品,则更新数量 + int r = _connection.ChannelStock.Where(cs => cs.Id == replace1ChannelStock.Id) + .Set(cs => cs.Quantity, replace1ChannelStock.Quantity + stockList[i].AddQuantity) + .Update(); + if (r <= 0) + { + logger.Info($"更新药盒药品数量失败,药盒号:{stockList[i].Location},药品ID:{stockList[i].DrugId}"); + } + } + else + { + //如果没有该批次的药品,则新增一条批次数据 + int mid = _connection.Insert(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + ListId = stock.ListId, + MachineId = _setting.boxMachineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo, + DrugId = stock.DrugId, + ManuNo = stockList[i].ManuNo, + EffDate = stockList[i].EffDate, + DrawerType = stock.DrawerType, + BoardType = stock.BoardType, + Quantity = stockList[i].AddToQuantity, + BaseQuantity = stock.BaseQuantity, + //BoxState = 1 + }); + if (mid <= 0) + { + logger.Info($"新增药盒药品记录失败,药盒号:{stockList[i].DrawerNo},药品ID:{stockList[i].DrugId}"); + flag = false; + break; + } + } + + //记录操作记录 + int recordId = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = stock.MachineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo, + DrugId = stock.DrugId, + ManuNo = stock.ManuNo, + EffDate = !String.IsNullOrEmpty(stock.EffDate) ? DateTime.ParseExact(stock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 69, //交换 + Quantity = stockList[i].AddQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"{stock.Location}-{stock.Drug.DrugName}-{stock.ManuNo}与{stockList[i].Location}-{stockList[i].Drug.DrugName}-{stockList[i].ManuNo}交换,交换数量{stockList[i].AddQuantity}", + BoxDrawer = stockList[i].DrawerNo, + BoxColNo = stockList[i].ColNo + }); + if (recordId <= 0) + { + logger.Info($"药盒{stock.DrawerNo}交换药品新增操作记录失败,药盒号:{stockList[i].DrawerNo},药品ID:{stockList[i].DrugId}"); + flag = false; + break; + } + + + + //更新入药的药盒中的药品数量 + ChannelStock replace2ChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stockList[i].DrawerNo && cs.ColNo == stockList[i].ColNo && cs.DrugId == stock.DrugId && cs.ManuNo == stock.ManuNo) + .FirstOrDefault(); + if (replace2ChannelStock != null) + { + //如果有该批次的药品,则更新数量 + int r = _connection.ChannelStock.Where(cs => cs.Id == replace2ChannelStock.Id) + .Set(cs => cs.Quantity, replace2ChannelStock.Quantity + stockList[i].AddQuantity) + .Update(); + if (r <= 0) + { + logger.Info($"更新药盒药品数量失败,药盒号:{stockList[i].DrawerNo},药品ID:{stockList[i].DrugId}"); + flag = false; + break; + } + } + else + { + //如果没有该批次的药品,则新增一条记录 + int mid = _connection.Insert(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + ListId = stockList[i].ListId, + MachineId = _setting.boxMachineId, + DrawerNo = stockList[i].DrawerNo, + ColNo = stockList[i].ColNo, + DrugId = stock.DrugId, + ManuNo = stock.ManuNo, + EffDate = stock.EffDate, + Quantity = stockList[i].AddQuantity, + BaseQuantity = stockList[i].BaseQuantity, + //BoxState = 1 + }); + if (mid <= 0) + { + logger.Info($"新增药盒药品记录失败,药盒号:{stockList[i].DrawerNo},药品ID:{stockList[i].DrugId}"); + flag = false; + break; + } + + } + + //出库药盒减数量 + int updateQuantity = _connection.ChannelStock.Where(cs => cs.Id == stock.Id) + .Set(cs => cs.Quantity, stock.Quantity - stockList[i].AddQuantity) + .Update(); + if (updateQuantity <= 0) + { + logger.Info($"更新出库药盒药品减数量失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + break; + } + //入库药盒减数量 + int updateQuantity2 = _connection.ChannelStock.Where(cs => cs.Id == stockList[i].Id) + .Set(cs => cs.Quantity, stockList[i].Quantity - stockList[i].AddQuantity) + .Update(); + if (updateQuantity2 <= 0) + { + logger.Info($"更新入库药盒药品减数量失败,药盒号:{stockList[i].DrawerNo},药品ID:{stockList[i].DrugId}"); flag = false; + break; + } + + //删除批次库存为零的数据 + //移出库位里是否有未绑套餐且库存为0的数据,有则删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.Quantity <= 0).Delete(); + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == stockList[i].DrawerNo && cs.ColNo == stockList[i].ColNo && cs.Quantity <= 0).Delete(); + //删除绑定套餐中同一药品多批次且库存为0的第一条数据 + List delChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.DrugId == stock.DrugId).ToListAsync(); + if (delChannelStock != null && delChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = delChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (delChannelStock.Count == del.Count) + { + for (int j = 1; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + else + { + for (int j = 0; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + } + } + //删除绑定套餐中同一药品多批次且库存为0的第一条数据 + List listChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stockList[i].DrawerNo && cs.ColNo == stockList[i].ColNo && cs.DrugId == stockList[i].DrugId).ToListAsync(); + if (listChannelStock != null && listChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = listChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (listChannelStock.Count == del.Count) + { + for (int j = 1; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + else + { + for (int j = 0; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + } + } + } + if (flag) + { + + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Info($"手术室药盒交换药品完成异常:{ex.Message}"); + _connection.RollbackTransaction(); + return false; + } + } + //手术室药盒移出药品完成 + public async Task BoxRemoveFinish(ChannelStock stock, string SelectedDrawerNo, int removeQuantity) + { + try + { + bool flag = true; + _connection.BeginTransaction(); + + int selectDrawerNo = 0; + int selectColNo = 0; + var selectSpl = SelectedDrawerNo.Split('-'); + if (selectSpl != null && selectSpl.Count() > 0) + { + selectDrawerNo = Convert.ToInt32(selectSpl[0]); + selectColNo = Convert.ToInt32(selectSpl[1] == "白" ? 1 : 2); + if (selectDrawerNo > 30) + { + selectColNo = Convert.ToInt32(selectSpl[1]); + } + else + { + selectColNo = Convert.ToInt32(selectSpl[1] == "白" ? 1 : 2); + } + } + //else if (SelectedDrawerNo.Length > 0) + //{ + // switch (SelectedDrawerNo) + // { + // case "胃镜药盒": + // selectDrawerNo = 31; + // selectColNo = 1; + // break; + // case "导管药盒": + // selectDrawerNo = 32; + // selectColNo = 1; + // break; + // case "生殖药盒": + // selectDrawerNo = 33; + // selectColNo = 1; + // break; + // case "妇门药盒": + // selectDrawerNo = 34; + // selectColNo = 1; + // break; + // case "急诊药盒": + // selectDrawerNo = 99; + // selectColNo = 1; + // break; + // case "恢复室药盒": + // selectDrawerNo = 111; + // selectColNo = 1; + // break; + // } + //} + + //查询移入的药品是否有库存 + ChannelStock inChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId == stock.MachineId && cs.DrawerNo == selectDrawerNo && cs.ColNo == selectColNo && cs.DrugId == stock.DrugId && cs.ManuNo == stock.ManuNo) + .FirstOrDefault(); + if (inChannelStock != null) + { + //如果有该批次的药品,则更新数量 + int r = _connection.ChannelStock.Where(cs => cs.Id == inChannelStock.Id) + .Set(cs => cs.Quantity, inChannelStock.Quantity + removeQuantity) + .Update(); + if (r <= 0) + { + logger.Info($"手术室药盒移出药品更新数量失败,药盒号:{SelectedDrawerNo},药品ID:{stock.DrugId}"); + } + } + else + { + //如果没有该批次的药品,先查询是否有未绑批次的,有则更新批次信息,无则新增一条记录 + ChannelStock inDrugChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId == stock.MachineId && cs.DrawerNo == selectDrawerNo && cs.ColNo == selectColNo && cs.DrugId == stock.DrugId && cs.Quantity <= 0) + .FirstOrDefault(); + if (inDrugChannelStock != null) + { + int mid = _connection.ChannelStock.Where(cs => cs.Id == inDrugChannelStock.Id) + .Set(cs => cs.Quantity, removeQuantity) + .Set(cs => cs.ManuNo, stock.ManuNo) + .Set(cs => cs.EffDate, stock.EffDate) + .Update(); + if (mid <= 0) + { + logger.Info($"更新药盒药品批次记录失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + } + } + else + { + int mid = _connection.Insert(new ChannelStock() + { + Id = Guid.NewGuid().ToString(), + MachineId = stock.MachineId, + DrawerNo = selectDrawerNo, + ColNo = selectColNo, + DrugId = stock.DrugId, + ManuNo = stock.ManuNo, + EffDate = stock.EffDate, + Quantity = removeQuantity, + BaseQuantity = stock.BaseQuantity, + //BoxState = 1 + }); + if (mid <= 0) + { + logger.Info($"新增药盒药品记录失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + } + } + } + if (flag) + { + //减本库位库存数量 + int updateQuantity2 = _connection.ChannelStock.Where(cs => cs.Id == stock.Id) + .Set(cs => cs.Quantity, stock.Quantity - removeQuantity) + .Update(); + if (updateQuantity2 <= 0) + { + logger.Info($"更新入库药盒药品减数量失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + } + else + { + int updateTotalQuantity = 0; + int updateMoveToTotalQuantity = 0; + //修改总库存数 + ChannelList channelList = _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.boxMachineId) && cl.DrawerNo == stock.DrawerNo && cl.ColNo == stock.ColNo).FirstOrDefault(); + if (channelList != null) + { + updateTotalQuantity = _connection.ChannelList.Where(cl => cl.Id == channelList.Id) + .Set(cl => cl.TotalQuantity, channelList.TotalQuantity - removeQuantity) + .Update(); + } + + //修改移入药盒的总库存数 + + ChannelList moveToChannelList = _connection.ChannelList.Where(cl => cl.MachineId == stock.MachineId && cl.DrawerNo == selectDrawerNo && cl.ColNo == selectColNo).FirstOrDefault(); + if (moveToChannelList != null) + { + updateMoveToTotalQuantity = _connection.ChannelList.Where(cl => cl.Id == moveToChannelList.Id) + .Set(cl => cl.TotalQuantity, moveToChannelList.TotalQuantity + removeQuantity) + .Update(); + } + if (updateTotalQuantity > 0 && updateMoveToTotalQuantity > 0) + { + flag = true; + } + else + { + flag = false; + } + + } + if (flag) + { + //记录操作记录 + int recordId = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = stock.MachineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo,//移入的药盒号 + DrugId = stock.DrugId, + ManuNo = stock.ManuNo, + EffDate = !String.IsNullOrEmpty(stock.EffDate) ? DateTime.ParseExact(stock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 21, //移 + Quantity = removeQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + BoxDrawer = selectDrawerNo, + BoxColNo = selectColNo, + InvoiceId = stock.Id.ToString(), + }); + if (recordId <= 0) + { + logger.Info($"药盒{stock.DrawerNo}交换药品新增操作记录失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + } + } + //移出库位里是否有未绑套餐且库存为0的数据,有则删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == selectDrawerNo && cs.ColNo == selectColNo && cs.Quantity <= 0).Delete(); + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.Quantity <= 0).Delete(); + //删除绑定套餐中同一药品多批次且库存为0的第一条数据 + List delChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.DrugId == stock.DrugId).ToListAsync(); + if (delChannelStock != null && delChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + //for (int i = 1; i < delChannelStock.Count; i++) + //{ + // _connection.Delete(delChannelStock[i]); + //} + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = delChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (delChannelStock.Count == del.Count) + { + for (int j = 1; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + else + { + for (int j = 0; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + } + } + } + if (flag) + { + + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Info($"手术室药盒移出药品异常{ex.Message}"); + _connection.RollbackTransaction(); + return false; + } + } + + + public async Task> GetAllBox() + { + var query = _connection.ChannelList.AsQueryable(); + + + return await query + .Where(cl => cl.MachineId == _setting.boxMachineId) + .OrderBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .ToListAsync(); + } + //根据药盒查询药品信息 + public async Task> GetChannelStockByBox(int BoxNum) + { + var query = _connection.ChannelStock.AsQueryable() + .Where(cl => cl.MachineId == _setting.boxMachineId && cl.DrawerNo == BoxNum && cl.Quantity > 0); + return await query + //.Where(cl=>cl.Quantity<=0) + .OrderBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.DrawerNo) + .ThenBy((cl) => cl.ColNo) + .ToListAsync(); + } + //根据套餐下无库存的药箱 + public async Task> GetChannelStockByPlan(string plan) + { + var query = await _connection.ChannelList.AsQueryable().Where(cl => cl.MachineId == _setting.boxMachineId && cl.DrugId == plan).Select(c => c.DrawerNo).ToListAsync(); + if (query != null && query.Count > 0) + { + return await _connection.ChannelStock.Where(c => query.Contains(c.DrawerNo) && c.MachineId == _setting.boxMachineId && c.Quantity <= 0).ToListAsync(); + } + return null; + } + + //手术室药盒获取绑定数据 + public async Task> GetAllChannelList() + { + + var query = _connection.ChannelList.AsQueryable() + .Where(cl => cl.MachineId == _setting.boxMachineId); + //.LoadWith(cl=>cl.PlanInfo); + + + int pagedData = await query.CountAsync(); + + List list = await query + .OrderBy((cl) => cl.DrawerNo) + .ToListAsync(); + return list; + } + + //抽屉取药向药盒加药校验药盒中是否存在该药 + public async Task> CheckBoxDrugInfo(BoxModel BoxNum, List channelStockList) + { + string errorInfo = string.Empty; + int count = 0; + List channelList = new List(); + for (int i = 0; i < channelStockList.Count; i++) + { + //ChannelList cl = _connection.ChannelList.InnerJoin + // ( + // _connection.PlanDetails.Where(pd => pd.UseState == 1 && pd.DrugId == channelStockList[i].DrugId), + // (cs, pd) => cs.DrugId == pd.PlanId.ToString(), + // (cs, pd) => cs + // ).FirstOrDefault(); + ChannelList cl = _connection.ChannelList.Where(cl => cl.MachineId == _setting.boxMachineId && cl.DrawerNo == BoxNum.BoxName && cl.ColNo == BoxNum.BoxNo).FirstOrDefault(); + if (cl != null && !string.IsNullOrEmpty(cl.DrugId)) + { + //查该库位绑定的套餐对应的药品信息 + cl._PlanDetails = _connection.PlanDetails.Where(pd => pd.PlanId.ToString() == cl.DrugId && pd.DrugId == channelStockList[i].DrugId).ToList(); + channelList.Add(cl); + } + else + { + errorInfo += $"{channelStockList[i].Drug.DrugName}未在{(BoxNum.BoxName == 99 ? "急诊" : BoxNum.BoxName == 111 ? "恢复室" : string.Concat(BoxNum.BoxName.ToString(), (BoxNum.BoxNo == 1 ? "-白" : "-绿")))}药盒中绑定;"; + } + } + + return new CheckInfo() + { + + StrInfo = errorInfo, + TEntity = channelList + }; + } + //药箱中的药移入到抽屉 + /// + /// + /// + /// 移入的抽屉 + /// 移出的药盒 + /// 移出数量 + /// + public async Task RemoveDrugToDrawerFinish(string SelectedDrawerNo, ChannelStock stock, int removeQuantity) + { + try + { + bool flag = true; + _connection.BeginTransaction(); + + int selectDrawerNo = 0; + int selectColNo = 0; + var selectSpl = SelectedDrawerNo.Split('-'); + if (selectSpl != null && selectSpl.Count() > 0) + { + selectDrawerNo = Convert.ToInt32(selectSpl[0]); + selectColNo = Convert.ToInt32(selectSpl[1]); + } + + //查询移入的药品是否有库存 + ChannelStock inChannelStock = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId.Equals(_setting.machineId) && cs.DrawerNo == selectDrawerNo && cs.ColNo == selectColNo && cs.DrugId == stock.DrugId && cs.ManuNo == stock.ManuNo) + .FirstOrDefault(); + if (inChannelStock != null) + { + //如果有该批次的药品,则更新数量 + int r = _connection.ChannelStock.Where(cs => cs.Id == inChannelStock.Id) + .Set(cs => cs.Quantity, inChannelStock.Quantity + removeQuantity) + .Update(); + if (r <= 0) + { + logger.Info($"手术室药盒移出药品更新数量失败,药盒号:{SelectedDrawerNo},药品ID:{stock.DrugId}"); + } + } + else + { + logger.Info($"抽屉{SelectedDrawerNo}不存在药品{stock.Drug.DrugName},批次{stock.ManuNo},无法移入"); + flag = false; + } + if (flag) + { + //减本库位库存数量 + int updateQuantity2 = _connection.ChannelStock.Where(cs => cs.Id == stock.Id) + .Set(cs => cs.Quantity, stock.Quantity - removeQuantity) + .Update(); + if (updateQuantity2 <= 0) + { + logger.Info($"更新入库药盒药品减数量失败,药盒号:{stock.DrawerNo},药品ID:{stock.DrugId}"); + flag = false; + } + if (flag) + { + //记录操作记录 + int recordId = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = stock.DrawerNo, + ColNo = stock.ColNo,//移入的抽屉库位 + BoxDrawer = selectDrawerNo, + BoxColNo = selectColNo,//移入的抽屉库位 + DrugId = stock.DrugId, + ManuNo = stock.ManuNo, + EffDate = !String.IsNullOrEmpty(stock.EffDate) ? DateTime.ParseExact(stock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 21, //交换 + Quantity = removeQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"药盒{stock.Location}中药品{stock.Drug.DrugName}批次{stock.ManuNo},移入抽屉{SelectedDrawerNo},数量{removeQuantity}", + }); + if (recordId <= 0) + { + logger.Info($"移盒移出药品失败:药盒{stock.Location}中药品{stock.Drug.DrugName}批次{stock.ManuNo},移入抽屉{SelectedDrawerNo},数量{removeQuantity}"); + flag = false; + } + } + //移出库位里是否有未绑套餐且库存为0的数据,有则删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.Quantity <= 0).Delete(); + //删除绑定套餐中同一药品多批次且库存为0的第一条数据 + List delChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == stock.DrawerNo && cs.ColNo == stock.ColNo && cs.DrugId == stock.DrugId).ToListAsync(); + if (delChannelStock != null && delChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + //for (int i = 1; i < delChannelStock.Count; i++) + //{ + // _connection.Delete(delChannelStock[i]); + //} + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = delChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (delChannelStock.Count == del.Count) + { + for (int j = 1; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + else + { + for (int j = 0; j < del.Count; j++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[j].Id).Delete(); + } + } + } + } + } + if (flag) + { + + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Info($"手术室药盒移出药品异常{ex.Message}"); + _connection.RollbackTransaction(); + return false; + } + } + + + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/DrugInfoDao.cs b/MasaBlazorApp3/DataAccess/Impl/DrugInfoDao.cs new file mode 100644 index 0000000..e55ca28 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/DrugInfoDao.cs @@ -0,0 +1,174 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class DrugInfoDao : IDrugInfoDao + { + + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(DrugInfoDao)); + + public DrugInfoDao(AppDataConnection connection, IOptions setting) + { + _connection = connection; + _setting = setting.Value; + } + public async Task> GetAllDrugAndStock() + { + var query = _connection.DrugInfo.AsQueryable(); + + List drugList = await query + .LoadWith(di => di.Stocks.Where(cs => cs.Quantity > 0 && (cs.MachineId == _setting.machineId))) + .InnerJoin( + _connection.ChannelStock.Where(cl => cl.MachineId == _setting.machineId && cl.DrawerType == 1).GroupBy(cl => cl.DrugId), + (di, cl) => di.DrugId == cl.Key, + (di, cl) => di + ) + //.Where(cs => cs.Quantity > 0) + .OrderBy((di) => di.DrugId) + .ToListAsync(); + if(drugList!=null&&drugList.Count>0) + { + for (int i = 0; i < drugList.Count; i++) + { + List channelStocks = _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrugId == drugList[i].DrugId).OrderBy(cs=> new{ cs.DrawerNo, cs.ColNo}).ToList(); + var nomalBoxStockList= channelStocks.Where(cs => cs.DrawerNo <= 30).GroupBy(cs =>new { cs.ManuNo, cs.EffDate }).Select(g => new { manuNo=g.Key.ManuNo,effdate=g.Key.EffDate,Quantity=g.Sum(k=>k.Quantity)}).ToList(); + foreach (var item in nomalBoxStockList) + { + ChannelStock nomalBox = new ChannelStock() { DrugId = drugList[i].DrugId,ManuNo=item.manuNo,Quantity=item.Quantity,EffDate=item.effdate,MachineId= "DM5" }; + drugList[i].Stocks.Add(nomalBox); + } + drugList[i].Stocks.AddRange(channelStocks.Where(cs=>cs.DrawerNo>30)); + } + } + return drugList; + //return await query + // .LoadWith(di => di.Stocks.Where(cs => cs.Quantity > 0 && (cs.MachineId == _setting.machineId))) + // .InnerJoin( + // _connection.ChannelStock.Where(cl => cl.MachineId == _setting.machineId && cl.DrawerType == 1).GroupBy(cl => cl.DrugId), + // (di, cl) => di.DrugId == cl.Key, + // (di, cl) => di + // ) + // //.Where(cs => cs.Quantity > 0) + // .OrderBy((di) => di.DrugId) + // .ToListAsync(); + } + + public async Task> GetAllDrugAndStockByBox(BoxModel boxModel) + { + var query = _connection.DrugInfo.AsQueryable(); + + + return await query + .LoadWith(di => di.Stocks.Where(cs => cs.Quantity > 0 && cs.MachineId == _setting.boxMachineId&&cs.DrawerNo==boxModel.BoxName&&cs.ColNo==boxModel.BoxNo)) + .InnerJoin( + _connection.ChannelStock.Where(cl => cl.MachineId == _setting.boxMachineId && cl.DrawerNo==boxModel.BoxName&&cl.ColNo==boxModel.BoxNo).GroupBy(cl => cl.DrugId), + (di, cl) => di.DrugId == cl.Key, + (di, cl) => di + ) + //.Where(cs => cs.Quantity > 0) + .OrderBy((di) => di.DrugId) + .ToListAsync(); + } + + public async Task> GetAllDrug(string drugId, string drugName, int? take, int? skip) + { + var query = _connection.DrugInfo.AsQueryable(); + + if (!String.IsNullOrEmpty(drugId)) + { + query = query.Where(di => di.DrugId.Contains(drugId)); + } + if (!String.IsNullOrEmpty(drugName)) + { + query = query.Where(di => di.DrugName.Contains(drugName)); + } + + + + int pagedData = await query.CountAsync(); + query = query + .LoadWith(di => di.Manus) + .OrderBy((di) => di.DrugId) + .Skip((int)skip) + .Take((int)take); + + List list = await query + .ToListAsync(); + + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + } + + public async Task> GetAllDrug() + { + var query = _connection.DrugInfo.AsQueryable(); + + return await query + .LoadWith(di => di.Manus) + .OrderBy((di) => di.DrugId) + .ToListAsync(); + } + + public async Task GetDrugManuNo(string drugId, string manuNo) + { + var query = _connection.DrugManuNo.AsQueryable(); + + return await query.Where(m => m.DrugId.Equals(drugId)) + .Where(m => m.ManuNo.Equals(manuNo)) + .FirstAsync(); + } + + public int AddDrugInfo(DrugInfo drugInfo) + { + return _connection.InsertWithInt32Identity(drugInfo); + } + + public async Task DeleteDrugInfo(string drugId) + { + try + { + logger.Error($"删除药品{drugId}"); + return _connection.DrugInfo.Where(di => di.DrugId == drugId).Delete() > 0; + } + catch (Exception ex) + { + logger.Error("删除药品失败,错误:" + ex.Message); + return false; + } + } + + public async Task UpdateDrugInfo(DrugInfo drugInfo) + { + try + { + var statement = _connection.DrugInfo + .Where(di => di.DrugId == drugInfo.DrugId) + .Set(di => di.DrugName, drugInfo.DrugName) + .Set(di => di.DrugSpec, drugInfo.DrugSpec) + .Set(di=>di.PackH,drugInfo.PackH) + .Set(di => di.Manufactory, drugInfo.Manufactory); + return statement.Update() > 0; + } + catch (Exception ex) + { + logger.Error($"修改药品{drugInfo.DrugId}失败,错误:" + ex.Message); + return false; + } + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/DrugManuNoDao.cs b/MasaBlazorApp3/DataAccess/Impl/DrugManuNoDao.cs new file mode 100644 index 0000000..8062766 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/DrugManuNoDao.cs @@ -0,0 +1,56 @@ +using LinqToDB; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class DrugManuNoDao : IDrugManuNoDao + { + private readonly AppDataConnection _connection; + public DrugManuNoDao(AppDataConnection connection) + { + _connection = connection; + } + public int AddDrugManuNo(DrugManuNo drugManuNo) + { + if(drugManuNo!=null&& drugManuNo.EffDate!=null) + { + drugManuNo.EffDate= drugManuNo.EffDate.ToString().Length>10 ?new DateTime(drugManuNo.EffDate.Value.Year, drugManuNo.EffDate.Value.Month, drugManuNo.EffDate.Value.Day) : drugManuNo.EffDate; + } + return _connection.InsertWithInt32Identity(drugManuNo); + } + + public bool DeleteDrugManuNo(string id) + { + if (!string.IsNullOrEmpty(id)) + { + int manuNo= _connection.DrugManuNo.Where(dm => dm.Id == id).Count(); + if (manuNo > 0) + { + return _connection.DrugManuNo.Where(dm => dm.Id == id).Delete() > 0; + } + else return true; + } + else + { + return true; + } + } + + public bool UpdateDrugManuNo(DrugManuNo drugManuNo) + { + var statement = _connection.DrugManuNo + .Where(dm => dm.Id == drugManuNo.Id) + .Set(dm => dm.ManuNo, drugManuNo.ManuNo) + .Set(dm => dm.EffDate, drugManuNo.EffDate); + return statement.Update() > 0; + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/HkcChangeShiftsDao.cs b/MasaBlazorApp3/DataAccess/Impl/HkcChangeShiftsDao.cs new file mode 100644 index 0000000..fa91262 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/HkcChangeShiftsDao.cs @@ -0,0 +1,51 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class HkcChangeShiftsDao: IHkcChangeShiftsDao + { + private readonly AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(HkcChangeShifts)); + private readonly PortUtil _portUtil; + public HkcChangeShiftsDao(AppDataConnection connection, IOptions setting, PortUtil portUtil) + { + _connection = connection; + _setting = setting.Value; + _portUtil = portUtil; + } + public async Task> GetChangeShiftRecordAsync(DateTime start, DateTime end, int? take, int? skip) + { + var query = _connection.HkcChangeShifts.AsQueryable().Where(it => it.MachineId.Equals(_setting.machineId)); + if (start != null && start != DateTime.MinValue) + { + query = query.Where(mr => mr.optDate > start); + } + if (end != null && end != DateTime.MinValue) + { + query = query.Where(mr => mr.optDate < end); + } + int pagedData = await query.CountAsync(); + List Records = await query + .OrderByDescending(mr => mr.optDate) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + return new PageData() { Desserts = Records, TotalDesserts = pagedData }; + + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/InOutInvoiceDao.cs b/MasaBlazorApp3/DataAccess/Impl/InOutInvoiceDao.cs new file mode 100644 index 0000000..03066a3 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/InOutInvoiceDao.cs @@ -0,0 +1,605 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class InOutInvoiceDao : IInOutInvoiceDao + { + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(InOutInvoiceDao)); + private GlobalStateService _globalStateService; + private readonly PortUtil _portUtil; + + public InOutInvoiceDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService, PortUtil portUtil) + { + _connection = connection; + _setting = setting.Value; + _globalStateService = globalStateService; + _portUtil = portUtil; + } + public async Task> GetAllInvoiceByType(string invoiceNo, DateTime invoiceDate, int? take, int? skip, int type = 1) + { + //var query2 = from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.machineId) + // group cl by cl.DrugId into temp + // select new { temp.Key }; + //var query3 = from ioi in _connection.InOutInvoice + // from od in query2.InnerJoin(od => od.Key == ioi.DrugId) + // group ioi by ioi.InvoiceNo into temp + // select new InOutInvoice{ + // InvoiceNo= temp.First().InvoiceNo, + // InPharmacyId = temp.First().InPharmacyId, + // OutPharmacyId = temp.First().OutPharmacyId, + // InvoiceDate = temp.First().InvoiceDate, + // CreateTime = temp.First().CreateTime, + // Type = temp.First().Type, + // CancelFlag = temp.First().CancelFlag, + // Status = temp.First().Status, + // }; + + + + var query = _connection.FromSql($@" + SELECT ioi.invoice_no,ioi.in_pharmacy_id, ioi.out_pharmacy_id, ioi.invoice_date, ioi.create_time, ioi.type, ioi.cancel_flag, ioi.status FROM in_out_invoice ioi + INNER JOIN (SELECT drug_id FROM channel_stock WHERE machine_id = {_setting.machineId} GROUP BY drug_id) c ON c.drug_id = ioi.drug_id + GROUP BY ioi.invoice_no"); + + if (!String.IsNullOrEmpty(invoiceNo)) + { + query = query.Where(ioi => ioi.InvoiceNo.Contains(invoiceNo)); + //query3 = query3.Where(ioi => ioi.InvoiceNo.Contains(invoiceNo)); + } + if (invoiceDate != DateTime.MinValue) + { + query = query.Where(ioi => Convert.ToDateTime(ioi.InvoiceDate).Date.Equals(invoiceDate.Date)); + //query3 = query3.Where(ioi => ioi.InvoiceNo.Contains(invoiceNo)); + } + + if (!String.IsNullOrEmpty(_setting.inPharmacyId)) + { + if (type == 1) + { + query = query.Where(ioi => ioi.InPharmacyId.Equals(_setting.inPharmacyId)); + //query = query.Where(ioi => ioi.OutPharmacyId.Equals(_setting.inPharmacyId)); + //query3 = query3.Where(ioi => ioi.OutPharmacyId.Equals(_setting.storage)); + } + // 调拨出库 + else if (type == 2) + { + query = query.Where(ioi => ioi.InPharmacyId.Equals(_setting.inPharmacyId)); + //query3 = query3.Where(ioi => ioi.OutPharmacyId.Equals(_setting.storage)); + } + + } + // 调拨入库 + if (type == 1) + { + query = query.Where(ioi => (ioi.Type == 2 && ioi.Status == 0)); + //query3 = query3.Where(ioi => (ioi.Type == 0 && ioi.Status == 2) || (ioi.Type == 1 && ioi.Status == 0)); + } + // 调拨出库 + else if (type == 2) + { + query = query.Where(ioi => new int[] { 0, 2 }.Contains(ioi.Type) && ioi.Status == 0); + //query3 = query3.Where(ioi => new int[] { 0, 2 }.Contains(ioi.Type) && ioi.Status == 0); + } + query = query.Where(ioi => ioi.CancelFlag == 0); + query = query.Select(ioi => new InOutInvoice() + { + InPharmacyId = ioi.InPharmacyId, + OutPharmacyId = ioi.OutPharmacyId, + InvoiceDate = ioi.InvoiceDate, + InvoiceNo = ioi.InvoiceNo, + CreateTime = ioi.CreateTime, + Type = ioi.Type, + Status = ioi.Status, + CancelFlag = ioi.CancelFlag, + }); + + //query3 = query3.Where(ioi => ioi.CancelFlag == 0); + List list = await query + .OrderByDescending(ioi => ioi.CreateTime) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + int pagedData = await query.CountAsync(); + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + + } + public async Task GetDrugManuNo(string drugId, string manuNo) + { + var query = _connection.DrugManuNo.AsQueryable(); + + return await query.Where(m => m.DrugId.Equals(drugId)) + .Where(m => m.ManuNo.Equals(manuNo)) + .FirstAsync(); + } + + public async Task> GetChannelStockByDrugId(string DrugId, string manuNo, int quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable(); + + + query = query.Where(cs => cs.MachineId.Equals(_setting.machineId)).Where(cs => cs.DrawerType == 1).Where(cs => cs.DrugId.Equals(DrugId)); + + + if (quantity > 0) + { + query = query.Where(cs => cs.Quantity > 0); + if (!String.IsNullOrEmpty(manuNo) && manuNo != "X") + { + query = query.Where(cs => cs.ManuNo.Equals(manuNo)); + } + } + else + { + if (!String.IsNullOrEmpty(manuNo) && manuNo != "X") + { + query = query.Where(cs => cs.ManuNo.Equals(manuNo) || String.IsNullOrEmpty(cs.ManuNo) || cs.Quantity == 0); + } + } + + return await query.LoadWith(cl => cl.drugManuNo) + .OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> getInvoiceByInvoiceNo(string invoiceNo) + { + var query = _connection.InOutInvoice.AsQueryable(); + + query = query.InnerJoin( + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.machineId)).GroupBy(cs => cs.DrugId).Select(cs => cs.Key), + (ioi, key) => key == ioi.DrugId, + (ioi, key) => ioi) + .Where(ioi => ioi.InvoiceNo.Equals(invoiceNo)) + .OrderBy(ioi => ioi.DrugId); + return await query.ToListAsync(); + } + + public async Task getDrugInfoById(string DrugId) + { + return await _connection.DrugInfo.Where(di => di.DrugId == DrugId).LoadWith(di => di.Manus).FirstOrDefaultAsync(); + } + + + public async Task> getTakeInfoByInvoiceNo(string invoiceNo) + { + List tempData = new(); + var flag = true; + List details = await this.getInvoiceByInvoiceNo(invoiceNo); + for (var i = 0; i < details.Count; i++) + { + //List> tempData = new(); + InOutInvoice detail = details[i]; + + DrugInfo Drug = await this.getDrugInfoById(detail.DrugId); + // 当前detail取药数量 + var Quantity = detail.quantity; + List stockList = await this.GetChannelStockByDrugId(detail.DrugId, detail.DrugManuNo, Quantity); + + // 当前药品的库存总量 + var total = stockList.Sum(cs => cs.Quantity); + + if (flag) + { + // 盘点库存是否足够 + if (total >= Quantity) + { + + for (var j = 0; Quantity > 0; j++) + { + ChannelStock stock = stockList[j]; + if (Quantity > stock.Quantity) + { + // 取药数量大于库存 + stock.TakeQuantity = stock.Quantity; + Quantity -= stock.Quantity; + } + else + { + //取药数量小于库存 + stock.TakeQuantity = Quantity; + Quantity = 0; + } + } + } + else + { + // 库存不足 + flag = false; + } + } + tempData.Add(new InvoiceVo() + { + Drug = Drug, + Invoice = detail, + StockQuantity = total, + Quantity = detail.quantity, + ChannelStocks = stockList, + }); + } + return tempData; + } + + public async Task> getAddInfoByInvoiceNo(string invoiceNo) + { + List tempData = new(); + List details = await this.getInvoiceByInvoiceNo(invoiceNo); + for (var i = 0; i < details.Count; i++) + { + //List> tempData = new(); + InOutInvoice detail = details[i]; + List stockList = await this.GetChannelStockByDrugId(detail.DrugId, detail.DrugManuNo); + + DrugInfo Drug = await this.getDrugInfoById(detail.DrugId); + if(Drug!=null&&stockList!=null&&stockList.Count>0) + { + stockList.ForEach(sl => sl.Drug = Drug); + } + + // 当前药品的库存总量 + var total = stockList.Aggregate(0, (current, next) => current + next.Quantity); + // 当前detail加药数量 + var Quantity = detail.quantity; + + stockList.First().AddQuantity = Quantity; + + tempData.Add(new InvoiceVo() + { + Drug = Drug, + Invoice = detail, + StockQuantity = total, + Quantity = Quantity, + ChannelStocks = stockList, + }); + + } + return tempData; + } + + public async Task InvoiceOutFinish(List datas) + { + try + { + _connection.BeginTransaction(); + var flag = true; + // 更新处方状态 + int r1 = _connection.InOutInvoice.Where(oi => oi.InvoiceNo == datas.First().Invoice.InvoiceNo) + .Set(oi => oi.Status, 2) + .Update(); + if (!(r1 > 0)) + { + flag = false; + logger.Error("调拨取药完成更新状态失败"); + _connection.RollbackTransaction(); + return flag; + } + for (var i = 0; i < datas.Count; i++) + { + var invoiceVo = datas[i]; + + List stocks = invoiceVo.ChannelStocks.Where(cs => cs.TakeQuantity > 0).ToList(); + + for (var j = 0; j < stocks.Count; j++) + { + var ChannelStock = stocks[j]; + if (!DateTime.TryParse(ChannelStock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (ChannelStock.EffDate != null) + { + string[] idate = ChannelStock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Trim())) + { + switch (iS.Trim().Length) + { + case 4: + ChannelStock.EffDate = iS.Trim(); + break; + case 2: + ChannelStock.EffDate += "-" + iS.Trim(); + break; + case 1: + ChannelStock.EffDate += "-0" + iS.Trim(); + break; + } + } + } + + + } + } + else + { + ChannelStock.EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + // 出库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = ChannelStock.DrawerNo, + ColNo = ChannelStock.ColNo, + DrugId = ChannelStock.DrugId, + ManuNo = ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(ChannelStock.EffDate) ? DateTime.ParseExact(ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + Quantity = ChannelStock.TakeQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = invoiceVo.Invoice.InvoiceNo, + }); + // 更新库存 + int r = _connection.ChannelStock.Where(cs => cs.Id == ChannelStock.Id) + .Set(cs => cs.Quantity, ChannelStock.Quantity - ChannelStock.TakeQuantity) + .Update(); + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(ChannelStock.DrugId)) + .ToListAsync(); + + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = ChannelStock.DrugId, + ManuNo = ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(ChannelStock.EffDate) ? DateTime.ParseExact(ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + OutQuantity = ChannelStock.TakeQuantity, + AddQuantity = 0, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == ChannelStock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = invoiceVo.Invoice.InvoiceNo + }); + if (mid > 0 && r > 0 && acid > 0) + { + //根据抽屉类型判断是否需要写标签 + if (ChannelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(ChannelStock.Quantity - ChannelStock.TakeQuantity, ChannelStock.DrawerNo, ChannelStock.ColNo); + } + } + else + { + flag = false; + break; + } + } + + if (!flag) + { + break; + } + + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("调拨取药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + public async Task InvoiceAddFinish(List datas) + { + + try + { + _connection.BeginTransaction(); + var flag = true; + // 更新调拨单状态 + int r1 = _connection.InOutInvoice.Where(oi => oi.InvoiceNo == datas.First().Invoice.InvoiceNo) + .Set(oi => oi.Status, 4) + .Update(); + if (!(r1 > 0)) + { + flag = false; + logger.Error("调拨加药完成更新状态失败"); + _connection.RollbackTransaction(); + return flag; + } + for (var i = 0; i < datas.Count; i++) + { + var invoiceVo = datas[i]; + + List stocks = invoiceVo.ChannelStocks.Where(cs => cs.AddQuantity > 0).ToList(); + + for (var j = 0; j < stocks.Count; j++) + { + var ChannelStock = stocks[j]; + + // 更新库存 + var q = _connection.ChannelStock.Where(cs => cs.Id == ChannelStock.Id) + .Set(cs => cs.Quantity, ChannelStock.Quantity + ChannelStock.AddQuantity); + if (String.IsNullOrEmpty(ChannelStock.ManuNo) || (ChannelStock.Quantity == 0 && !ChannelStock.ManuNo.Equals(invoiceVo.Invoice.DrugManuNo))) + { + DrugManuNo drugManuNo = await GetDrugManuNo(ChannelStock.DrugId, ChannelStock.drugManuNo.ManuNo); + + ChannelStock.Dmnguid = drugManuNo.Id; + ChannelStock.ManuNo = drugManuNo.ManuNo; + ChannelStock.EffDate = drugManuNo.EffDate?.ToString("yyyy-MM-dd"); + + q = q.Set(cs => cs.Dmnguid, ChannelStock.Dmnguid) + .Set(cs => cs.ManuNo, ChannelStock.ManuNo) + .Set(cs => cs.EffDate, ChannelStock.EffDate); + } + int r = q.Update(); + if (!DateTime.TryParse(ChannelStock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (ChannelStock.EffDate != null) + { + string[] idate = ChannelStock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Trim())) + { + switch (iS.Trim().Length) + { + case 4: + ChannelStock.EffDate = iS.Trim(); + break; + case 2: + ChannelStock.EffDate += "-" + iS.Trim(); + break; + case 1: + ChannelStock.EffDate += "-0" + iS.Trim(); + break; + } + } + } + + + } + } + else + { + ChannelStock.EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + // 入库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = ChannelStock.DrawerNo, + ColNo = ChannelStock.ColNo, + DrugId = ChannelStock.DrugId, + ManuNo = ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(ChannelStock.EffDate) ? DateTime.ParseExact(ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 1, + Quantity = ChannelStock.AddQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = invoiceVo.Invoice.InvoiceNo, + }); + + //更新回收箱库存,入库后回收箱的空瓶库存减少 + //List returnChannelStockList = _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 2 && cs.DrugId == ChannelStock.DrugId && cs.Quantity > 0).OrderBy(cs => cs.Quantity).ToList(); + //if (returnChannelStockList != null && returnChannelStockList.Count > 0 && returnChannelStockList.Sum(rcs => rcs.Quantity) <= ChannelStock.AddQuantity) + //{ + // //空瓶数小于等于入库数量,直接清空所有回收箱中药品空瓶数 + // returnChannelStockList.ForEach(rcs => rcs.Quantity = 0); + // _connection.Update(returnChannelStockList); + + //} + //else if(returnChannelStockList != null && returnChannelStockList.Count > 0) + //{ + // for (int rt = 0; rt < ChannelStock.AddQuantity; rt++) + // { + // int AddQuan = ChannelStock.AddQuantity; + // int StockQuan = returnChannelStockList[rt].Quantity; + // returnChannelStockList[rt].Quantity = (StockQuan - AddQuan) <= 0 ? 0 : (StockQuan - AddQuan); + // ChannelStock.AddQuantity = AddQuan - StockQuan; + + // } + + // _connection.Update(returnChannelStockList); + //} + + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .Where(cs => cs.MachineId.Equals(_setting.machineId)) + .Where(cs => cs.DrawerType == 1) + .Where(cs => cs.DrugId.Equals(ChannelStock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = ChannelStock.DrugId, + ManuNo = ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(ChannelStock.EffDate) ? DateTime.ParseExact(ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 1, + OutQuantity = 0, + AddQuantity = ChannelStock.AddQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == ChannelStock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = invoiceVo.Invoice.InvoiceNo + }); + if (mid > 0 && r > 0 && acid > 0) + { + //根据抽屉类型判断是否需要写标签 + if (ChannelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(ChannelStock.Quantity - ChannelStock.TakeQuantity, ChannelStock.DrawerNo, ChannelStock.ColNo); + } + } + else + { + flag = false; + break; + } + } + if (!flag) + { + break; + } + + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("调拨加药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/MachineRecordDao.cs b/MasaBlazorApp3/DataAccess/Impl/MachineRecordDao.cs new file mode 100644 index 0000000..19844b6 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/MachineRecordDao.cs @@ -0,0 +1,489 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using Mysqlx.Crud; +using System.Collections.Generic; +using static LinqToDB.Common.Configuration; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class MachineRecordDao : IMachineRecordDao + { + + private readonly AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(MachineRecordDao)); + private readonly PortUtil _portUtil; + + private GlobalStateService _globalStateService; + //public UserDao(MyContext context) + //{ + // Context = context; + //} + public MachineRecordDao(AppDataConnection connection, IOptions setting, PortUtil portUtil, GlobalStateService globalStateService) + { + _connection = connection; + _setting = setting.Value; + _portUtil = portUtil; + _globalStateService = globalStateService; + } + + public async Task> GetChannelStockByDrugId(string DrugId, String ManuNo) + { + var query = _connection.ChannelStock.AsQueryable(); + + + query = query.Where(cs => cs.MachineId.Equals(_setting.machineId)).Where(cs => cs.DrawerType == 1) + .Where(cs => cs.Quantity > 0) + .Where(cs => cs.DrugId.Equals(DrugId)) + .Where(cs => cs.ManuNo.Equals(ManuNo)); + + + return await query.OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + //还药时有库位即可,不需要库存大于0的条件 + public async Task> GetChannelStockByDrugIdForReturn(string DrugId, String ManuNo) + { + var query = _connection.ChannelStock.AsQueryable(); + + + query = query.Where(cs => cs.MachineId.Equals(_setting.machineId)).Where(cs => cs.DrawerType == 1) + //.Where(cs => cs.Quantity > 0) + .Where(cs => cs.DrugId.Equals(DrugId)) + .Where(cs => cs.ManuNo.Equals(ManuNo)); + + + return await query.OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> GetCanReturnRecords(DateTime start, DateTime end, int operatorId, string drugId, int? take, int? skip) + { + var query = _connection.MachineRecord.AsQueryable().Where(it => it.MachineId.Equals(_setting.machineId)&&it.InvoiceId.StartsWith("DRAWER_")); + if (start != null && start != DateTime.MinValue) + { + query = query.Where(mr => mr.OperationTime > start); + } + if (end != null && end != DateTime.MinValue) + { + query = query.Where(mr => mr.OperationTime < end.AddDays(1)); + } + if (operatorId != 0) + { + query = query.Where(mr => mr.Operator == operatorId); + } + query = query.Where(mr => mr.Type == 2); + query = query.Where(mr => mr.Status < 2); + if (!String.IsNullOrEmpty(drugId)) + { + query = query.Where(mr => mr.DrugId == drugId); + } + int pagedData = await query.CountAsync(); + List MachineRecords = await query.LoadWith(mr => mr.Drug) + .LoadWith(mr => mr.OperatorUser) + .OrderByDescending(mr => mr.OperationTime) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + return new PageData() { Desserts = MachineRecords, TotalDesserts = pagedData }; + } + + public async Task> GetMachineRecordAsync(DateTime start, DateTime end, int operatorId, string drugId, int type, int? take, int? skip) + { + var query = from mr in _connection.MachineRecord select mr ; + + if (start != null && start != DateTime.MinValue) + { + query = query.Where(mr => mr.OperationTime > start); + } + if (end != null && end != DateTime.MinValue) + { + query = query.Where(mr => mr.OperationTime < end.AddDays(1)); + } + if (operatorId != 0) + { + query = query.Where(mr => mr.Operator == operatorId); + } + if (type != 0) + { + query = query.Where(mr => mr.Type == type); + } + if (!String.IsNullOrEmpty(drugId)) + { + query = query.Where(mr => mr.DrugId == drugId); + } + query = query.OrderByDescending(mr => mr.OperationTime); + query =from mr in query + from dr in _connection.DrugInfo.Where(d => d.DrugId == mr.DrugId) + from us in _connection.User.Where(u => u.Id == mr.Operator) + select MachineRecord.Build(mr, dr, us); + + int pagedData = await query.CountAsync(); + List MachineRecords = await query + //.OrderByDescending(mr => mr.OperationTime) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + //var query = _connection.MachineRecord.AsQueryable().Where(it => it.MachineId.Equals(_setting.machineId)); + //if (start != null && start != DateTime.MinValue) + //{ + // query = query.Where(mr => mr.OperationTime > start); + //} + //if (end != null && end != DateTime.MinValue) + //{ + // query = query.Where(mr => mr.OperationTime < end.AddDays(1)); + //} + //if (operatorId != 0) + //{ + // query = query.Where(mr => mr.Operator == operatorId); + //} + //if (type != 0) + //{ + // query = query.Where(mr => mr.Type == type); + //} + //if (!String.IsNullOrEmpty(drugId)) + //{ + // query = query.Where(mr => mr.DrugId == drugId); + //} + //int pagedData = await query.CountAsync(); + //List MachineRecords = await query.LoadWith(mr => mr.Drug) + // .LoadWith(mr => mr.OperatorUser) + // .OrderByDescending(mr => mr.OperationTime) + // .Skip((int)skip) + // .Take((int)take) + // .ToListAsync(); + + return new PageData() { Desserts = MachineRecords, TotalDesserts = pagedData }; + + } + + + public int InsertMachineRecord(MachineRecord record) + { + record.MachineId = _setting.machineId; + return _connection.InsertWithInt32Identity(record); + } + public async Task>>> getReturnDrugInfoByRecords(List records) + { + List>> list = new(); + + for (int i = 0; i < records.Count; i++) + { + var record = records[i]; + //var index = list.FindIndex(it => it.Drug.DrugId == record.DrugId && it.data.Count > 0 && it.data.First().ManuNo == record.ManuNo); + var index = list.FindIndex(it => it.Drug.DrugId == record.DrugId && it.data.First().ManuNo == record.ManuNo); + if (index > -1) + { + list[index].Quantity += record.CurrentReturnQuantity; + list[index].data.Add(record); + if (list[index].ChannelStocks.Count > 0) + { + list[index].ChannelStocks.First().ReturnQuantity += record.CurrentReturnQuantity; + } + } + else + { + //List stockList = await this.GetChannelStockByDrugId(record.DrugId, record.ManuNo); + List stockList = await this.GetChannelStockByDrugIdForReturn(record.DrugId, record.ManuNo); + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + if (stockList.Count > 0) + { + stockList.First().ReturnQuantity = record.CurrentReturnQuantity; + } + list.Add(new OperationVo>() + { + Drug = record.Drug, + ChannelStocks = stockList, + data = new List { record }, + Quantity = record.CurrentReturnQuantity, + StockQuantity = total, + }); + } + + + } + return list; + } + + public async Task ReturnDrugFinish(List>> datas) + { + //throw new NotImplementedException(); + //还药完成 + try + { + _connection.BeginTransaction(); + if (datas.Count > 0) + { + datas = datas.Select(it => + { + it.ChannelStocks = it.ChannelStocks.Where(cs => cs.ReturnQuantity > 0).ToList(); + return it; + }).ToList(); + if (datas.Count > 0) + { + foreach (var data in datas) + { + int sumQuantity = data.data.Sum(mr => mr.CurrentReturnQuantity); + //更新 库存 + foreach (ChannelStock record in data.ChannelStocks) + { + record.Quantity = record.Quantity + record.ReturnQuantity; + record.Id = record.Id; + _connection.Update(record); + + // 保存数据 还药记录 + int acid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = record.MachineId, + DrawerNo = record.DrawerNo, + ColNo = record.ColNo, + DrugId = record.DrugId, + ManuNo = record.ManuNo, + EffDate = !String.IsNullOrEmpty(record.EffDate) ? DateTime.ParseExact(record.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = data.data.First().Operator, + OperationTime = DateTime.Now, + Quantity = record.ReturnQuantity, + Type = 31, + InvoiceId = data.data.First().InvoiceId, + GetId = data.data.First().GetId + }); + //称重计数或称重+智能显示+管控药盒 类型需要 发26指令 + if (record.BoardType == 5 || record.BoardType == 6) + { + //计数数量设置,发送称重26指令 + _portUtil.SetNumCount(record.DrawerNo, record.ColNo, record.ReturnQuantity); + Thread.Sleep(80); + } + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(record.DrugId)) + .ToListAsync(); + //账册添加入库记录 + int accountID = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = record.DrugId, + ManuNo = record.ManuNo, + EffDate = !String.IsNullOrEmpty(record.EffDate) ? DateTime.ParseExact(record.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 31, + AddQuantity = record.ReturnQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == record.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = data.data.First().InvoiceId, + }); + + } + // 更新 取药记录 设置还药数量、状态 + foreach (MachineRecord record in data.data) + { + record.ReturnQuantity1 = record.ReturnQuantity1 + record.CurrentReturnQuantity; + record.Id = record.Id; + record.Status = (record.Quantity - (record.ReturnQuantity1 + record.ReturnQuantity2 + sumQuantity)) <= 0 ? 2 : 1; + _connection.Update(record); + + //更新药盒库存(原库存减已还药数) + if(record.BoxDrawer>0) + { + //查询药盒库位中对应的药品信息 + ChannelStock csBox = _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrugId == record.DrugId && cs.ManuNo == record.ManuNo && cs.DrawerNo == record.BoxDrawer && cs.ColNo == record.BoxColNo).FirstOrDefault(); + if(csBox!=null) + { + csBox.Quantity = csBox.Quantity - sumQuantity; + int iUpdateBox= _connection.Update(csBox); + if(iUpdateBox<=0) + { + logger.Info("更新药品库存失败"); + } + } + else + { + logger.Info($"未查询到药品{record.DrugId}批次{record.ManuNo}在库位{record.BoxDrawer}-{record.BoxColNo}中信息"); + } + } + } + + } + _connection.CommitTransaction(); + } + } + else + { + _connection.RollbackTransaction(); + return false; + } + return true; + } + catch (Exception ex) + { + logger.Error("还药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + + #region 还空瓶 + public async Task> GetReturnEmpty() + { + List channelStocks = new(); + var query = _connection.ChannelStock.AsQueryable().Where(it => it.MachineId == _setting.machineId && it.DrawerType == 2); + channelStocks= await query.LoadWith(cs => cs.Drug).ToListAsync(); + + //获取可归还数量 + return channelStocks; + //if (start != null && start != DateTime.MinValue) + //{ + // query = query.Where(mr => mr.OperationTime > start); + //} + //if (end != null && end != DateTime.MinValue) + //{ + // query = query.Where(mr => mr.OperationTime < end); + //} + //if (operatorId != 0) + //{ + // query = query.Where(mr => mr.Operator == operatorId); + //} + //query = query.Where(mr => mr.Type == 2); + //query = query.Where(mr => mr.Status < 2); + //if (!String.IsNullOrEmpty(drugId)) + //{ + // query = query.Where(mr => mr.DrugId == drugId); + //} + //int pagedData = await query.CountAsync(); + //List MachineRecords = await query.LoadWith(mr => mr.Drug) + // .LoadWith(mr => mr.OperatorUser) + // .OrderByDescending(mr => mr.OperationTime) + // .Skip((int)skip) + // .Take((int)take) + // .ToListAsync(); + + //return new PageData() { Desserts = MachineRecords, TotalDesserts = pagedData }; + } + public async Task> getReturnEmptyInfoByRecords(ChannelStock records) + { + List machineRecords = new(); + int pagedData = 0; + if (records != null && !string.IsNullOrEmpty(records.DrugId)) + { + var query = _connection.MachineRecord.Where(it => it.DrugId == records.DrugId && it.MachineId == _setting.machineId && it.Type == 2 && it.Status != 2).AsQueryable(); + machineRecords = await query.LoadWith(cs => cs.OperatorUser).ToListAsync(); + + pagedData = await query.CountAsync(); + } + return new PageData() { Desserts = machineRecords, TotalDesserts = pagedData }; + + } + public async Task ReturnEmptyFinish(List datas, ChannelStock channelStock) + { + try + { + _connection.BeginTransaction(); + // 更新数据 库存信息 + channelStock.Quantity = channelStock.Quantity+ datas.Sum(it => it.CurrentReturnQuantity); + int iStock = _connection.Update(channelStock); + for (int i = 0; i < datas.Count; i++) + { + MachineRecord _MachineRecord = datas[i]; + _MachineRecord.ReturnQuantity2 = _MachineRecord.ReturnQuantity2+ _MachineRecord.CurrentReturnQuantity; + _MachineRecord.Status = _MachineRecord.ReturnQuantity2 + _MachineRecord.ReturnQuantity1 >= _MachineRecord.Quantity ? 2 : 1; + // 更新数据 取药记录 设置还药数量、状态 + _connection.Update(_MachineRecord); + // 保存数据 还药空瓶记录 + int iMachineRecord = _connection.InsertWithInt32Identity(new MachineRecord() { + MachineId= channelStock.MachineId, + DrawerNo = channelStock.DrawerNo, + ColNo = channelStock.ColNo, + DrugId = channelStock.DrugId, + ManuNo = channelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(channelStock.EffDate) ? DateTime.ParseExact(channelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = _MachineRecord.Operator, + OperationTime = DateTime.Now, + Quantity = _MachineRecord.CurrentReturnQuantity, + Type = 32, + InvoiceId = _MachineRecord.InvoiceId, + GetId = _MachineRecord.GetId + }); + + ////称重计数或称重+智能显示+管控药盒 类型需要 发26指令 + //if (channelStock.BoardType == 5 || channelStock.BoardType == 6) + //{ + // //计数数量设置,发送称重26指令 + // _portUtil.SetNumCount(channelStock.DrawerNo, channelStock.ColNo, channelStock.ReturnQuantity); + // Thread.Sleep(80); + //} + + + if (channelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(channelStock.Quantity + datas.Sum(it => it.CurrentReturnQuantity), channelStock.DrawerNo, channelStock.ColNo); + } + } + // 更新屏显库存 + if (channelStock.BoardType == 5 || channelStock.BoardType == 35) + { + _portUtil.WriteQuantity(channelStock.DrawerNo, channelStock.ColNo, channelStock.Quantity); + } + _connection.CommitTransaction(); + return true; + } + catch (Exception ex) + { + logger.Error("还空瓶完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + public async Task> GetReturnEmptyWithCanReturnQuantiy() + { + List channelStocks = new(); + var queryStock = _connection.ChannelStock.Where(cs => cs.DrawerType == 2 && cs.MachineId == _setting.machineId); + var queryMachineRecord = _connection.MachineRecord.Where(dm => dm.Type == 2 && dm.Status != 2); + var query = from cs in queryStock + join other in queryMachineRecord on cs.DrugId equals other.DrugId + where cs.MachineId==other.MachineId + group other by cs.DrugId into g + select new + { + ChannelStockId = g.Key, + SumValue = g.Sum(x => x.Quantity-x.ReturnQuantity1-x.ReturnQuantity2) + }; + + var results = await query.ToListAsync(); + channelStocks= await queryStock.LoadWith(cs => cs.Drug).ToListAsync(); + foreach (var itemStock in channelStocks) + { + foreach (var itemResult in results) + { + if(itemStock.DrugId==itemResult.ChannelStockId) + { + itemStock.CanReturnQuantity = itemResult.SumValue; + } + } + } + return channelStocks; + } + #endregion + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/OrderInfoDao.cs b/MasaBlazorApp3/DataAccess/Impl/OrderInfoDao.cs new file mode 100644 index 0000000..b70f9ae --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/OrderInfoDao.cs @@ -0,0 +1,1622 @@ +using Google.Protobuf; +using LinqToDB; +using LinqToDB.SqlQuery; +using log4net; +using log4net.Util; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using MasaBlazorApp3.Port; +using MasaBlazorApp3.Util; +using Microsoft.Extensions.Options; +using Mysqlx.Crud; +using Radzen; +using Radzen.Blazor.Rendering; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection.PortableExecutable; +using System.Security.Permissions; +using System.Text; +using System.Threading.Tasks; +using static LinqToDB.Common.Configuration; +using static LinqToDB.Reflection.Methods.LinqToDB.Insert; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class OrderInfoDao : IOrderInfoDao + { + + private readonly SettingConfig _setting; + private AppDataConnection _connection; + private GlobalStateService _globalStateService; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderInfoDao)); + private readonly PortUtil _portUtil; + NotificationService _message; + public OrderInfoDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService, PortUtil portUtil, NotificationService message) + { + _connection = connection; + _setting = setting.Value; + _globalStateService = globalStateService; + _portUtil = portUtil; + _message = message; + } + + public async Task> GetAllOrderInfo(string OrderrNo, DateTime OrderDate, int? take, int? skip) + { + + //var query = _connection.OrderInfo.AsQueryable(); + + //query.InnerJoin((oi, od) => oi.OrderNo == od.OrderNo); + + var query2 = from od in _connection.OrderDetail + from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.machineId).InnerJoin(c => c.DrugId == od.DrugId) + group od by od.OrderNo into temp + select new { temp.Key }; + var query = from oi in _connection.OrderInfo + from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + select oi; + + if (!String.IsNullOrEmpty(OrderrNo)) + { + query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + } + if (OrderDate != null && OrderDate != DateTime.MinValue) + { + query = query.Where(oi => oi.ChargeDate.Date.Equals(OrderDate.Date)); + } + + query = query.Where(oi => oi.Status == 0); + query = query.Where(oi => oi.HisDispFlag == 0); + query = query.Where(oi => oi.CancelFlag == 0); + + + int pagedData = await query.CountAsync(); + + List list = await query + //.LoadWith(oi => oi.Detail) + //.LoadWith(oi => oi.Detail.Drug) + .OrderBy((oi) => oi.RecvDate) + .ThenBy((oi => oi.OrderNo)) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + } + public async Task> GetAllOrderInfoForImport(string name, string OrderrNo, DateTime OrderDate, BoxModel boxModel, int? take, int? skip) + { + + //var query = _connection.OrderInfo.AsQueryable(); + + //query.InnerJoin((oi, od) => oi.OrderNo == od.OrderNo); + + var query2 = from od in _connection.OrderDetail + from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.boxMachineId && c.DrawerNo != boxModel.BoxName && c.ColNo != boxModel.BoxNo).InnerJoin(c => c.DrugId == od.DrugId) + group od by od.OrderNo into temp + select new { temp.Key }; + var query = from oi in _connection.OrderInfo + from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + select oi; + if (!string.IsNullOrEmpty(name)) + { + query = query.Where(oi => oi.PatientName.Equals(name)); + } + if (!String.IsNullOrEmpty(OrderrNo)) + { + query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + } + if (OrderDate != null && OrderDate != DateTime.MinValue) + { + query = query.Where(oi => oi.ChargeDate.Date.Equals(OrderDate.Date)); + } + + query = query.Where(oi => oi.Status == 0); + query = query.Where(oi => oi.HisDispFlag == 0); + query = query.Where(oi => oi.CancelFlag == 0); + + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(oi => oi.DetailInfo) + //.LoadWith(oi => oi.DetailInfo.Drug) + .OrderBy((oi) => oi.RecvDate) + .ThenBy((oi => oi.OrderNo)) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + for (int i = 0; i < list.Count; i++) + { + if (list[i].DetailInfo != null && list[i].DetailInfo.Id > 0) + { + list[i].DetailInfo.Drug = await _connection.DrugInfo.AsQueryable().Where(d => d.DrugId == list[i].DetailInfo.DrugId).FirstOrDefaultAsync(); + list[i].SelectedOrderList = new List(); + list[i].SelectedOrderList.Add(list[i]); + } + } + + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + } + + public async Task> getDetailByOrderNo(string OrderrNo) + { + var query2 = from cl in _connection.ChannelStock + where cl.MachineId == _setting.machineId + group cl by cl.DrugId into temp + select new { temp.Key }; + ; + + + var query = from od in _connection.OrderDetail.Where(od => od.OrderNo == OrderrNo) + from cl in query2.InnerJoin(c => c.Key == od.DrugId) + orderby od.DrugId + select od; + + query = query.LoadWith(od => od.Drug); + + return await query.ToListAsync(); + } + + public async Task> GetChannelStockByDrugId(string DrugId, String ManuNo, int quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable(); + + + query = query.Where(cs => cs.MachineId.Equals(_setting.machineId)).Where(cs => cs.DrawerType == 1) + .Where(cs => cs.Quantity > 0) + .Where(cs => cs.DrugId.Equals(DrugId)); + + if (quantity > 0) + { + if (!String.IsNullOrEmpty(ManuNo)) + { + query = query.Where(cs => cs.ManuNo.Equals(ManuNo)); + } + } + else + { + if (!String.IsNullOrEmpty(ManuNo)) + { + query = query.Where(cs => cs.ManuNo.Equals(ManuNo) || cs.Quantity == 0); + } + } + + + return await query.OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + public async Task> getTakeInfoByOrderNo(string OrderrNo) + { + List tempData = new(); + List tempData2 = new(); + List details = await this.getDetailByOrderNo(OrderrNo); + var flag = true; + for (var i = 0; i < details.Count; i++) + { + //List> tempData = new(); + OrderDetail detail = details[i]; + // 当前detail取药数量 + var Quantity = detail.Quantity; + List stockList = await this.GetChannelStockByDrugId(detail.DrugId, detail.SetManuNo, Quantity); + + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + + tempData2.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + StockQuantity = total, + Quantity = Quantity + }); + + if (flag) + { + // 盘点库存是否足够 + if (total > Quantity) + { + + for (var j = 0; Quantity > 0; j++) + { + ChannelStock stock = stockList[j]; + if (Quantity > stock.Quantity) + { + // 取药数量大于库存 + tempData.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + ChannelStock = stock, + StockQuantity = total, + Quantity = stock.Quantity, + }); + Quantity -= stock.Quantity; + } + else + { + //取药数量小于库存 + tempData.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + ChannelStock = stock, + StockQuantity = total, + Quantity = Quantity, + }); + Quantity = 0; + } + } + } + else + { + // 库存不足 + flag = false; + } + } + + } + if (flag) + { + return tempData; + } + else + { + return tempData2; + } + } + + public async Task OrderTakeFinish(List datas) + { + + try + { + _connection.BeginTransaction(); + var flag = true; + // 更新处方状态 + int r1 = _connection.OrderInfo.Where(oi => oi.OrderNo == datas.First().OrderDetail.OrderNo) + .Set(oi => oi.Status, 1) + .Update(); + if (!(r1 > 0)) + { + flag = false; + logger.Error("处方取药完成更新处方状态失败"); + _connection.RollbackTransaction(); + return flag; + } + for (var i = 0; i < datas.Count; i++) + { + var orderTakeVo = datas[i]; + var EffDate = orderTakeVo.ChannelStock.EffDate; + if (!DateTime.TryParse(orderTakeVo.ChannelStock.EffDate, out DateTime dEffDate)) + { + //效期转换出错 + if (orderTakeVo.ChannelStock.EffDate != null) + { + string[] idate = orderTakeVo.ChannelStock.EffDate.Split('/'); + foreach (string iS in idate) + { + if (!string.IsNullOrEmpty(iS.Trim())) + { + switch (iS.Trim().Length) + { + case 4: + EffDate = iS.Trim(); + break; + case 2: + EffDate += "-" + iS.Trim(); + break; + case 1: + EffDate += "-0" + iS.Trim(); + break; + } + } + } + + + } + } + else + { + EffDate = dEffDate.ToString("yyyy-MM-dd"); + } + // 出库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = orderTakeVo.ChannelStock.DrawerNo, + ColNo = orderTakeVo.ChannelStock.ColNo, + DrugId = orderTakeVo.ChannelStock.DrugId, + ManuNo = orderTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + Quantity = orderTakeVo.GetQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = orderTakeVo.OrderDetail.Id.ToString(), + }); + // 更新库存 + int r = _connection.ChannelStock.Where(cs => cs.Id == orderTakeVo.ChannelStock.Id) + .Set(cs => cs.Quantity, orderTakeVo.ChannelStock.Quantity - orderTakeVo.GetQuantity) + .Update(); + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(orderTakeVo.ChannelStock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = orderTakeVo.ChannelStock.DrugId, + ManuNo = orderTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(EffDate) ? DateTime.ParseExact(EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + OutQuantity = orderTakeVo.GetQuantity, + AddQuantity = 0, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == orderTakeVo.ChannelStock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = orderTakeVo.OrderDetail.Id.ToString() + }); + if (mid > 0 && r > 0 && acid > 0) + { + if (orderTakeVo.ChannelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(orderTakeVo.ChannelStock.Quantity - orderTakeVo.GetQuantity, orderTakeVo.ChannelStock.DrawerNo, orderTakeVo.ChannelStock.ColNo); + } + + } + else + { + flag = false; + break; + } + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("处方取药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + public async Task> GetAllCanReturnOrderInfo(string OrderrNo, DateTime OrderDate, int? take, int? skip) + { + var query2 = from od in _connection.OrderDetail + from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.machineId).InnerJoin(c => c.DrugId == od.DrugId) + group od by od.OrderNo into temp + select new { temp.Key }; + var query = from oi in _connection.OrderInfo + from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + select oi; + + if (!String.IsNullOrEmpty(OrderrNo)) + { + query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + } + if (OrderDate != null && OrderDate != DateTime.MinValue) + { + query = query.Where(oi => oi.ChargeDate.Date.Equals(OrderDate.Date)); + } + + query = query.Where(oi => oi.Status == 1); + query = query.Where(oi => oi.CancelFlag == 1); + + + int pagedData = await query.CountAsync(); + + List list = await query + .OrderBy((oi) => oi.RecvDate) + .ThenBy((oi => oi.OrderNo)) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + } + + public async Task> GetMachineRecordByOrderNo(string OrderrNo) + { + var query = _connection.MachineRecord.AsQueryable(); + query = query.InnerJoin( + _connection.OrderDetail.Where(od => od.OrderNo.Equals(OrderrNo)), + (mr, od) => mr.InvoiceId.Equals(od.Id), + (mr, od) => mr + ) + .Where(md => md.Type == 2) + .LoadWith(md => md.Drug) + ; + return await query.ToListAsync(); + } + + public async Task>> getReturnInfoByOrderNo(string OrderrNo) + { + List> tempData = new(); + List details = await this.GetMachineRecordByOrderNo(OrderrNo); + for (var i = 0; i < details.Count; i++) + { + //List> tempData = new(); + MachineRecord detail = details[i]; + List stockList = await this.GetChannelStockByDrugId(detail.DrugId, detail.ManuNo); + + + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + // 当前detail出库数量 + var Quantity = detail.Quantity; + + stockList.First().AddQuantity = Quantity; + + tempData.Add(new OperationVo() + { + Drug = detail.Drug, + data = detail, + StockQuantity = total, + Quantity = Quantity, + ChannelStocks = stockList, + }); + + } + return tempData; + } + + public async Task GetDrugManuNo(string drugId, string manuNo) + { + var query = _connection.DrugManuNo.AsQueryable(); + + return await query.Where(m => m.DrugId.Equals(drugId)) + .Where(m => m.ManuNo.Equals(manuNo)) + .FirstAsync(); + } + + public async Task OrderReturnFinish(List> datas, string OrderNo) + { + try + { + _connection.BeginTransaction(); + var flag = true; + // 更新处方状态 + int r1 = _connection.OrderInfo.Where(oi => oi.OrderNo == OrderNo) + .Set(oi => oi.Status, 0) + .Update(); + if (!(r1 > 0)) + { + flag = false; + logger.Error("处方取药完成更新处方状态失败"); + _connection.RollbackTransaction(); + return flag; + } + for (var i = 0; i < datas.Count; i++) + { + var operationVo = datas[i]; + + List stocks = operationVo.ChannelStocks.Where(cs => cs.ReturnQuantity > 0).ToList(); + + // 更新取出记录状态 + var r2 = _connection.MachineRecord.Where(cs => cs.Id == operationVo.data.Id) + .Set(cs => cs.Status, 2) + .Set(cs => cs.ReturnQuantity1, operationVo.data.Quantity).Update(); + + if (r2 > 0) + { + + } + else + { + flag = false; + break; + } + + for (var j = 0; j < stocks.Count; j++) + { + var channelStock = stocks[j]; + + // 更新库存 + var q = _connection.ChannelStock.Where(cs => cs.Id == channelStock.Id) + .Set(cs => cs.Quantity, channelStock.Quantity + channelStock.ReturnQuantity); + if (String.IsNullOrEmpty(channelStock.ManuNo) || (channelStock.Quantity == 0 && !channelStock.ManuNo.Equals(operationVo.data.ManuNo))) + { + DrugManuNo drugManuNo = await GetDrugManuNo(channelStock.DrugId, operationVo.data.ManuNo); + + channelStock.Dmnguid = drugManuNo.Id; + channelStock.ManuNo = drugManuNo.ManuNo; + channelStock.EffDate = drugManuNo.EffDate.ToString(); + + q = q.Set(cs => cs.Dmnguid, drugManuNo.Id) + .Set(cs => cs.ManuNo, drugManuNo.ManuNo) + .Set(cs => cs.EffDate, drugManuNo.EffDate.ToString()); + } + int r = q.Update(); + // 退回记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = channelStock.DrawerNo, + ColNo = channelStock.ColNo, + DrugId = channelStock.DrugId, + ManuNo = channelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(channelStock.EffDate) ? DateTime.ParseExact(channelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 31, + Quantity = channelStock.ReturnQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = operationVo.data.InvoiceId.ToString(), + GetId = operationVo.data.Id + }); + + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(channelStock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = channelStock.DrugId, + ManuNo = channelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(channelStock.EffDate) ? DateTime.ParseExact(channelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + OutQuantity = channelStock.ReturnQuantity, + AddQuantity = 0, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == channelStock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = operationVo.data.InvoiceId + }); + if (mid > 0 && r > 0 && acid > 0) + { + if (channelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(channelStock.Quantity - channelStock.ReturnQuantity, channelStock.DrawerNo, channelStock.ColNo); + } + } + else + { + flag = false; + break; + } + + } + + + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("处方取药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + + /// + /// 获取药盒中的用药信息 + /// + /// + /// + /// + /// + /// + public async Task> GetAllOrderInfoByBox(int box, string OrderrNo, DateTime OrderDate, int? take, int? skip) + { + var query2 = from od in _connection.OrderDetail + from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.boxMachineId).InnerJoin(c => c.DrugId == od.DrugId) + group od by od.OrderNo into temp + select new { temp.Key }; + var query = from oi in _connection.OrderInfo + from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + where oi.Pharmacy == _setting.storage + select oi; + if (!String.IsNullOrEmpty(OrderrNo)) + { + query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + } + if (OrderDate != null && OrderDate != DateTime.MinValue) + { + query = query.Where(oi => oi.ChargeDate.Date.Equals(OrderDate.Date)); + } + + query = query.Where(oi => oi.Status == 0); + query = query.Where(oi => oi.HisDispFlag == 0); + query = query.Where(oi => oi.CancelFlag == 0); + //query = query.Where(oi => oi.DoctorCode == box); + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(oi => oi.DetailInfo) + .OrderBy((oi) => oi.RecvDate) + .ThenBy((oi => oi.OrderNo)) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + if (list != null && list.Count > 0) + { + for (int i = 0; i < list.Count; i++) + { + //for (int j = 0; j < list[i].DetailList.Count; j++) + //{ + if (list[i].DetailInfo != null && list[i].DetailInfo.Id > 0) + { + list[i].DetailInfo.Drug = await _connection.DrugInfo.AsQueryable().Where(d => d.DrugId == list[i].DetailInfo.DrugId).FirstOrDefaultAsync(); + if (list[i].DetailInfo.Drug != null) + { + list[i].DetailInfo.Drug.Manus = await _connection.DrugManuNo.AsQueryable().Where(m => m.DrugId == list[i].DetailInfo.DrugId).ToListAsync(); + } + } + //} + } + } + + + //var query2 = from od in _connection.OrderDetail + // from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.machineId).InnerJoin(c => c.DrugId == od.DrugId) + // group od by od.OrderNo into temp + // select new { temp.Key }; + //var query = from oi in _connection.OrderInfo + // from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + // select oi; + + //if (!String.IsNullOrEmpty(OrderrNo)) + //{ + // query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + //} + //if (OrderDate != null && OrderDate != DateTime.MinValue) + //{ + // query = query.Where(oi => oi.OrderDate.Date.Equals(OrderDate.Date)); + //} + + //query = query.Where(oi => oi.Status == 0); + //query = query.Where(oi => oi.HisDispFlag == 0); + //query = query.Where(oi => oi.CancelFlag == 0); + ////query = query.Where(oi => oi.DoctorCode == box); + + //int pagedData = await query.CountAsync(); + + //List list = await query + // .LoadWith(oi => oi.Detail) + // .LoadWith(oi => oi.Detail.Drug) + // .OrderBy((oi) => oi.RecvDate) + // .ThenBy((oi => oi.OrderNo)) + // .Skip((int)skip) + // .Take((int)take) + // .ToListAsync(); + //if (list != null && list.Count > 0) + //{ + // for (int i = 0; i < list.Count; i++) + // { + // //list[i].Detail = await _connection.OrderDetail.AsQueryable() + // // .Where(od => od.OrderNo == list[i].OrderNo) + // // .LoadWith(od => od.Drug) + // // .ToListAsync(); + // } + //} + + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + } + /// + /// 获取待处理处方中的麻醉师 + /// + /// + /// + /// + /// + /// + public async Task> GetAllOrderInfo(string Name, string BoxNum, string PatientName, string OrderrNo, DateTime? OrderDate, int? take, int? skip) + { + logger.Info($"GetAllOrderInfo开始:{DateTime.Now}"); + var query2 = from od in _connection.OrderDetail + from cl in _connection.ChannelStock.Where(c => c.MachineId == _setting.boxMachineId).InnerJoin(c => c.DrugId == od.DrugId) + group od by od.OrderNo into temp + select new { temp.Key }; + var query = from oi in _connection.OrderInfo + from od in query2.InnerJoin(od => od.Key == oi.OrderNo) + where oi.Pharmacy == _setting.storage + select oi; + if (!string.IsNullOrEmpty(Name)) + { + query = query.Where(oi => oi.anaesthetistName == Name); + } + if (!string.IsNullOrEmpty(BoxNum) && !BoxNum.Contains("99") && !BoxNum.Contains("111")) + { + query = query.Where(oi => oi.RoomName == BoxNum); + } + if (!string.IsNullOrEmpty(PatientName)) + { + query = query.Where(oi => oi.PatientName.Contains(PatientName)); + } + if (!String.IsNullOrEmpty(OrderrNo)) + { + query = query.Where(oi => oi.OrderNo.Equals(OrderrNo)); + } + if (OrderDate != null && OrderDate != DateTime.MinValue) + { + query = query.Where(oi => oi.ChargeDate.Date.Equals(((DateTime)OrderDate).Date)); + } + query = query.Where(oi => oi.Status == 0); + query = query.Where(oi => oi.HisDispFlag == 0); + query = query.Where(oi => oi.CancelFlag == 0); + + int pagedData = await query.CountAsync(); + + List list = await query + .LoadWith(oi => oi.DetailInfo) + .OrderBy((oi) => oi.DetailInfo.DrugId) + .ThenBy((oi => oi.OrderNo)) + //.Skip((int)skip) + //.Take((int)take) + .ToListAsync(); + if (list != null && list.Count > 0) + { + + var group = list.GroupBy(it => it.DetailInfo.DrugId) + .Select(it => new + { + drugId = it.Key, + totalQuantity = it.Sum(g => g.DetailInfo.Quantity) + }); + foreach (var item in group) + { + OrderInfo oiGroup = list.Where(it => it.DetailInfo.DrugId == item.drugId).FirstOrDefault(); + list.Where(it => it.OrderId == oiGroup.OrderId).ToList().ForEach(it => it.DetailInfo.TotalQuantity = item.totalQuantity); + } + for (int i = 0; i < list.Count; i++) + { + if (list[i].DetailInfo != null && list[i].DetailInfo.Id > 0) + { + list[i].DetailInfo.Drug = await _connection.DrugInfo.AsQueryable().Where(d => d.DrugId == list[i].DetailInfo.DrugId).FirstOrDefaultAsync(); + if (list[i].DetailInfo.Drug != null) + { + list[i].DetailInfo.Drug.Manus = await _connection.DrugManuNo.AsQueryable().Where(m => m.DrugId == list[i].DetailInfo.DrugId).ToListAsync(); + } + } + } + } + logger.Info($"GetAllOrderInfo结束:{DateTime.Now}"); + return new PageData() + { + TotalDesserts = pagedData, + Desserts = list + }; + + } + /// + /// 获取待处理处方中的麻醉师 + /// + /// + /// + /// + /// + /// + public async Task> GetAllOrderInfoDrugByBox(BoxModel boxNum, string roomName, DateTime? OrderDate) + { + List csList = await _connection.ChannelStock + .Where(cs => cs.MachineId == _setting.boxMachineId && cs.DrawerNo == boxNum.BoxName && cs.ColNo == boxNum.BoxNo && cs.Quantity > 0) + .LoadWith(cs => cs.Drug) + .ToListAsync(); + if (csList != null && csList.Count > 0) + { + for (int i = 0; i < csList.Count; i++) + { + List oiList = await _connection.OrderInfo.Where(oi => oi.RoomName == roomName && oi.Status == 0 && oi.HisDispFlag == 0 && oi.CancelFlag == 0 && oi.ChargeDate.Date.Equals(((DateTime)OrderDate).Date)) + .LoadWith(oi => oi.DetailInfo).Where(oi => oi.DetailInfo.DrugId == csList[i].DrugId && oi.DetailInfo.SetManuNo == csList[i].ManuNo) + .ToListAsync(); + csList[i].OrderList = oiList; + csList[i].SelectedOrderList = oiList; + csList[i].UseQuantity = oiList.Sum(oi => oi.DetailInfo.Quantity); + csList[i].OrderQuantity = oiList.Count; + csList[i].EmptyQuantity = oiList.Sum(oi => oi.DetailInfo.Quantity); + csList[i].TotalQuantity = csList.Where(c => c.DrugId == csList[i].DrugId).Sum(c => c.Quantity); + if ((String.IsNullOrEmpty(csList[i].ListId) && csList[i].Quantity > csList[i].UseQuantity) || (csList[i].Quantity > csList[i].BaseQuantity)) + { + //药品未在套餐中绑定需要把药还到对应抽屉 + List allDrugStock = await GetStockByDRrug(csList[i].DrugId, csList[i].ManuNo, 1);// await _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 1 && cs.DrugId == csList[i].DrugId && cs.ManuNo == csList[i].ManuNo).OrderBy(cs => cs.Quantity).ToListAsync(); + if (allDrugStock != null && allDrugStock.Count > 0) + { + csList[i].DrawerChanneStockList = new(); + int iReturnQuantity = csList[i].Quantity - csList[i].UseQuantity - csList[i].BaseQuantity; + for (int j = 0; j < allDrugStock.Count; j++) + { + if (allDrugStock[j].BoardType.ToString().Contains("2") && allDrugStock[j].Quantity >= 25) + continue; + if (allDrugStock[j].BoardType.ToString().Contains("2") && allDrugStock[j].Quantity + csList[i].Quantity - csList[i].UseQuantity > 25) + { + //if (iReturnQuantity <= allDrugStock.Sum(it => it.Quantity)) + if (allDrugStock[j].Quantity <= 25) + { + //有空位置可以放 + int canStockQuantity = 25 - allDrugStock[j].Quantity; + if (canStockQuantity > iReturnQuantity) + { + allDrugStock[j].ReturnQuantity = iReturnQuantity; + csList[i].DrawerChanneStockList.Add(allDrugStock[j]); + break; + } + else + { + allDrugStock[j].ReturnQuantity = canStockQuantity; + iReturnQuantity = iReturnQuantity - allDrugStock[j].ReturnQuantity; + csList[i].DrawerChanneStockList.Add(allDrugStock[j]); + } + //iReturnQuantity = iReturnQuantity - allDrugStock[j].ReturnQuantity; + //for (int q = 0; iReturnQuantity > 0; q++) + //{ + + // allDrugStock[j].ReturnQuantity = 25 - allDrugStock[q].Quantity; + // csList[i].DrawerChanneStockList.Add(allDrugStock[q]); + // iReturnQuantity = iReturnQuantity - allDrugStock[q].ReturnQuantity; + // if (iReturnQuantity <= 0) + // break; + //} + + } + else + { + //库位不足,有药品无库位可放 + allDrugStock[j].ReturnQuantity = iReturnQuantity; + csList[i].DrawerChanneStockList.Add(allDrugStock[j]); + logger.Info($"还药品【{csList[i].Drug.DrugName}】库位不足,有药品无库位可放"); + } + } + else + { + allDrugStock[j].ReturnQuantity = iReturnQuantity; + csList[i].DrawerChanneStockList.Add(allDrugStock[j]); + break; + } + } + } + } + } + + } + int pagedData = csList.Count; + return new PageData() + { + TotalDesserts = pagedData, + Desserts = csList.OrderBy(cs => cs.DrugId).OrderByDescending(cs => cs.UseQuantity).ToList() + }; + } + //public List GetAnaesthetistName() + //{ + // List strList = new List(); + // strList = _connection.OrderInfo.Where(it=>it.state==0&&it.HisDispFlag==0&&it.CancelFlag==0).Select(it => it.anaesthetistName).Distinct().ToList(); + // return strList; + + //} + /// + /// 获取所有药盒号 + /// + /// + /// + public async Task> GetDrawerNum(string machineId) + { + List stockList = _connection.ChannelStock + .Where(cs => cs.MachineId == machineId) + .GroupBy(cs => new { cs.DrawerNo, cs.ColNo }) + .Select(g => new ChannelStock + { + DrawerNo = g.Key.DrawerNo, + ColNo = g.Key.ColNo, + }) + .ToList(); + return stockList; + } + /// + /// 获取指定药盒号 + /// + /// + /// + public async Task> GetDrawerNumByOperationNum(string machineId, int boxColor) + { + List boxModelList = new List(); + //var query = _connection.ChannelStock + // .Where(cs => cs.MachineId == machineId && operationNum.Contains(cs.DrawerNo)&&cs.Quantity>0); + //boxModelList = await _connection.ChannelStock + // .Where(cs => cs.MachineId == machineId && cs.Quantity > 0 && (operationNum.Contains(cs.DrawerNo))) + // .Select(cs => new BoxModel { BoxName = cs.DrawerNo, BoxNo = Convert.ToInt32(cs.ColNo) }).Distinct().OrderBy(cs=>new { cs.BoxName, cs.BoxNo }).ToListAsync(); + //return boxModelList; + var query = _connection.ChannelList.Where(cs => cs.MachineId == machineId).AsQueryable(); + if (boxColor > 0) + { + query.Where(cs => cs.ColNo == boxColor); + } + List csList = query.OrderBy(cs => cs.DrawerNo).ToList(); + if (csList != null && csList.Count > 0) + { + for (int i = 0; i < csList.Count; i++) + { + boxModelList.Add(new BoxModel { BoxName = csList[i].DrawerNo, BoxNo = csList[i].ColNo }); + } + } + + return boxModelList; + } + //核对处方 + public async Task CheckOrderInfo(IList selectedOrderInfos, BoxModel boxModel) + { + try + { + _connection.BeginTransaction(); + bool bFlag = true; + logger.Info($"管理员{_globalStateService.Operator.NickName}开始确认手麻单"); + + + string empChannelStock = string.Empty; + + for (int i = 0; i < selectedOrderInfos.Count; i++) + { + OrderInfo oi = selectedOrderInfos[i]; + + + int drawerNo = Convert.ToInt32(boxModel.BoxName); + if (oi.DetailInfo != null && oi.DetailInfo.Id > 0) + { + //ChannelStock? cs = _connection.ChannelStock.AsQueryable() + // .Where(cs => cs.DrugId == oi.DetailList[j].DrugId + // // && cs.ManuNo == oi.DetailList[j].SetManuNo + // // && cs.EffDate == oi._OrderDetail.SetEffDate + // && cs.MachineId.Equals(_setting.boxMachineId) + // && cs.DrawerNo == drawerNo + // && cs.Quantity >= oi.DetailList[j].Quantity).FirstOrDefault(); + List cs = _connection.ChannelStock.AsQueryable() + .Where(cs => cs.DrugId == oi.DetailInfo.DrugId + && cs.ManuNo == oi.DetailInfo.drugManuNo.ManuNo + //&& cs.EffDate == ((DateTime)oi.DetailInfo.drugManuNo.EffDate).ToString("yyyy-MM-dd") + && cs.MachineId.Equals(_setting.boxMachineId) + && cs.DrawerNo == drawerNo && cs.ColNo == boxModel.BoxNo).OrderBy(cs => cs.EffDate).ToList(); + if (cs.Count <= 0) + { + logger.Info($"处方{oi.OrderNo}中药品{oi.DetailInfo.Drug.DrugName}在{drawerNo}号药盒无库存"); + empChannelStock += $"处方{oi.OrderNo}中药品{oi.DetailInfo.Drug.DrugName}在{drawerNo}号药盒无库存 "; + continue; + } + int csQuantity = cs.Sum(cs => cs.Quantity); + if (csQuantity < oi.DetailInfo.Quantity) + { + logger.Info($"处方{oi.OrderNo}中药品{oi.DetailInfo.Drug.DrugName}在{drawerNo}号库存不足,需要核对数{oi.DetailInfo.Quantity},库存总数{csQuantity}"); + empChannelStock += $"处方{oi.OrderNo}中药品{oi.DetailInfo.Drug.DrugName}在{drawerNo}号库存不足,需要核对数{oi.DetailInfo.Quantity},库存总数{csQuantity} "; + continue; + } + //更新处方状态 + if (oi.Status == 0) + { + int iUpdate = _connection.OrderInfo.Where(o => o.OrderNo == oi.OrderNo).Set(o => o.Status, 2).Update(); + int odUpdate = _connection.OrderDetail.Where(od => od.OrderNo == oi.OrderNo).Set(od => od.SetManuNo, oi.DetailInfo.drugManuNo.ManuNo).Set(od => od.Quantity, oi.DetailInfo.Quantity).Update(); + _connection.Insert(new OrderFinish() + { + OrderNo = oi.OrderNo, + PatientId = oi.PatientId, + Pharmacy = oi.Pharmacy, + State = 1, + //WinNo = DrawerNo + 1 + "号手术间", + Operator = _globalStateService.Operator.NickName, + }); + } + int Break = 0; + for (int k = 0; (k < cs.Count && Break == 0); k++) + { + int oldQuantity = cs[k].Quantity; + int useQuantity = 0; //实际使用数量 + if (cs[k].Quantity >= oi.DetailInfo.Quantity) + { + cs[k].Quantity = cs[k].Quantity - oi.DetailInfo.Quantity; + Break = 1;//药品够取跳出循环 + useQuantity = oi.DetailInfo.Quantity; + } + else + { + oi.DetailInfo.Quantity = oi.DetailInfo.Quantity - cs[k].Quantity; + useQuantity = cs[k].Quantity; + cs[k].Quantity = 0; + } + //cs.NeedNum = cs.NeedNum > 0 ? cs.NeedNum + oi._OrderDetail.Quantity : oi._OrderDetail.Quantity; + logger.Info($"更新药盒{cs[k].DrawerNo}药品{cs[k].DrugId}批次{cs[k].ManuNo}库存为{oldQuantity},处方用药数量为{oi.DetailInfo.Quantity}"); + // 更新数据 库存信息 + _connection.Update(cs[k]); + + //更新ChannelList对应的总库存 + ChannelList? channelList = _connection.ChannelList.AsQueryable().Where(cl => cl.MachineId.Equals(cs[k].MachineId) && cl.Id.Equals(cs[k].ListId) && cl.DrawerNo.Equals(cs[k].DrawerNo)).FirstOrDefault(); + if (channelList != null) + { + channelList.TotalQuantity = channelList.TotalQuantity - useQuantity;// oi.DetailList[j].Quantity; + _connection.Update(channelList); + } + // 获取更新完库存后的药品库存 + List nowChannels = _connection.ChannelStock.AsQueryable() + .Where(it => it.MachineId.Equals(cs[k].MachineId) || it.MachineId.Equals(_setting.machineId)) + .Where(it => it.DrugId.Equals(cs[k].DrugId)) + .Where(it => it.ManuNo.Equals(cs[k].ManuNo)) + .Where(it => it.DrawerType == 1) + .ToList(); + _connection.Insert(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = cs[k].DrawerNo, + ColNo = cs[k].ColNo, + DrugId = cs[k].DrugId, + ManuNo = cs[k].ManuNo, + EffDate = !String.IsNullOrEmpty(cs[k].EffDate) ? DateTime.ParseExact(cs[k].EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = _globalStateService.Operator?.Id, + Reviewer = _globalStateService.Reviewer?.Id, + OperationTime = DateTime.Now, + Quantity = useQuantity,// oi.DetailList[j].Quantity, + Type = 2, + InvoiceId = oi.OrderNo + //, StockQuantity = nowChannels.Sum(it => it.Quantity) + }); + + + //查询上一条账册中的空瓶数 + AccountBookG2? accountBookEmpty = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 1 || ab.Type == 2) + .Where(ab => ab.DrugId == oi.DetailInfo.DrugId) + .Where(ab => ab.ManuNo == cs[k].ManuNo).OrderByDescending(ab => ab.Id).FirstOrDefault(); + //保存账册 + int iInsertResult = _connection.Insert(new AccountBookG2() + { + DrugId = oi.DetailInfo.DrugId, + Type = 2, + Department = oi.DeptName, + OrderNo = oi.OrderNo, + ManuNo = cs[k].ManuNo, + EffDate = cs[k].EffDate, + OutQuantity = useQuantity,// oi.DetailList[j].Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + CreateTime = DateTime.Now, + InvoiceNo = oi.OrderNo, + ManuStock = nowChannels.Sum(it => it.Quantity), + TotalStock = (accountBookEmpty != null ? (accountBookEmpty.TotalStock > 0 ? accountBookEmpty.TotalStock : 0) : 0) + oi.DetailInfo.Quantity, + ShoushuJian = drawerNo.ToString() + }); + //修改凌晨生成的日结存与总结存数据 + AccountBookG2? accountBookG2Day = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 3) + .Where(ab => ab.DrugId == oi.DetailInfo.DrugId) + .Where(ab => ab.ManuNo == cs[k].ManuNo) + .Where(ab => ab.CreateDate == DateTime.Now.ToString("yyyy-MM-dd")).FirstOrDefault(); + if (accountBookG2Day != null) + { + accountBookG2Day.ManuStock = accountBookG2Day.ManuStock - useQuantity;// oi.DetailList[j].Quantity; + _connection.Update(accountBookG2Day); + } + else + { + //生成日结存时可能没有该库位的绑定信息,需要写入日结存 + int iDayResult = _connection.Insert(new AccountBookG2() + { + DrugId = oi.DetailInfo.DrugId, + Type = 3, + ManuNo = cs[k].ManuNo, + EffDate = cs[k].EffDate, + YQuantity = 0, + ManuStock = useQuantity,// oi.DetailList[j].Quantity, + TotalStock = useQuantity,// oi.DetailList[j].Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + InvoiceNo = "日结存" + }); + if (iDayResult <= 0) + { + logger.Info($"未写入日结存数据{oi.DetailInfo.DrugId}-{cs[k].ManuNo}-{cs[k].EffDate}-{useQuantity}"); + empChannelStock += $"未写入日结存数据{oi.DetailInfo.DrugId}-{cs[k].ManuNo}-{cs[k].EffDate}-{useQuantity} "; + } + } + //修改凌晨生成的日结存与总结存数据 + AccountBookG2? accountBookG2Total = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 4) + .Where(ab => ab.DrugId == oi.DetailInfo.DrugId) + .Where(ab => ab.CreateDate == DateTime.Now.ToString("yyyy-MM-dd")).FirstOrDefault(); + if (accountBookG2Total != null) + { + accountBookG2Total.TotalStock = accountBookG2Total.TotalStock - useQuantity;// oi.DetailList[j].Quantity; + _connection.Update(accountBookG2Total); + } + else + { + //生成总结存时可能没有该库位的绑定信息,需要写入总结存 + int iTotalResult = _connection.Insert(new AccountBookG2() + { + DrugId = oi.DetailInfo.DrugId, + Type = 4, + YQuantity = 0, + ManuStock = useQuantity,//oi.DetailList[j].Quantity, + TotalStock = useQuantity,// oi.DetailList[j].Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + InvoiceNo = "总结存" + }); + if (iTotalResult <= 0) + { + logger.Info($"未写入总结存数据{oi.DetailInfo.DrugId}-{useQuantity}"); + empChannelStock += $"未写入总结存数据{oi.DetailInfo.DrugId}-{useQuantity} "; + } + } + } + + } + } + logger.Info($"管理员{_globalStateService.Operator.NickName}结束确认手麻单"); + if (!string.IsNullOrEmpty(empChannelStock)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"有未核对处方:{empChannelStock}", Duration = 4000 } + ); + _connection.RollbackTransaction(); + return false; + } + if (bFlag) + { + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + logger.Info($"管理员{_globalStateService.Operator.NickName}确认手麻单失败"); + return false; + } + } + catch (Exception ex) + { + _connection.RollbackTransaction(); + logger.Info($"核对处方异常{ex.Message}"); + return false; + } + } + int status; + //核对处方 + public async Task CheckOrderInfoByChannelStock(IList csList, BoxModel boxModel) + { + try + { + _connection.BeginTransaction(); + bool bFlag = true; + logger.Info($"管理员{_globalStateService.Operator.NickName}开始核对处方"); + + + string empChannelStock = string.Empty; + + for (int i = 0; i < csList.Count; i++) + { + ChannelStock channelStock = csList[i]; + if (channelStock != null && channelStock.SelectedOrderList != null && channelStock.SelectedOrderList.Count > 0) + { + List oiList = channelStock.SelectedOrderList.ToList(); + for (int j = 0; j < oiList.Count; j++) + { + //修改选中的处方状态 + int iUpdate = _connection.OrderInfo.Where(o => o.OrderNo == oiList[j].OrderNo).Set(o => o.Status, 2).Update(); + _connection.Insert(new OrderFinish() + { + OrderNo = oiList[j].OrderNo, + PatientId = oiList[j].PatientId, + Pharmacy = oiList[j].Pharmacy, + State = 1, + //WinNo = DrawerNo + 1 + "号手术间", + Operator = _globalStateService.Operator.NickName, + }); + //更新库存 + channelStock.Quantity = channelStock.Quantity - oiList[j].DetailInfo.Quantity; + _connection.Update(channelStock); + + //更新ChannelList对应的总库存 + if (!string.IsNullOrEmpty(channelStock.ListId) && channelStock.ListId != "0") + { + ChannelList? channelList = _connection.ChannelList.AsQueryable().Where(cl => cl.Id == channelStock.ListId).FirstOrDefault(); + if (channelList != null) + { + channelList.TotalQuantity = channelList.TotalQuantity - oiList[j].DetailInfo.Quantity; + _connection.Update(channelList); + } + } + //记录出库记录 + _connection.Insert(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = channelStock.DrawerNo, + ColNo = channelStock.ColNo, + DrugId = channelStock.DrugId, + ManuNo = channelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(channelStock.EffDate) ? DateTime.ParseExact(channelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = _globalStateService.Operator?.Id, + Reviewer = _globalStateService.Reviewer?.Id, + OperationTime = DateTime.Now, + Quantity = oiList[j].DetailInfo.Quantity, + Type = 2, + InvoiceId = oiList[j].OrderNo + }); + //保存账册 + // 获取更新完库存后的药品库存 + List nowChannels = _connection.ChannelStock.AsQueryable() + .Where(it => it.MachineId.Equals(_setting.machineId) || it.MachineId.Equals(_setting.boxMachineId)) + .Where(it => it.DrugId.Equals(oiList[j].DetailInfo.DrugId)) + .Where(it => it.ManuNo.Equals(oiList[j].DetailInfo.SetManuNo)) + .Where(it => it.DrawerType == 1) + .ToList(); + //查询上一条账册中的空瓶数 + AccountBookG2? accountBookEmpty = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 1 || ab.Type == 2) + .Where(ab => ab.DrugId == oiList[j].DetailInfo.DrugId) + .Where(ab => ab.ManuNo == oiList[j].DetailInfo.SetManuNo).OrderByDescending(ab => ab.Id).FirstOrDefault(); + //保存账册 + int iInsertResult = _connection.Insert(new AccountBookG2() + { + DrugId = oiList[j].DetailInfo.DrugId, + Type = 2, + Department = oiList[j].DeptName, + OrderNo = oiList[j].OrderNo, + ManuNo = oiList[j].DetailInfo.SetManuNo, + EffDate = oiList[j].DetailInfo.SetEffDate, + OutQuantity = oiList[j].DetailInfo.Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + CreateTime = DateTime.Now, + InvoiceNo = oiList[j].OrderNo, + ManuStock = nowChannels.Sum(it => it.Quantity), + TotalStock = (accountBookEmpty != null ? (accountBookEmpty.TotalStock > 0 ? accountBookEmpty.TotalStock : 0) : 0) + oiList[j].DetailInfo.Quantity, + ShoushuJian = oiList[j].RoomName + }); + + //修改日结 + //修改凌晨生成的日结存与总结存数据 + AccountBookG2? accountBookG2Day = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 3) + .Where(ab => ab.DrugId == oiList[j].DetailInfo.DrugId) + .Where(ab => ab.ManuNo == oiList[j].DetailInfo.SetManuNo) + .Where(ab => ab.CreateDate == DateTime.Now.ToString("yyyy-MM-dd")).FirstOrDefault(); + if (accountBookG2Day != null) + { + accountBookG2Day.ManuStock = accountBookG2Day.ManuStock - oiList[j].DetailInfo.Quantity; + _connection.Update(accountBookG2Day); + } + else + { + //生成日结存时可能没有该库位的绑定信息,需要写入日结存 + int iDayResult = _connection.Insert(new AccountBookG2() + { + DrugId = oiList[j].DetailInfo.DrugId, + Type = 3, + ManuNo = oiList[j].DetailInfo.SetManuNo, + EffDate = oiList[j].DetailInfo.SetEffDate, + YQuantity = 0, + ManuStock = oiList[j].DetailInfo.Quantity, + TotalStock = oiList[j].DetailInfo.Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + InvoiceNo = "日结存" + }); + if (iDayResult <= 0) + { + logger.Info($"未写入日结存数据{oiList[j].DetailInfo.DrugId}-{oiList[j].DetailInfo.SetManuNo}-{oiList[j].DetailInfo.SetEffDate}-{oiList[j].DetailInfo.Quantity}"); + empChannelStock += $"未写入日结存数据{oiList[j].DetailInfo.DrugId}-{oiList[j].DetailInfo.SetManuNo}-{oiList[j].DetailInfo.SetEffDate}-{oiList[j].DetailInfo.Quantity} "; + } + } + //总结 + //修改凌晨生成的日结存与总结存数据 + AccountBookG2? accountBookG2Total = _connection.AccountBookG2.AsQueryable() + .Where(ab => ab.MachineId.Equals(_setting.machineId)) + .Where(ab => ab.Type == 4) + .Where(ab => ab.DrugId == oiList[j].DetailInfo.DrugId) + .Where(ab => ab.CreateDate == DateTime.Now.ToString("yyyy-MM-dd")).FirstOrDefault(); + if (accountBookG2Total != null) + { + accountBookG2Total.TotalStock = accountBookG2Total.TotalStock - oiList[j].DetailInfo.Quantity;// oi.DetailList[j].Quantity; + _connection.Update(accountBookG2Total); + } + else + { + //生成总结存时可能没有该库位的绑定信息,需要写入总结存 + int iTotalResult = _connection.Insert(new AccountBookG2() + { + DrugId = oiList[j].DetailInfo.DrugId, + Type = 4, + YQuantity = 0, + ManuStock = oiList[j].DetailInfo.Quantity, + TotalStock = oiList[j].DetailInfo.Quantity, + UserId1 = _globalStateService.Operator?.Id, + UserId2 = _globalStateService.Reviewer?.Id, + MachineId = _setting.machineId, + CreateDate = DateTime.Now.ToString("yyyy-MM-dd"), + InvoiceNo = "总结存" + }); + if (iTotalResult <= 0) + { + logger.Info($"未写入总结存数据{oiList[j].DetailInfo.DrugId}-{oiList[j].DetailInfo.Quantity}"); + empChannelStock += $"未写入总结存数据{oiList[j].DetailInfo.DrugId}-{oiList[j].DetailInfo.Quantity} "; + } + } + //移出库位里是否有未绑套餐且库存为0的数据,有则删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && (string.IsNullOrEmpty(cs.ListId)) && cs.DrawerNo == channelStock.DrawerNo && cs.ColNo == channelStock.ColNo && cs.Quantity <= 0).Delete(); + //删除绑定套餐中同一药品多批次且库存为0的第一条数据 + List delChannelStock = await _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && cs.DrawerNo == channelStock.DrawerNo && cs.ColNo == channelStock.ColNo && cs.DrugId == channelStock.DrugId).ToListAsync(); + if (delChannelStock != null && delChannelStock.Count > 1) + { + //删除绑定套餐中库存为0的药的批次数据,只保留一条数据 + List del = delChannelStock.Where(c => c.Quantity <= 0).ToList(); + if (del != null && del.Count > 0) + { + if (delChannelStock.Count == del.Count) + { + for (int d = 1; d < del.Count; d++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[d].Id).Delete(); + } + } + else + { + for (int d = 0; d < del.Count; d++) + { + _connection.ChannelStock.Where(cs => cs.Id == del[d].Id).Delete(); + } + } + } + } + } + + } + + List drawerNos = new(); + List returnStock = new(); + //if (csList.Any(c => c.DrawerChanneStockList?.Count > 0)) + + if (csList[i].DrawerChanneStockList != null && csList[i].DrawerChanneStockList.Count > 0) + { + List drawerChannelStockList = csList[i].DrawerChanneStockList; + for (int j = 0; j < drawerChannelStockList.Count; j++) + { + //还药将库存加入抽屉、从药盒中减库存 + _connection.ChannelStock.Where(cs => cs.Id == csList[i].DrawerChanneStockList[j].Id).Set(cs => cs.Quantity, csList[i].DrawerChanneStockList[j].Quantity + csList[i].DrawerChanneStockList[j].ReturnQuantity).Update(); + _connection.ChannelStock.Where(cs => cs.Id == csList[i].Id).Set(cs => cs.Quantity, csList[i].Quantity - csList[i].DrawerChanneStockList[j].ReturnQuantity).Update(); + //药盒对应channel_list表总库存也要减 + ChannelList clList = _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.boxMachineId) && cl.DrawerNo == csList[i].DrawerNo && cl.ColNo == csList[i].ColNo).FirstOrDefault(); + if (clList != null) + { + clList.TotalQuantity -= csList[i].DrawerChanneStockList[j].ReturnQuantity; + int iUpdate = await _connection.UpdateAsync(clList); + if (iUpdate <= 0) + { + logger.Info($"抽屉还药记录药盒{boxModel.BoxName}-{boxModel.BoxNo}总库存失败,还药数量{csList[i].DrawerChanneStockList[j].ReturnQuantity}"); + } + } + MachineRecord _MachineRecord = _connection.MachineRecord + .Where(dm => dm.MachineId.Equals(_setting.boxMachineId) && dm.DrugId == csList[i].DrugId && dm.ManuNo == csList[i].ManuNo && dm.BoxDrawer == csList[i].DrawerNo && dm.ColNo == csList[i].ColNo && dm.Type == 2 && dm.Status != 2).FirstOrDefault(); + if (_MachineRecord != null) + { + _MachineRecord.ReturnQuantity2 = _MachineRecord.ReturnQuantity2 + _MachineRecord.CurrentReturnQuantity; + _MachineRecord.Status = _MachineRecord.ReturnQuantity2 + _MachineRecord.ReturnQuantity1 >= _MachineRecord.Quantity ? 2 : 1; + // 更新借药数据 取药记录 设置还药数量、状态 + _connection.Update(_MachineRecord); + } + //添加还药记录 + int acid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + DrawerNo = csList[i].DrawerChanneStockList[j].DrawerNo, + ColNo = csList[i].DrawerChanneStockList[j].ColNo, + DrugId = csList[i].DrugId, + ManuNo = csList[i].DrawerChanneStockList[j].ManuNo, + // EffDate = !String.IsNullOrEmpty(record.EffDate) ? DateTime.ParseExact(record.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = _globalStateService.Operator?.Id, + Reviewer = _globalStateService.Reviewer?.Id, + OperationTime = DateTime.Now, + Quantity = csList[i].DrawerChanneStockList[j].ReturnQuantity, + Type = 31, + InvoiceId = csList[i].Location, + GetId = _MachineRecord?.GetId + }); + } + + + } + if (csList[i].EmptyStock != null && csList[i].EmptyStock.ReturnQuantity > 0) + { + //还空瓶,将空瓶数量加到空瓶库位 //还药将库存加入抽屉、从药盒中减库存 + _connection.ChannelStock.Where(cs => cs.Id == csList[i].EmptyStock.Id).Set(cs => cs.Quantity, csList[i].EmptyStock.Quantity + csList[i].EmptyStock.ReturnQuantity).Update(); + + MachineRecord _MachineRecord = _connection.MachineRecord + .Where(dm => dm.MachineId.Equals(_setting.boxMachineId) && dm.DrugId == csList[i].DrugId && dm.ManuNo == csList[i].ManuNo && dm.BoxDrawer == csList[i].DrawerNo && dm.ColNo == csList[i].ColNo && dm.Type == 2 && dm.Status != 2).FirstOrDefault(); + if (_MachineRecord != null) + { + _MachineRecord.ReturnQuantity2 = _MachineRecord.ReturnQuantity2 + _MachineRecord.CurrentReturnQuantity; + _MachineRecord.Status = _MachineRecord.ReturnQuantity2 + _MachineRecord.ReturnQuantity1 >= _MachineRecord.Quantity ? 2 : 1; + // 更新借药数据 取药记录 设置还药数量、状态 + _connection.Update(_MachineRecord); + } + //添加还空瓶记录 + int acid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + DrawerNo = csList[i].EmptyStock.DrawerNo, + ColNo = csList[i].EmptyStock.ColNo, + DrugId = csList[i].DrugId, + ManuNo = csList[i].EmptyStock.ManuNo, + // EffDate = !String.IsNullOrEmpty(record.EffDate) ? DateTime.ParseExact(record.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + Operator = _globalStateService.Operator?.Id, + Reviewer = _globalStateService.Reviewer?.Id, + OperationTime = DateTime.Now, + Quantity = csList[i].EmptyStock.ReturnQuantity, + Type = 32, + InvoiceId = csList[i].Location, + GetId = _MachineRecord?.GetId + }); + } + } + + //将药盒中无绑定库位的药品且库存为0的删除 + _connection.ChannelStock.Where(cs => cs.MachineId.Equals(_setting.boxMachineId) && string.IsNullOrEmpty(cs.ListId) && cs.Quantity <= 0).Delete(); + logger.Info($"管理员{_globalStateService.Operator.NickName}结束确认手麻单"); + if (!string.IsNullOrEmpty(empChannelStock)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"有未核对处方:{empChannelStock}", Duration = 4000 } + ); + _connection.RollbackTransaction(); + return false; + } + if (bFlag) + { + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + logger.Info($"管理员{_globalStateService.Operator.NickName}确认手麻单失败"); + return false; + } + } + catch (Exception ex) + { + _connection.RollbackTransaction(); + logger.Info($"核对处方异常{ex.Message}"); + return false; + } + } + + void RestData() + { + // PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + // this.status = 0; + // data.ForEach(it => + // { + // it.Status = 0; + // it.BeforeQuantity = new int[9]; + // it.AfterQuantity = new int[9]; + // }); + // this.WeightFinnalQuantity = new int[9]; + // DrawerNoColNoList.Clear(); + } + public async Task> GetAnaesthetistName() + { + List strList = new List(); + strList = await _connection.OrderInfo.Where(it => it.state == 0 && it.HisDispFlag == 0 && it.CancelFlag == 0).Select(it => new Anaesthetist { Name = it.anaesthetistName }).Distinct().ToListAsync(); + return strList; + + } + + //获取麻醉师单对应的手术间号 + public async Task> GetOperationNum(int boxColor) + { + List boxNumList = new List(); + //List roomNameList = await _connection.OrderInfo + // .Where(it => it.state == 0 && it.HisDispFlag == 0 && it.CancelFlag == 0&&it.anaesthetistName== anaesthetistName) + // .Select(it => Convert.ToInt32(it.RoomName.Substring(6, it.RoomName.Length - 6))).Distinct().ToListAsync(); + //roomNameList.Add(99); + //roomNameList.Add(111); + logger.Info($"开始查询药盒{DateTime.Now}"); + boxNumList = await GetDrawerNumByOperationNum(_setting.boxMachineId, boxColor); + + logger.Info($"结束查询药盒{DateTime.Now}"); + return boxNumList; + } + + + //获取麻醉师单对应的手术间号(查询全部手术间已绑套餐的手术间) + public async Task> GetAllBindOperationNum() + { + List boxModelList = new List(); + boxModelList = await _connection.ChannelList + .Where(cs => cs.MachineId == _setting.boxMachineId && (!string.IsNullOrEmpty(cs.DrugId))) + .Select(cs => new BoxModel { BoxName = cs.DrawerNo, BoxNo = Convert.ToInt32(cs.ColNo) }).Distinct().OrderBy(cs => new { cs.BoxName, cs.BoxNo }).ToListAsync(); + return boxModelList; + } + + //查询药品对应的库位 drawerType=1药品库位,其他则是回收库位 + public async Task> GetStockByDRrug(string drugId, string manuNo, int drawerType) + { + if (drawerType == 1) + { + return await _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == drawerType && cs.DrugId == drugId && cs.ManuNo == manuNo).OrderBy(cs => cs.Quantity).ToListAsync(); + } + else + { + return await _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType != 1 && cs.DrugId == drugId).OrderBy(cs => cs.Quantity).ToListAsync(); + } + } + + public Task> GetDrawerNumByOperationNum(string machineId, List operationNum) + { + throw new NotImplementedException(); + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/PlanDao.cs b/MasaBlazorApp3/DataAccess/Impl/PlanDao.cs new file mode 100644 index 0000000..0c55b77 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/PlanDao.cs @@ -0,0 +1,461 @@ +using Google.Protobuf; +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using Microsoft.Extensions.Options; +using Org.BouncyCastle.Crypto; +using Radzen; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using ZstdSharp.Unsafe; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class PlanDao : IPlanDao + { + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(DrugInfoDao)); + private GlobalStateService _globalStateService; + private NotificationService _message; + public PlanDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService,NotificationService message) + { + _connection = connection; + _setting = setting.Value; + _globalStateService = globalStateService; + _message = message; + } + /// + /// 获取所有套餐数据 + /// + /// + public async Task> GetAllPlanInfo() + { + var query = _connection.Plan.AsQueryable(); + + List list = await query.Where(p => p.UseState == 1 && p.MachineId==_setting.boxMachineId) + .LoadWith(p => p._PlanDetails.Where(pd => pd.UseState == 1)) + //.ThenLoad(p=>p._DrugInfo) + .OrderBy(r => r.Id) + .ToListAsync(); + if (list != null && list.Count > 0) + { + for (int i = 0; i < list.Count(); i++) + { + for (int j = 0; j < list[i]._PlanDetails.Count(); j++) + { + list[i]._PlanDetails[j]._DrugInfo = + _connection.DrugInfo.AsQueryable().Where(di => di.DrugId == list[i]._PlanDetails[j].DrugId).First(); + + } + } + } + + var other = _connection.DrugInfo.AsQueryable(); + List drugInfos = await other + .LoadWith(di => di.Manus) + .OrderBy((di) => di.DrugId) + .ToListAsync(); + + int pagedData = await query.CountAsync(); + return new PageMultiData() + { + + TotalDesserts = pagedData, + Desserts = list, + Other = drugInfos + }; + } + /// + /// 根据套餐ID获取套餐数据 + /// + /// + /// + public async Task GetPlanById(int Id) + { + var query = _connection.Plan.AsQueryable().Where(p => p.Id == Id && p.UseState == 1 && p.MachineId == _setting.boxMachineId); + List list = await query + .LoadWith(p => p._PlanDetails) + //.ThenLoad(p=>p._DrugInfo) + .OrderBy(r => r.Id) + .ToListAsync(); + if (list != null && list.Count > 0) + { + for (int i = 0; i < list.Count(); i++) + { + for (int j = 0; j < list[i]._PlanDetails.Count(); j++) + { + list[i]._PlanDetails[j]._DrugInfo = + _connection.DrugInfo.AsQueryable().Where(di => di.DrugId == list[i]._PlanDetails[j].DrugId).First(); + + } + } + } + + return list[0]; + } + + /// + /// 新增套餐 + /// + /// + /// + public async Task InsertPlanInfo(Plan plan) + { + try + { + plan.AddTime = DateTime.Now; + plan.OperatorUser = _globalStateService.Operator.Id; + plan.ReviewerUser = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id; + plan.UseState = 1; + plan.MachineId = _setting.boxMachineId; + if(_connection.InsertWithInt32Identity(plan) > 0) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + OperationTime = DateTime.Now, + Type = 50, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"新增套餐{plan.Name}", + }); + + + return true; + } + else + { + return false; + } + } + catch (Exception ex) + { + + logger.Error($"添加套餐{plan.Name}失败,错误:" + ex.Message); + return false; + } + } + + /// + /// 更新套餐 + /// + /// + /// + public async Task UpdatePlanInfo(Plan plan) + { + try + { + var iResult = _connection.Plan + .Where(p => p.Id == plan.Id && p.MachineId == _setting.boxMachineId) + .Set(p => p.Name, plan.Name) + .Set(p => p.Description, plan.Description); + return iResult.Update() > 0; + } + catch (Exception ex) + { + logger.Error($"修改套餐{plan.Name}失败,错误:" + ex.Message); + return false; + } + } + //查询要删除的套餐下是否有绑定,且绑定有库存 + public async Task CheckPlanBind(int planId) + { + try + { + //查询是否有绑定,没有绑定可以删除,有绑定则不允许删除 + List channelListsId = await _connection.ChannelList.AsQueryable().Where(cl => cl.DrugId == planId.ToString() && cl.MachineId == _setting.boxMachineId).Select(cl => cl.Id).ToListAsync(); + if (channelListsId != null && channelListsId.Count > 0) + { + bool searchResult = _connection.ChannelStock.AsQueryable().Where(cs => channelListsId.Contains(cs.ListId)).Any(cs => cs.Quantity > 0); + if (searchResult) + { + return false; + } + else + { + return true; + } + } + else + { + return true; + } + } + catch (Exception ex) + { + logger.Error($"查询要删除的套餐下是否有绑定异常{ex.Message}"); + return false; + } + } + + + /// + /// 删除套餐 + /// + /// + /// + public async Task DeletePlanInfo(int planId) + { + try + { + _connection.BeginTransaction(); + + + //如果套餐下有绑药且库存为0的也将绑定药品信息一并删除 + List listIds = await _connection.ChannelList.Where(cl => cl.DrugId == planId.ToString()).Select(cl => cl.Id).ToListAsync(); + int iDelResult = 1; + int iDelChannelListResult = 1; + if (listIds != null && listIds.Count > 0) + { + //删除channelStock表中的绑定药品 + iDelResult = _connection.ChannelStock.Where(cs => listIds.Contains(cs.ListId)).Delete(); + _connection.ChannelList.Where(cl => listIds.Contains(cl.Id)).Set(cl => cl.DrugId, "").Update(); + + + } + bool flag = false; + logger.Error($"删除套餐{planId}"); + //查询该套餐下是否有药品,如果有则一并删除 + int iHasPd = _connection.PlanDetails.Where(pd => pd.PlanId == planId).Count(); + int pdResult = 1; + if (iHasPd > 0) + { + pdResult = await _connection.PlanDetails.Where(pd => pd.PlanId == planId).Set(pd => pd.UseState, 0).UpdateAsync(); + } + int pResult = await _connection.Plan.Where(p => p.Id == planId).Set(pd => pd.UseState, 0).UpdateAsync(); + + + + if (pdResult > 0 && pResult > 0 && iDelResult > 0 && iDelChannelListResult > 0) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + OperationTime = DateTime.Now, + Type = 51, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"删除套餐{planId}", + }); + + flag = true; + } + + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + } + catch (Exception ex) + { + logger.Error($"修改套餐失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + + + /// + /// 向套餐中添加药品 + /// + /// + /// + public async Task AddPlanDetail(PlanDetails details) + { + try + { + if (!string.IsNullOrEmpty(details.DrugId)) + { + int id = await _connection.InsertWithInt32IdentityAsync(details); + details.Id = id; + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + OperationTime = DateTime.Now, + Type = 52, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"套餐{details.PlanId}添加药品{details.DrugId},基数{details.BaseQuantity}", + }); + return id > 0; + } + else + { + return false; + } + } + catch (Exception ex) + { + logger.Error($"添加药品{details._DrugInfo.DrugName}失败,错误:" + ex.Message); + return false; + } + } + /// + /// 修改套餐中的药品 + /// + /// + /// + public async Task UpdatePlanDetail(PlanDetails details) + { + try + { + var iResult = _connection.PlanDetails + .Where(p => p.Id == details.Id) + .Set(p => p.DrugId, details._DrugInfo.DrugId) + .Set(p => p.BaseQuantity, details.BaseQuantity); + + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + OperationTime = DateTime.Now, + Type = 53, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"修改套餐{details.PlanId},药品{details.DrugId}-{details._DrugInfo.DrugId},基数{details.BaseQuantity}", + }); + return await iResult.UpdateAsync() > 0; + } + catch (Exception ex) + { + logger.Error($"修改药品{details._DrugInfo.DrugName}失败,错误:" + ex.Message); + return false; + } + } + + //查询要删除的药品是否有绑定且库存大于0 + public async Task CheckPlanDetailBind(PlanDetails planDetail) + { + try + { + bool bFlag = true; + List idList = await _connection.ChannelList.AsQueryable().Where(cl => cl.DrugId == planDetail.PlanId.ToString()).Select(cl => cl.Id).ToListAsync(); + if (idList != null && idList.Count > 0) + { + bFlag = !(_connection.ChannelStock.AsQueryable().Where(cs => idList.Contains(cs.ListId) && cs.DrugId == planDetail.DrugId).Any(cs => cs.Quantity > 0)); + } + return bFlag; + } + catch (Exception ex) + { + logger.Error($"查询要删除的药品是否有绑定异常{ex.Message}"); + return true; + } + } + + /// + /// 删除套餐中的药品 + /// + /// + /// + public async Task DeletePlanDetail(PlanDetails detail) + { + try + { + _connection.BeginTransaction(); + logger.Error($"删除套餐中的药品{detail._DrugInfo.DrugName}"); + int iDelResult = 1; + //删除该套餐下该药品对应绑定的库位 + List idList = await _connection.ChannelList.AsQueryable().Where(cl => cl.DrugId == detail.PlanId.ToString()).Select(cl => cl.Id).ToListAsync(); + if (idList != null && idList.Count > 0) + { + iDelResult = await _connection.ChannelStock.AsQueryable().Where(cs => idList.Contains(cs.ListId) && cs.DrugId == detail.DrugId).DeleteAsync(); + } + //if (iDelResult > 0) + //{ + bool bUpdateResult = _connection.PlanDetails.Where(p => p.Id == detail.Id).Set(p => p.UseState, 0).Update() > 0; + if (bUpdateResult) + { + //保存操作记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.boxMachineId, + OperationTime = DateTime.Now, + Type = 54, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = $"删除套餐{detail.PlanId},中的药品{detail._DrugInfo.DrugName}ID:{detail.DrugId}", + }); + _connection.CommitTransaction(); + return true; + } + else + { + _connection.RollbackTransaction(); + return false; + } + //} + //else + //{ + // logger.Error($"套餐中的药品{detail._DrugInfo.DrugName}无绑定"); + // return false; + //} + } + catch (Exception ex) + { + logger.Error($"添加药品失败,错误:" + ex.Message); + return false; + } + } + + public bool CheckDrugById(PlanDetails details) + { + if (details._DrugInfo.DrugId != null) + { + //查询该药品是否已在套餐中存在,存在则不再添加 + PlanDetails pdDrug = _connection.PlanDetails.Where(p => p.PlanId == details.PlanId && p.DrugId == details._DrugInfo.DrugId && p.UseState == 1).FirstOrDefault(); + + if (details.Id > 0) + { + //修改原数据 + if (pdDrug != null && pdDrug.Id == details.Id) + { + return true; + } + else + { + return false; + } + } + else + { + //新增数据 + if (pdDrug != null) + { + return !(pdDrug.Id > 0); + } + else + { + return true; + } + } + //return !(hasCount > 0); + } + else + { + return true; + } + } + + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/ReportDataDao.cs b/MasaBlazorApp3/DataAccess/Impl/ReportDataDao.cs new file mode 100644 index 0000000..af82109 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/ReportDataDao.cs @@ -0,0 +1,178 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using Microsoft.Extensions.Options; +using Mysqlx.Crud; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class ReportDataDao : IReportDataDao + { + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(ReportDataDao)); + public ReportDataDao(AppDataConnection connection, IOptions setting) + { + _connection = connection; + _setting = setting.Value; + } + //获取库存导出数据 + public async Task> GetStockExportData(string drugName) + { + try + { + List reportStockList = new List(); + int pagedData = 0; + string SQL = $@"SELECT cl.drug_id AS DrugId,di.`drug_name` AS DrugName,di.drug_type AS DrugType,di.drug_spec AS DrugSpec,di.manufactory AS Manufactory, + di.pack_unit AS pack_unit,di.py_code AS PyCode,null AS Stocks,NULL AS Manus,db.baseQuantity AS BaseQuantity,CONCAT(cl.row_no,cl.col_no) as location, + cl.manu_no as ManuNo,cl.eff_date as EffDate,cl.Quantity AS Quantity,cl.manu_no,cl.eff_date FROM channel_stock cl INNER JOIN drug_info di ON di.`drug_id` = cl.`drug_id` + LEFT JOIN drug_base db ON db.drugid=di.drug_id and db.machine_id= '{_setting.machineId}' + WHERE cl.`machine_id` = '{_setting.machineId}' AND cl.`drawer_type` = 1 "; + if (!string.IsNullOrEmpty(drugName)) + { + SQL += $" and (di.drug_name like '%{drugName}%'|| di.py_code like '%{drugName}%'||di.drug_id like '%{drugName}%')"; + } + SQL += " ORDER BY cl.`drug_id`"; + // 加载模板文件 + //Report.LoadFromFile(new FileInfo(AppDomain.CurrentDomain.BaseDirectory) + "ReportTemp//" + "stock_template.grf"); + + var reportList = _connection.FromSql(SQL); + if (reportList != null) + { + foreach (var report in reportList) + { + reportStockList.Add(report); + } + + pagedData = await reportList.CountAsync(); + } + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = reportStockList + }; + } + catch (Exception ex) + { + logger.Info($"获取库存导出数据异常:{ex.Message}"); + return null; + } + } + //中部战区总医院麻醉药品、第一类精神药品进出专用账册 + public async Task> GetAccountExportData(DateTime? startDate, DateTime? endDate, string drugName) + { + List accountList = new List(); + int pagedData = 0; + DateTime? p_startDate = startDate ?? Convert.ToDateTime("2010-1-1"); + DateTime? p_endDate = endDate ?? DateTime.Now.AddDays(1); + string SQL = $@"SELECT ab.`create_time` AS `OperationTime`,ab.manu_no AS ManuNo,ab.eff_date as EffDate, ab.add_quantity AS `inQuantity`, + ab.out_quantity AS `outQuantity`,ab.manu_quantity as ManuQuantity,ab.total_quantity as StockQuantity, + u1.`user_name` AS `operatorName`, u2.`user_name` AS `reviewerName`, ab.`drug_id` AS `drugId`,di.`drug_name` AS `drugName`,di.`drug_spec` AS `drugSpec`, di.`pack_unit` AS `BigUnit`, di.`dosage` AS `dosage`, + di.`manufactory` AS `manufactory`, ab.`invoice_id` AS `invoiceId`, ab.department as department,'' as Remarks FROM + account_book ab LEFT JOIN drug_info di ON ab.`drug_id` = di.`drug_id` LEFT JOIN user_list u1 ON ab.`operator` = u1.`id` + LEFT JOIN user_list u2 ON ab.`reviewer` = u2.`id` WHERE ab.`machine_id` = '{_setting.machineId}' AND ab.type in(1,2,31) DATE_FORMAT(ab.`create_time`,'%Y-%m-%d') > '{p_startDate}' + AND DATE_FORMAT(ab.`create_time`,'%Y-%m-%d') < '{p_endDate}'"; + if (!string.IsNullOrEmpty(drugName)) + { + SQL += $" AND (di.drug_name like '%{drugName}%' or di.drug_id like '%{drugName}%' or di.py_code like '%{drugName}%')"; + } + SQL += " ORDER BY ab.`create_time`, ab.`drug_id`"; + var reportList = _connection.FromSql(SQL); + if (reportList != null) + { + foreach (var report in reportList) + { + accountList.Add(report); + } + + pagedData = await reportList.CountAsync(); + } + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = accountList + }; + } + //手术室患者麻醉药品使用登记本(主表数据) + public async Task> GetOrderInfoParentData(DateTime? searchDate) + { + //List accountList = new List(); + int pagedData = 0; + + string SQL = $@"SELECT od.drug_id drugId1, di.drug_Name drugName1,od.set_manu_No as manuNo1,sum(od.quantity) quantity1 ,oi.charge_Date as portDate + from order_info oi inner join order_detail od on oi.order_no=od.order_no inner join drug_info di on od.drug_id=di.drug_id + WHERE DATE_FORMAT(oi.charge_Date,'%Y-%m-%d')='{searchDate?.ToString("yyyy-MM-dd")}' and oi.dm_status=2 and oi.cancel_flag=0 and oi.his_disp_flag=0 and di.pack_h=1 group by od.drug_id,od.set_manu_No"; + + + + + var reportList =await _connection.FromSql(SQL).ToListAsync(); + //if (reportList != null) + //{ + // foreach (var report in reportList) + // { + // accountList.Add(report); + // } + + // pagedData = await reportList.CountAsync(); + //} + return reportList; + } + + //手术室患者麻醉药品使用登记本(子数据) + public async Task> GetOrderInfoData(DateTime? searchDate) + { + string SQL = $@"SELECT oi.charge_Date as portdate, od.drug_id as DrugId,1 as ShouShuJian,oi.anaesthetist_code as doctor1,oi.anaesthetist_name as doctor2,oi.patient_id as patientId,oi.p_name as PName,oi.disease as Diagnose, + CONCAT(di.drug_name,' ',di.drug_spec) as DrugName,od.set_manu_No as ManuNo,od.use_dosage as UsageDosage,'' as CanYeLiang,'' as CanYeChuZhi,'' as UseUserName,'' as CheckUserName,od.quantity as quantity + from order_info oi inner join order_detail od on oi.order_no=od.order_no inner join drug_info di on od.drug_id=di.drug_id + WHERE DATE_FORMAT(oi.charge_Date,'%Y-%m-%d')='{searchDate?.ToString("yyyy-MM-dd")}' and oi.dm_status=2 and oi.cancel_flag=0 and oi.his_disp_flag=0 and di.pack_h=1 order by oi.anaesthetist_code,oi.anaesthetist_name, od.drug_id"; + + + + + var reportList =await _connection.FromSql(SQL).ToListAsync(); + return reportList; + } + + //麻醉科毒麻药品请领登记表 + public async Task> GetApplyInfoDate(DateTime searchDate) + { + List accountList = new List(); + int pagedData = 0; + + string SQL = $@"SELECT Drawerno as BoxNum,Create_date AS applyinfo,userfirst,usersecond,drugid,doctor,manager + from applyinfo ap inner join drug_info di on ap.drugid=di.drug_id + WHERE machine_id='{_setting.boxMachineId}' and DATE_FORMAT(ap.Create_date,'%Y-%m-%d')='{searchDate.ToString("yyyy-MM-dd")}' "; + + + + + var reportList = _connection.FromSql(SQL); + if (reportList != null&& reportList.Count()>0) + { + foreach (var report in reportList) + { + accountList.Add(report); + } + + pagedData = await reportList.CountAsync(); + } + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = accountList + }; + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/RoleDao.cs b/MasaBlazorApp3/DataAccess/Impl/RoleDao.cs new file mode 100644 index 0000000..6355459 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/RoleDao.cs @@ -0,0 +1,75 @@ +using LinqToDB; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using Microsoft.Extensions.Options; +using System.Linq; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class RoleDao : IRoleDao + { + + private AppDataConnection _connection; + private readonly SettingConfig _setting; + + public RoleDao(AppDataConnection connection, IOptions setting) { _connection = connection; _setting = setting.Value; } + + public async Task GetRoleById(int id) + { + return await _connection.Role.AsQueryable().FirstAsync(x => x.Id == id); + } + + + public int InsertRole(Role role) + { + role.MachineId = _setting.machineId; + return _connection.InsertWithInt32Identity(role); + } + + public bool UpdateRole(Role role) + { + int r = _connection.Role + .Where(r => r.Id == role.Id) + .Set(r => r.RoleName, role.RoleName) + .Set(r => r.permissions, role.permissions) + .Update(); + return r > 0; + } + + public bool DeleteRole(int id) + { + return _connection.Role.Where(r => r.Id ==id).Delete() > 0; + } + + public async Task> GetRolesByName(string name, int? take, int? skip) + { + var query = _connection.Role.AsQueryable(); + + if (!String.IsNullOrEmpty(name)) + { + query = query.Where(r => r.RoleName.IndexOf(name) > -1); + } + query = query.Where(r => r.MachineId == _setting.machineId); + + List list = await query + .OrderBy(r => r.Id) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + + int pagedData = await query.CountAsync(); + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + } + + public async Task> GetAllRoles() + { + return await _connection.Role.Where(r => r.MachineId == _setting.machineId).ToListAsync(); + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/SelfTakeDao.cs b/MasaBlazorApp3/DataAccess/Impl/SelfTakeDao.cs new file mode 100644 index 0000000..c2de68c --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/SelfTakeDao.cs @@ -0,0 +1,300 @@ +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pages; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Pojo.Vo; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class SelfTakeDao : ISelfTakeDao + { + private AppDataConnection _connection; + private readonly SettingConfig _setting; + ILog logger = LogManager.GetLogger(typeof(SelfTake)); + private GlobalStateService _globalStateService; + private readonly PortUtil _portUtil; + + public SelfTakeDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService, PortUtil portUtil) + { + _connection = connection; + _setting = setting.Value; + _globalStateService = globalStateService; + _portUtil = portUtil; + } + /// + /// 根据药品信息 获取药品库存信息 + /// + /// + /// + public async Task> GetChannelStocksByDrug(List drugInfos) + { + List channelStocks = new List(); + try + { + foreach (var drugInfo in drugInfos) + { + var query = _connection.ChannelStock.AsQueryable(); + ChannelStock channelStock = query.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 1 && cs.DrugId == drugInfo.DrugId).First(); + if (channelStock != null) + { + channelStocks.Add(channelStock); + } + else + { + logger.Info($"药品{drugInfo.DrugName}未绑定"); + channelStocks.Add(new ChannelStock() + { + DrugId = drugInfo.DrugId, + DrawerType = 1, + MachineId = _setting.machineId, + Quantity = 0 + }); + } + } + } + catch (Exception ex) + { + logger.Info($"SelfTakeDao异常{ex.Message}"); + } + return channelStocks; + } + /// + /// 根据药品明细获取数据 + /// + /// + /// + public async Task> getTakeInfoByOrderNo(List orderDetails) + { + + List tempData = new(); + List tempData2 = new(); + var flag = true; + for (var i = 0; i < orderDetails.Count; i++) + { + //List> tempData = new(); + OrderDetail detail = orderDetails[i]; + // 当前detail取药数量 + var Quantity = detail.Quantity; + List stockList = await this.GetChannelStockByDrugId(detail.Drug.DrugId, detail.SetManuNo, Quantity); + + // 当前药品的库存总量 + var total = stockList.Sum(current => current.Quantity); + + tempData2.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + StockQuantity = total, + Quantity = Quantity + }); + + if (flag) + { + // 盘点库存是否足够 + if (total > Quantity) + { + + for (var j = 0; Quantity > 0; j++) + { + ChannelStock stock = stockList[j]; + if (Quantity > stock.Quantity) + { + // 取药数量大于库存 + tempData.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + ChannelStock = stock, + StockQuantity = total, + Quantity = stock.Quantity, + }); + Quantity -= stock.Quantity; + } + else + { + //取药数量小于库存 + tempData.Add(new OrderTakeVo() + { + Drug = detail.Drug, + OrderDetail = detail, + ChannelStock = stock, + StockQuantity = total, + Quantity = Quantity, + }); + Quantity = 0; + } + } + } + else + { + // 库存不足 + flag = false; + } + } + + } + if (flag) + { + return tempData; + } + else + { + return tempData2; + } + } + + public async Task> GetChannelStockByDrugId(string DrugId, String ManuNo, int quantity = 0) + { + var query = _connection.ChannelStock.AsQueryable(); + + + query = query.Where(cs => cs.MachineId.Equals(_setting.machineId)).Where(cs => cs.DrawerType == 1) + .Where(cs => cs.Quantity > 0) + .Where(cs => cs.DrugId.Equals(DrugId)); + + if (quantity > 0) + { + if (!String.IsNullOrEmpty(ManuNo)) + { + query = query.Where(cs => cs.ManuNo.Equals(ManuNo)); + } + } + else + { + if (!String.IsNullOrEmpty(ManuNo)) + { + query = query.Where(cs => cs.ManuNo.Equals(ManuNo) || cs.Quantity == 0); + } + } + + + return await query.OrderBy((cs) => cs.EffDate) + .ThenBy((cs) => cs.DrawerNo) + .ThenBy((cs) => cs.ColNo) + .ToListAsync(); + } + + /// + /// 保存自选取药完成数据 + /// + /// + /// + public async Task OrderTakeFinish(List datas, OrderInfo order) + { + + try + { + _connection.BeginTransaction(); + var flag = true; + // 保存处方信息 + order.Status = 1; + order.PatientId = order.PatientId == null ? "0" : order.PatientId; + int r1 = _connection.InsertWithInt32Identity(order); + if (!(r1 > 0)) + { + flag = false; + logger.Error("处方取药完成更新处方状态失败"); + _connection.RollbackTransaction(); + return flag; + } + for (var i = 0; i < datas.Count; i++) + { + var orderTakeVo = datas[i]; + //保存处方明细 + orderTakeVo.OrderDetail.PatientId = orderTakeVo.OrderDetail.PatientId == null ? order.PatientId : orderTakeVo.OrderDetail.PatientId; + orderTakeVo.OrderDetail.ChargeDate = orderTakeVo.OrderDetail.ChargeDate == null ? order.ChargeDate : orderTakeVo.OrderDetail.ChargeDate; + orderTakeVo.OrderDetail.OrderNo = order.OrderNo; + orderTakeVo.OrderDetail.DrugId = orderTakeVo.Drug.DrugId; + orderTakeVo.OrderDetail.SetManuNo = orderTakeVo.ChannelStock.ManuNo; + orderTakeVo.OrderDetail.SetEffDate = orderTakeVo.ChannelStock.EffDate; + int od = _connection.InsertWithInt32Identity(orderTakeVo.OrderDetail); + // 出库记录 + int mid = _connection.InsertWithInt32Identity(new MachineRecord() + { + MachineId = _setting.machineId, + DrawerNo = orderTakeVo.ChannelStock.DrawerNo, + ColNo = orderTakeVo.ChannelStock.ColNo, + DrugId = orderTakeVo.ChannelStock.DrugId, + ManuNo = orderTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(orderTakeVo.ChannelStock.EffDate) ? DateTime.ParseExact(orderTakeVo.ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + Quantity = orderTakeVo.GetQuantity, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + InvoiceId = orderTakeVo.OrderDetail.Id.ToString(), + }); + // 更新库存 + int r = _connection.ChannelStock.Where(cs => cs.Id == orderTakeVo.ChannelStock.Id) + .Set(cs => cs.Quantity, orderTakeVo.ChannelStock.Quantity - orderTakeVo.GetQuantity) + .Update(); + // 获取更新完库存之后的药品库存 + List list = await _connection.ChannelStock.AsQueryable() + .InnerJoin( + _connection.ChannelList.Where(cl => cl.MachineId.Equals(_setting.machineId)).Where(cl => cl.DrawerType == 1), + (cs, cl) => cs.ListId == cl.Id, + (cs, cl) => cs + ) + .Where(cs => cs.DrugId.Equals(orderTakeVo.ChannelStock.DrugId)) + .ToListAsync(); + // 保存账册 + int acid = _connection.InsertWithInt32Identity(new AccountBook() + { + MachineId = _setting.machineId, + DrugId = orderTakeVo.ChannelStock.DrugId, + ManuNo = orderTakeVo.ChannelStock.ManuNo, + EffDate = !String.IsNullOrEmpty(orderTakeVo.ChannelStock.EffDate) ? DateTime.ParseExact(orderTakeVo.ChannelStock.EffDate, "yyyy-MM-dd", System.Globalization.CultureInfo.CurrentCulture) : null, + OperationTime = DateTime.Now, + Type = 2, + OutQuantity = orderTakeVo.GetQuantity, + AddQuantity = 0, + Operator = _globalStateService.Operator.Id, + Reviewer = _globalStateService.Reviewer?.Id ?? _globalStateService.Operator.Id, + ManuStock = list.Where(it => it.ManuNo == orderTakeVo.ChannelStock.ManuNo).Sum(it => it.Quantity), + TotalStock = list.Sum(it => it.Quantity), + InvoiceId = orderTakeVo.OrderDetail.Id.ToString() + }); + if (mid > 0 && r > 0 && acid > 0) + { + //根据抽屉类型判断是否需要写标签 + if (orderTakeVo.ChannelStock.BoardType.ToString().Contains("5")) + { + await _portUtil.WriteQuantityMethod(orderTakeVo.ChannelStock.Quantity - orderTakeVo.GetQuantity, orderTakeVo.ChannelStock.DrawerNo, orderTakeVo.ChannelStock.ColNo); + } + } + else + { + flag = false; + break; + } + } + if (flag) + { + _connection.CommitTransaction(); + } + else + { + _connection.RollbackTransaction(); + } + return flag; + + } + catch (Exception ex) + { + logger.Error("自选取药完成保存数据库失败,错误:" + ex.Message); + _connection.RollbackTransaction(); + return false; + } + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/SettingManuDao.cs b/MasaBlazorApp3/DataAccess/Impl/SettingManuDao.cs new file mode 100644 index 0000000..67ea73f --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/SettingManuDao.cs @@ -0,0 +1,37 @@ +using LinqToDB; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Port; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class SettingManuDao : ISettingManuDao + { + private AppDataConnection _connection; + private readonly SettingConfig _setting; + private GlobalStateService _globalStateService; + public SettingManuDao(AppDataConnection connection, IOptions setting, GlobalStateService globalStateService, PortUtil portUtil) + { + _globalStateService = globalStateService; + _connection = connection; + _setting = setting.Value; + } + public async Task> GetMenuItemsAsync() + { + var query = _connection.SettingManu.Where(s=>s.UseStatus==1).AsQueryable(); + + + return await query + .OrderBy((sm) => sm.Id) + .ToListAsync(); + } + } +} diff --git a/MasaBlazorApp3/DataAccess/Impl/UserDao.cs b/MasaBlazorApp3/DataAccess/Impl/UserDao.cs new file mode 100644 index 0000000..ad18e9e --- /dev/null +++ b/MasaBlazorApp3/DataAccess/Impl/UserDao.cs @@ -0,0 +1,198 @@ +using Google.Protobuf.WellKnownTypes; +using LinqToDB; +using log4net; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.Pojo; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Util; +using Microsoft.Extensions.Options; +using System.Data; +using System.Xml.Linq; + +namespace MasaBlazorApp3.DataAccess.Impl +{ + public class UserDao : IUserDao + { + + //private MyContext Context; + + private readonly AppDataConnection _connection; + private readonly SettingConfig _setting; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderInfoDao)); + + //public UserDao(MyContext context) + //{ + // Context = context; + //} + public UserDao(AppDataConnection connection, IOptions setting) + { + _connection = connection; + _setting = setting.Value; + } + + public async Task> GetAllByNickname(string nickname, int? take, int? skip) + { + var query = _connection.User.AsQueryable(); + + if (!String.IsNullOrEmpty(nickname)) + { + query = query.Where(r => r.NickName.IndexOf(nickname) > -1); + } + query = query.Where(u => u.MachineId == _setting.machineId); + + List list = await query + .LoadWith(u => u.role) + .OrderBy(u => u.Id) + .Skip((int)skip) + .Take((int)take) + .ToListAsync(); + int pagedData = await query.CountAsync(); + return new PageData() + { + + TotalDesserts = pagedData, + Desserts = list + }; + } + + public User GetById(int id) + { + return _connection.User.LoadWith(u => u.role).FirstOrDefault(u => u.Id == id); + } + + public User GetByUsername(string username) + { + + return _connection.User.LoadWith(u => (u.role)).FirstOrDefault(u => u.Username == username && u.MachineId == _setting.machineId); + } + + public int InsertUser(User user) + { + user.MachineId = _setting.machineId; + user.Password = MD5.GetMD5Hash("123456").ToLower(); + return _connection.InsertWithInt32Identity(user); + } + + public bool UpdateUser(User user) + { + var statement = _connection.User + .Where(u => u.Id == user.Id) + .Set(u => u.NickName, user.NickName) + .Set(u => u.Username, user.Username) + .Set(u => u.RoleId, user.RoleId); + //if(!String.IsNullOrEmpty(user.Password)) + //{ + // statement.Set(u => user.Password, MD5.GetMD5Hash(user.Password).ToLower()); + //} + return statement.Update() > 0; + } + + public bool DeleteeUser(int id) + { + return _connection.User.Where(u => u.Id == id).Delete() > 0; + } + //重置用户密码 + public bool ResetPassword(int id) + { + var statement = _connection.User.Where(u => u.Id == id).Set(u => u.Password, MD5.GetMD5Hash("123456").ToLower()); + return statement.Update() > 0; + } + + public async Task UpdateSign(int id, string sign) + { + var statement = _connection.User + .Where(u => u.Id == id) + .Set(u => u.Sign, Convert.FromBase64String(sign)); + //if(!String.IsNullOrEmpty(user.Password)) + //{ + // statement.Set(u => user.Password, MD5.GetMD5Hash(user.Password).ToLower()); + //} + return (await statement.UpdateAsync()) > 0; + } + //修改密码 + public bool UpdateUserPassword(User user) + { + var statement = _connection.User + .Where(u => u.Id == user.Id) + .Set(u => u.Password, MD5.GetMD5Hash(user.Password).ToLower()); + return statement.Update() > 0; + } + + //查询当前值班信息 + public HkcChangeShifts GetOnDuty() + { + try + { + return _connection.HkcChangeShifts.Where(cs => cs.MachineId == _setting.machineId && cs.State == "0").FirstOrDefault(); + + } + catch (Exception ex) + { + logger.Info($"查询当前值班信息异常{ex.Message}"); + return null; + } + } + //保存交接班信息 + public async Task UpdateChangeShift(HkcChangeShifts changeShift, HkcChangeShifts changeShiftNew) + { + try + { + _connection.BeginTransaction(); + var insertResult = _connection.InsertWithInt32Identity(changeShiftNew); + + int updateResult = _connection.HkcChangeShifts + .Where(cs => cs.Id == changeShift.Id) + .Set(cs => cs.State, "1") + .Set(cs => cs.ToDate, DateTime.Now) + .Set(cs => cs.ToOperator, changeShift.ToOperator).Update(); + + //插入交接班时药品数据信息 + var channelStockList = _connection.ChannelStock + .Where(cs => (cs.MachineId == _setting.machineId || cs.MachineId == _setting.boxMachineId) && cs.DrawerType == 1) + .GroupBy(cs => cs.DrugId) + .Select(g => new + { + drugId = g.Key, + sumQuantity = g.Sum(cs => cs.Quantity) + }).ToList(); + + if (channelStockList != null && channelStockList.Count > 0) + { + //将药品库存信息写入交接明细表 + for (int i = 0; i < channelStockList.Count; i++) + { + //查询药品上次交接的明细,用于记录处方数 + HkcChangeShiftsDetail? historyList = _connection.HkcChangeShiftsDetail + .Where(d => d.DrugId == channelStockList[i].drugId && d.ChangeshiftsId == changeShift.Id).FirstOrDefault(); + + HkcChangeShiftsDetail detail = new HkcChangeShiftsDetail() + { + ChangeshiftsId = insertResult, + DrugId = channelStockList[i].drugId, + RealNumber = channelStockList[i].sumQuantity, + OrderNumber = historyList != null ? historyList.OrderNumber + historyList.RealNumber - channelStockList[i].sumQuantity : 0 + }; + var insertDetailResult = _connection.InsertWithInt32Identity(detail); + } + } + + + if (insertResult <= 0 || updateResult <= 0) + { + _connection.RollbackTransaction(); + return false; + } + else + { + _connection.CommitTransaction(); + return true; + } + } + catch (Exception ex) + { + logger.Error($"更新交接班信息异常: {ex.Message}"); + return false; + } + } + } +} diff --git a/MasaBlazorApp3/DataAccess/PageData.cs b/MasaBlazorApp3/DataAccess/PageData.cs new file mode 100644 index 0000000..1cab9b4 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/PageData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess +{ + public class PageData + { + public int TotalDesserts { get; set; } + public List Desserts { get; set; } = new List(); + } +} diff --git a/MasaBlazorApp3/DataAccess/PageMultiData.cs b/MasaBlazorApp3/DataAccess/PageMultiData.cs new file mode 100644 index 0000000..da34870 --- /dev/null +++ b/MasaBlazorApp3/DataAccess/PageMultiData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.DataAccess +{ + public class PageMultiData + { + public int TotalDesserts { get; set; } + public List Desserts { get; set; } = new List(); + public List Other { get; set; } = new List(); + } +} diff --git a/MasaBlazorApp3/Finger/FingerprintUtil.cs b/MasaBlazorApp3/Finger/FingerprintUtil.cs new file mode 100644 index 0000000..7f31910 --- /dev/null +++ b/MasaBlazorApp3/Finger/FingerprintUtil.cs @@ -0,0 +1,139 @@ +using log4net; +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using zkemkeeper; +using Microsoft.Extensions.Options; +using MasaBlazorApp3.Pojo.Config; + +namespace MasaBlazorApp3.Finger +{ + public class FingerprintUtil + { + + private readonly ILog logger = LogManager.GetLogger(typeof(FingerprintUtil)); + private readonly FingerPojo _options; + + public CZKEMClass axCZKEM1 = new CZKEMClass(); + public bool bIsConnected = false; + + private int fingerPort = 4370; + private int machineNumber = 1; + private int machineType = 2; + + public FingerprintUtil(IOptions options) + { + _options = options.Value; + logger.Info($"进入构造器,开始连接指纹机"); + // ConnectionMain(); + } + + public async Task ConnectionMain() + { + return await Task.Run(() => + { + + bIsConnected = axCZKEM1.Connect_Net(_options.ip, fingerPort); + logger.Info($"连接指纹机,IP:{_options.ip},端口:{fingerPort},机器号:{machineNumber},连接结果:{bIsConnected}"); + if (bIsConnected) + { + if (axCZKEM1.RegEvent(machineNumber, 65535)) + { + this.axCZKEM1.OnAttTransactionEx += new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx); + //this.axCZKEM1.OnEnrollFinger += new zkemkeeper._IZKEMEvents_OnEnrollFingerEventHandler(axCZKEM1_OnEnrollFinger); + this.axCZKEM1.OnEnrollFingerEx += new zkemkeeper._IZKEMEvents_OnEnrollFingerExEventHandler(axCZKEM1_OnEnrollFingerEx); + + } + } + return bIsConnected; + }); + + + } + + //If your fingerprint(or your card) passes the verification,this event will be triggered + private void axCZKEM1_OnAttTransactionEx(string sEnrollNumber, int iIsInValid, int iAttState, int iVerifyMethod, int iYear, int iMonth, int iDay, int iHour, int iMinute, int iSecond, int iWorkCode) + { + + logger.Info($"触发用户验证通过事件,用户id:{sEnrollNumber}验证方式:{iVerifyMethod}"); + } + + //When you are enrolling your finger,this event will be triggered. + private void axCZKEM1_OnEnrollFinger(int iEnrollNumber, int iFingerIndex, int iActionResult, int iTemplateLength) + { + + axCZKEM1.StartIdentify(); + axCZKEM1.RefreshData(1); + + logger.Info($"触发用户登记指纹事件,用户id:{iEnrollNumber}指纹索引:{iFingerIndex}登记结果:{(iActionResult == 0)}"); + + } + + private void axCZKEM1_OnEnrollFingerEx(string iEnrollNumber, int iFingerIndex, int iActionResult, int iTemplateLength) + { + + axCZKEM1.StartIdentify(); + axCZKEM1.RefreshData(1); + logger.Info($"触发用户登记指纹事件1,用户id:{iEnrollNumber}指纹索引:{iFingerIndex}登记结果:{(iActionResult == 0)}"); + + } + + /** + * 删除用户 + */ + public bool DelUser(int Id) + { + bool result = false; + axCZKEM1.EnableDevice(machineNumber, false); + if (machineType == 1) + { + result = axCZKEM1.DeleteEnrollData(machineNumber, Id, machineNumber, 12); + } + else + { + result = axCZKEM1.SSR_DeleteEnrollData(machineNumber, Id.ToString(), 12); + } + + axCZKEM1.RefreshData(machineNumber); + axCZKEM1.EnableDevice(machineNumber, true); + return result; + } + + /** + * 添加或修改用户 + */ + public bool SaveUser(User User) + { + bool result = false; + //axCZKEM1.SetStrCardNumber(User.UserBarcode); + if (machineType == 1) + { + result = axCZKEM1.SetUserInfo(machineNumber, User.Id, User.NickName, "123456", 0, true); + } + else + { + result = axCZKEM1.SSR_SetUserInfo(machineNumber, User.Id.ToString(), User.NickName, "123456", 0, true); + } + return result; + } + + /** + * 添加或修改用户指纹 + */ + public bool SaveFingerprint(int Id, int FingerIndex) + { + bool result = false; + // 取消其他操作 + bool res2 = axCZKEM1.CancelOperation(); + // 删除源指纹 + bool res = axCZKEM1.SSR_DelUserTmp(machineNumber, Id.ToString(), FingerIndex); + // 添加新指纹 + result = axCZKEM1.StartEnrollEx(Id.ToString(), FingerIndex, 3); + return result; + } + } +} diff --git a/MasaBlazorApp3/GlobalStateService.cs b/MasaBlazorApp3/GlobalStateService.cs new file mode 100644 index 0000000..710af3a --- /dev/null +++ b/MasaBlazorApp3/GlobalStateService.cs @@ -0,0 +1,42 @@ +using System.ComponentModel; +using MasaBlazorApp3.Pojo; + +namespace MasaBlazorApp3 +{ + public class GlobalStateService : INotifyPropertyChanged + { + private User _operator; + private User _reviewer; + + public User Operator + { + get { return _operator; } + set + { + _operator = value; + //OnPropertyChanged(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Operator")); + } + } + + public User Reviewer + { + get => _reviewer; + set + { + _reviewer = value; + //OnPropertyChanged(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Reviewer")); + } + } + + public bool isInit { get; set; } = false; + + public event PropertyChangedEventHandler? PropertyChanged; + + //protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + //{ + + //} + } +} diff --git a/MasaBlazorApp3/MasaBlazorApp3.csproj b/MasaBlazorApp3/MasaBlazorApp3.csproj new file mode 100644 index 0000000..19004af --- /dev/null +++ b/MasaBlazorApp3/MasaBlazorApp3.csproj @@ -0,0 +1,106 @@ + + + + Exe + net7.0 + enable + enable + favicon.ico + AnyCPU;x64 + + + + + tlbimp + 0 + 1 + fe9ded34-e159-408e-8490-b720a5e632c7 + 0 + false + False + + + tlbimp + 0 + 6 + 4018f953-1bfe-441e-8a04-dc8ba1ff060e + 0 + false + False + + + + + + + + + + + + + + + + + + + + + Always + + + + + + Always + + + Always + + + + + + + + + + + + + + Always + + + + + + Always + + + Always + + + PreserveNewest + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + diff --git a/MasaBlazorApp3/Pages/BiaoDing.razor b/MasaBlazorApp3/Pages/BiaoDing.razor new file mode 100644 index 0000000..2186971 --- /dev/null +++ b/MasaBlazorApp3/Pages/BiaoDing.razor @@ -0,0 +1,256 @@ +@page "/stock/biaoDing" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Util; +@using Microsoft.AspNetCore.Components +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + +
+ @if (DrawerNos.Count() > 8) + { +
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
+ } + else + { +
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
+ } + +
+ + + + @if (status < 3) + { + + } + @if (status > 0 && status <= 3) + { + + } + + + + + + + + + + + + + + + + + + +
+@code { + @inject IChannelListDao channelListDao; + @inject NavigationManager na; + @inject PortUtil PortUtil; + @inject NotificationService _message + @inject IOptions setting; + @inject DialogService dialogService; + int status = 0; + int drawerNo = 0; + RadzenDataGrid grid; + private List? channels; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + private readonly ILog logger = LogManager.GetLogger(typeof(BiaoDing)); + + // 当前操作的库位号列表 + public List ColNos { get; set; } = new List(); + //当前操作的库位数据 + ChannelStock currentChannelStock; + bool CompleteIsEnable = true; + bool CancleIsEnable = true; + + void SelectDrawer(int drawerNo) + { + this.drawerNo = drawerNo; + grid.Reload(); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + if (drawerNo > 0) + { + var result = await channelListDao.GetChannelStockByBiaoDing(drawerNo); + DrawerNos = result.DrawerArray; + channels = result.ChannelStocks; + count = result.ChannelStocks.Count; + } + + isLoading = false; + } + async Task OpenDrawer() + { + this.status = 1; + var promiseUtil = new PromiseUtil(); + await promiseUtil.taskAsyncLoop(300, null, async (data, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + else + { + if (this.status == 1) + { + PortUtil.DrawerNo = this.drawerNo; + var b = await PortUtil.OpenDrawerStatus(this.drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请选择库位开药盒"); + this.status = 2; + PortUtil.Operate = true; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + RestData(); + PortUtil.Operate = false; + stop(); + } + } + else + { + //查询抽屉状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + if (!b) + { + if (this.status == 2) + { + //药盒称重抽屉 + if (currentChannelStock != null && currentChannelStock.BoardType.ToString().Contains("3")) + { + //打开药盒 + await PortUtil.OpenBoxByColNo(currentChannelStock.ColNo); + this.status = 3; + } + } + if (this.status == 3) + { + this.status = 4; + //弹出标定对话框 + var dialog = await dialogService.OpenAsync( + $"标定库位{currentChannelStock.ColNo}", + new Dictionary() { { "channelStockInfo", + currentChannelStock } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + currentChannelStock = null; + //关闭弹窗后将状态置为2以便下次点击药盒进行开药盒操作 + this.status = 2; + } + next(); + } + else + { + //抽屉已关闭 + stop(); + this.status = 0; + logger.Info($"抽屉关闭"); + } + } + } + } + catch (Exception e) + { + logger.Info($"标定药品发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + PortUtil.AllLightOff(); + } + RestData(); + stop(); + } + }); + } + void RestData() + { + this.status = 0; + } + void Cancel() + { + this.status = 0; + } + + void OnCellClick(DataGridCellMouseEventArgs args) + { + if (this.status == 0) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("请先打开抽屉后再点开药盒"); + } + else + { + currentChannelStock = args.Data; + if (args.Data.BoardType.ToString().Contains("3")) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("正在打开药盒"); + } + // else + // { + // grid.EditRow(args.Data); + // } + } + } +} diff --git a/MasaBlazorApp3/Pages/BiaoDingDialog.razor b/MasaBlazorApp3/Pages/BiaoDingDialog.razor new file mode 100644 index 0000000..b4a4da7 --- /dev/null +++ b/MasaBlazorApp3/Pages/BiaoDingDialog.razor @@ -0,0 +1,194 @@ +@using MasaBlazorApp3.Util +@using log4net + + + @* *@ +
+
+ + @if (channelStockInfo.Quantity>0) + { + 库位库存不为零,请取出药品后点击【清空】按钮,清空完成后输入标定数量并放入对应数量药品并根据下一步提示操作 + } + else + { + 正在清零,清零完成后输入标定数量并放入对应数量药品后点击【标定】按钮 + } + + +
+
+ @*
*@ + + + + + 0) Style="width: 120px" /> + + + + +
+ +@code { + @inject Radzen.DialogService dialogService; + @inject NotificationService _message + @inject PortUtil PortUtil; + [Parameter] public ChannelStock channelStockInfo { get; set; } + + PromiseUtil promiseUtil = new PromiseUtil(); + private readonly ILog logger = LogManager.GetLogger(typeof(BiaoDingDialog)); + + int BDQuantity = 10; + + int status = 0; + int iClear = 0; + int iBiaoDing = 0; + int iClearFinish = 1; + protected override async Task OnInitializedAsync() + { + if(channelStockInfo!=null&&channelStockInfo.Quantity<=0) + { + //库存为零,直接进行清空操作 + await Clear(); + } + base.OnInitializedAsync(); + } + //清空按钮 + async Task Clear() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"正在清空,请稍等"); + + this.status = 1; + int i = 0; + await promiseUtil.taskAsyncLoop(200, null, async (data, next, stop) => + { + i++; + if (this.status == 0) + { + iClear = 0; + stop(); + } + else + { + try + { + if (iClear == 0) + { + logger.Info($"清零操作{i}"); + //无库存发送计数清零指令 + await PortUtil.ClearCount(channelStockInfo.DrawerNo, channelStockInfo.ColNo); + iClear += 1; + next(); + } + else + { + logger.Info($"查数操作{i}"); + //发查数指令 + PortUtil.DrawerNo = channelStockInfo.DrawerNo; + PortUtil.Operate = true; + int stock = await PortUtil.CheckQuantityForBiaoDing(channelStockInfo.ColNo); + if (stock != 0) + { + _message.Notify( + new NotificationMessage + { Severity = NotificationSeverity.Success, Summary = "提示", Detail = "清空操作成功", Duration = 3000 } + ); + + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("清空完成,请放入10个药品,放好后点击标定按钮"); + iClear = 0; + iClearFinish = 0; + stop(); + } + else + { + next(); + } + } + } + catch (Exception ex) + { + logger.Info($"清空操作异常"); + next(); + } + } + + }); + } + //标定按钮 + async Task ConfirmOK() + { + if (BDQuantity > 0) + { + try + { + status = 2; + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("正在标定,请稍等"); + //提示输入标定数量,发26指令 + await PortUtil.SetNumCount(channelStockInfo.DrawerNo, channelStockInfo.ColNo, BDQuantity); + await Task.Delay(200); + int i = 1; + await promiseUtil.taskAsyncLoop(200, null, async (data, next, stop) => + { + if(status==0) + { + stop(); + } + if (status == 2) + { + //查数量 + int quantity = await PortUtil.CheckQuantityForBiaoDing(channelStockInfo.ColNo); + if (quantity == BDQuantity) + { + //标定完成 + status = 0; + _message.Notify( + new NotificationMessage + { Severity = NotificationSeverity.Success, Summary = "提示", Detail = "标定成功", Duration = 3000 } + ); + + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("标定完成,请取出药品"); + status = 0; + i = 0; + stop(); + // 关闭弹窗 + dialogService.Close(true); + } + else + { + i++; + logger.Info($"标定数量不一致{quantity}-{BDQuantity},标定次数{i}"); + next(); + } + + } + }); + } + catch (Exception ex) + { + logger.Error($"标定异常{ex.Message}"); + _message.Notify( + new NotificationMessage + { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "标定异常", Duration = 3000 } + ); + } + } + else + { + _message.Notify( + new NotificationMessage + { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "请输入标定数量", Duration = 3000 }); + } + } + // 取消 + async Task CancelClick() + { + status = 0; + // 关闭弹窗 + dialogService.Close(true); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxAddBox.razor b/MasaBlazorApp3/Pages/BoxAddBox.razor new file mode 100644 index 0000000..c001ea3 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxAddBox.razor @@ -0,0 +1,150 @@ +@page "/Box/BoxAddBox" + + + +
+ + + + + + + + + + +
+ +@code { + @inject IChannelListDao channelStockDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime start; + DateTime end; + + IList selectedChannelLists; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelStockDao.GetBoxWaitInfo(args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + isLoading = false; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + // await grid.ExpandRows(grid.PagedView.Where(di => di.Stocks.Count > 0)); + } + } + void RowRender(RowRenderEventArgs args) + { + args.Expandable = args.Data.ChannelStocks.Count > 0; + } + + async void OnRowSelect(ChannelList cl) + { + var b = await dialogService.OpenAsync( + $"{cl.DrawerNo}号药盒药品入库", + new Dictionary() { { "boxChannelList", cl } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await grid.Reload(); + } + } + + + async void StockExport() + { + + } + + async void AccountBookExport() + { + + } + + + +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxAddBoxDetailDialog.razor b/MasaBlazorApp3/Pages/BoxAddBoxDetailDialog.razor new file mode 100644 index 0000000..a56fd0c --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxAddBoxDetailDialog.razor @@ -0,0 +1,301 @@ +@page "/Box/BoxAddBoxDetail" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + + + + + + + + + + + + + + + + + + + + + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IChannelListDao channelListDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + // int status; + bool isLoading; + int count; + [Parameter] public ChannelList boxChannelList { get; set; } + + List channelStockList = new List(); + + public List data { get; set; } + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + + protected override async Task OnInitializedAsync() + { + channelStockList = await channelListDao.GetBoxAddToBox(boxChannelList); + base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + data = await channelListDao.getBoxWaitByBox(boxChannelList, args.Top, args.Skip); + // Update the Data property + isLoading = false; + } + // async Task OpenDrawer() + // { + // this.status = 1; + // // 解析需要打开的抽屉列表 + // List drawerNos = this.data.GroupBy(it => it.ChannelStock.DrawerNo).Select(it => it.First()).ToList(); + + // // 根据抽屉类型来决定打开前是否需要查询数量 + // var promiseUtil = new PromiseUtil(); + + // await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + // { + // var orderTakeVo = drawerNos[options._data]; + // var drawerNo = orderTakeVo.ChannelStock.DrawerNo; + // try + // { + // if (this.status == 0) + // { + // stop(); + // } + // // 开启抽屉 + // else if (this.status == 1) + // { + // if (orderTakeVo.Status == 0) + // { + // // 判断是否为单支抽屉 + // if (setting.Value.single.Contains(drawerNo)) + // { + // byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + // orderTakeVo.BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + // logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + + // await PortUtil.HasLightOnByCol(drawerNo, data.Where(ot => ot.ChannelStock.DrawerNo == drawerNo).Select(ot => ot.ChannelStock.ColNo).ToArray()); + // } + // for (int i = 0; i < data.Count; i++) + // { + // if (!DrawerNoColNoList.Contains(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo)) + // { + // if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + // { + // PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + // PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + // data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + // logger.Info($"称重抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + // await Task.Delay(200); + // } + + // //是药盒抽屉开药盒 + // if (data[i].ChannelStock.BoardType.ToString().Contains("3")) + // { + // PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + // await PortUtil.OpenBoxByColNo(data[i].ChannelStock.ColNo); + // await Task.Delay(200); + // } + // DrawerNoColNoList.Add(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo); + // } + // } + // var b = await PortUtil.OpenDrawerStatus(drawerNo); + // if (b) + // { + // PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + // PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + // orderTakeVo.Status = 1; + // next(); + // } + // else + // { + // _message.Notify( + // new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + // ); + // logger.Info($"抽屉打开失败"); + // PortUtil.AllLightOff(); + // RestData(); + // stop(); + // } + // } + // // 检测状态 + // else if (orderTakeVo.Status == 1) + // { + // // 查询抽屉是否为关闭状态 + // var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // // 关闭则改变状态并终止循环 + // if (b) + // { + + // data.ForEach(cl => + // { + // if (cl.ChannelStock.DrawerNo == drawerNo) + // { + // cl.GetQuantity = cl.Quantity; + + // } + // }); + // orderTakeVo.Status = 2; + // PortUtil.AllLightOff(); + // if (options._data == drawerNos.Count - 1) + // { + // PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + // PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + // PortUtil.SpeakAsync($"取药完成,请,点击完成按钮进行确认"); + // this.status = 2; + // string alertMessage = string.Empty; + // //检查是否称重抽屉,核对实际取出数量是否与应取数量一致,不一致则弹出提示 + // for (int i = 0; i < data.Count; i++) + // { + // if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + // { + // PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo;// drawerNo; + // PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + // orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + // logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + // WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + // if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + // { + // //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + // alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + + // } + // await Task.Delay(200); + // } + + // if (data[i].ChannelStock.BoardType.ToString().Contains("2")) + // { + // byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + // orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + // logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + // WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = orderTakeVo.BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + // if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + // { + // alertMessage += $"{data[i].Drug.DrugName}应取数量【{orderTakeVo.Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + // } + // } + // } + // if (!string.IsNullOrEmpty(alertMessage)) + // { + // //弹出确认对话框 + // alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + // //弹出确认提示框 + // var confirm = await dialogService.OpenAsync( + // $"保存确认", + // new Dictionary() { { "confirmInfo", alertMessage } }, + // new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + // logger.Info(alertMessage); + // if (!confirm) + // { + // RestData(); + // logger.Info("取消保存"); + // // 关闭弹窗 + // dialogService.Close(false); + // } + // } + // stop(); + // } + // else + // { + // options._data += 1; + // next(); + // } + // } + // else + // { + // next(); // continue iteration + // } + // } + + + // } + + // } + // catch (Exception e) + // { + // RestData(); + // logger.Info($"{boxChannelList.DrawerNo}药盒取药发生错误,{e.Message}"); + // _message.Notify( + // new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + // ); + // if (setting.Value.single.Contains(drawerNo)) + // { + // PortUtil.AllLightOff(); + // } + // stop(); + // } + // }); + // } + + void Cancel() + { + // 关闭弹窗 + dialogService.Close(false); + } + async Task Finish() + { + + // 保存账册、操作记录 + var b = await channelListDao.BoxAddBoxFinish(boxChannelList); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"手术室药盒取药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + } + + +} diff --git a/MasaBlazorApp3/Pages/BoxAddDetailDialog.razor b/MasaBlazorApp3/Pages/BoxAddDetailDialog.razor new file mode 100644 index 0000000..f8f7cc6 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxAddDetailDialog.razor @@ -0,0 +1,341 @@ +@page "/Box/BoxAddDetail" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + @* + 处方号: + @(order?.OrderNo) + 患者姓名: + @(order?.PatientName) + 性别: + @(order?.Sex) + 年龄: + @(order?.Age) + + *@ + @if (CanTakeDrug) + { + + + + + + + + + + + + + } + else + { + + + + + + + + + } + + + + + + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status <= 2) + { + + } + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IChannelListDao channelListDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + int status; + + [Parameter] public ChannelList boxChannelList { get; set; } + private bool CanTakeDrug = true; + + public List data { get; set; } + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + + protected override async Task OnInitializedAsync() + { + data = await channelListDao.getTakeInfoByBox(boxChannelList); + // 如果有【stockQuantity】字段说明有药品库存不足 + if (data.Any(it => it.ChannelStock == null)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + List drawerNos = this.data.GroupBy(it => it.ChannelStock.DrawerNo).Select(it => it.First()).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + + await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + { + var orderTakeVo = drawerNos[options._data]; + var drawerNo = orderTakeVo.ChannelStock.DrawerNo; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (orderTakeVo.Status == 0) + { + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + + await PortUtil.HasLightOnByCol(drawerNo, data.Where(ot => ot.ChannelStock.DrawerNo == drawerNo).Select(ot => ot.ChannelStock.ColNo).ToArray()); + } + for (int i = 0; i < data.Count; i++) + { + if (!DrawerNoColNoList.Contains(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo)) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + await Task.Delay(200); + } + + //是药盒抽屉开药盒 + if (data[i].ChannelStock.BoardType.ToString().Contains("3")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + await PortUtil.OpenBoxByColNo(data[i].ChannelStock.ColNo); + await Task.Delay(200); + } + DrawerNoColNoList.Add(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo); + } + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + orderTakeVo.Status = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (orderTakeVo.Status == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + + data.ForEach(cl => + { + if (cl.ChannelStock.DrawerNo == drawerNo) + { + cl.GetQuantity = cl.Quantity; + + } + }); + orderTakeVo.Status = 2; + // if (data.Any(it => it.ChannelStock.BoardType.ToString().Contains("2"))) + // { + // //有单支抽屉则广播灭灯 + // PortUtil.AllLightOff(); + // } + if (options._data == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"取药完成,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + //检查是否称重抽屉,核对实际取出数量是否与应取数量一致,不一致则弹出提示 + for (int i = 0; i < data.Count; i++) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo;// drawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + + } + await Task.Delay(200); + } + + if (data[i].ChannelStock.BoardType.ToString().Contains("2") && data[i].ChannelStock.DrawerNo == drawerNo) + { + + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = orderTakeVo.BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}库位{data[i].ChannelStock.ColNo}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + } + } + } + + //有单支抽屉则广播灭灯 + PortUtil.PowerOff(); + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + // //弹出确认提示框 + var confirm = await dialogService.OpenAsync( + $"保存确认", + new Dictionary() { { "confirmInfo", alertMessage } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + logger.Info(alertMessage); + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + // 关闭弹窗 + dialogService.Close(false); + } + } + stop(); + } + else + { + options._data += 1; + next(); + } + } + else + { + next(); // continue iteration + } + } + + + } + + } + catch (Exception e) + { + RestData(); + logger.Info($"{boxChannelList.DrawerNo}药盒取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + data.ForEach(it => + { + it.Status = 0; + it.BeforeQuantity = new int[9]; + it.AfterQuantity = new int[9]; + }); + this.WeightFinnalQuantity = new int[9]; + DrawerNoColNoList.Clear(); + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task TakeFinish() + { + + // 保存账册、操作记录 + var b = await channelListDao.BoxTakeFinish(data, boxChannelList); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"手术室药盒取药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + +} diff --git a/MasaBlazorApp3/Pages/BoxAddDrug.razor b/MasaBlazorApp3/Pages/BoxAddDrug.razor new file mode 100644 index 0000000..bfe05e2 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxAddDrug.razor @@ -0,0 +1,197 @@ +@page "/Box/BoxAdd" +@using MasaBlazorApp3.Report +@using Radzen.Blazor.Rendering + + +
+@* + + + + + + + + + + + + + + + + + + + + + + + + + *@ + + + + + + + + + +
+ +@code { + @inject IChannelListDao channelStockDao; + @inject DialogService dialogService; + @inject IReportDataDao reportDataDao; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime start; + DateTime end; + RadzenButton button; + Popup popup; + IList selectedChannelLists; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelStockDao.GetAllBoxAddDrug(args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + isLoading = false; + } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + // await grid.ExpandRows(grid.PagedView.Where(di => di.Stocks.Count > 0)); + } + } + + void RowRender(RowRenderEventArgs args) + { + args.Expandable = args.Data.ChannelStocks.Count > 0; + } + + async void OnRowSelect(ChannelList cl) + { + var b = await dialogService.OpenAsync( + cl.DrawerNo==99?"急诊药盒":cl.DrawerNo==111?"恢复室药盒":$"{cl.DrawerNo}-{(cl.ColNo==1?'白':'绿')} 药盒加药", + new Dictionary() { { "boxChannelList", cl } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await grid.Reload(); + } + } + + + + //请领登记表导出 + async Task AccountBookExport() + { + // string drugId = drugName != null ? drugName.Split('/').Last().Trim():""; + // GridReportUtil gridReportUtil = new GridReportUtil(); + PageData pageData = await reportDataDao.GetApplyInfoDate(start); + GridReportUtil.PrintReport("account_book_temp.grf", pageData); + } + + + +} diff --git a/MasaBlazorApp3/Pages/BoxBind.razor b/MasaBlazorApp3/Pages/BoxBind.razor new file mode 100644 index 0000000..e34c698 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxBind.razor @@ -0,0 +1,278 @@ +@page "/Box/BoxBindings" + + +
+ +
+
+ @* + + 选择套餐 + + + + + + + + + + *@ +
+ + + + + + + + + + + + + + @* *@ + + + + +
+
+
+
+
+ + + + +
+
+
+ +@code { + @inject IChannelListDao channelListDao; + @inject IDrugInfoDao drugInfoDao; + @inject DialogService dialogService; + @inject NotificationService _message + @inject IPlanDao planDao; + RadzenDataList grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + + List drugInfos; + List drugManuNos; + + DrugInfo drugInfo; + + DrugManuNo drugManuNo; + + + List plans; + int firstFlag = 0; + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + var resultPlan = await planDao.GetAllPlanInfo(); + plans = resultPlan.Desserts.Where(p => p._PlanDetails.Count > 0).ToList(); + firstFlag = 0; + + } + + async Task LoadData(LoadDataArgs args) + { + + isLoading = true; + + var result = await channelListDao.GetAllChannelListWithPlan(args.Top, args.Skip); + + // Update the Data property + _forecasts = result.Desserts; + + // Update the count + count = result.TotalDesserts; + + isLoading = false; + + plans = result.Other; + } + + async Task reloadGrid() + { + await grid.Reload(); + } + + + + + // 默认选中的项 + private Plan selectedPlan = new(); + // 处理选择变更(可选) + private void OnPlanSelected(Plan plan) + { + selectedPlan = plan; + } + //绑定 + async Task EditChannel() + { + List bindList = _forecasts.Where(b => b.IsChecked).ToList(); + if (bindList == null || bindList.Count <= 0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请先选择药箱号再点击按钮", Duration = 4000 } + ); + return; + } + if (!string.IsNullOrEmpty(bindList[0].DrugId)) + { + //之前有绑定,在进行解绑 + foreach (var item in bindList) + { + var b = await channelListDao.UnBindBox(item); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"解除绑定成功", Duration = 4000 } + ); + } + await grid.Reload(); + } + } + else + {// 否则是进行解绑 + if (selectedPlan != null && selectedPlan.Id > 0) + { + foreach (var item in bindList) + { + var b = await channelListDao.BindBox(item, selectedPlan); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"绑定成功", Duration = 4000 } + ); + } + } + await grid.Reload(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择套餐", Duration = 4000 } + ); + + } + } + } + + + async Task CardClick(ChannelList list) + { + if (firstFlag == 0 && !(list.BoxDisabled)) + { + firstFlag = 1; + if (!string.IsNullOrEmpty(list.DrugId)) + { + list.IsChecked = !list.IsChecked; + //已绑药品需要解绑,未绑定的不可选 + if (list.IsChecked) + { + _forecasts.Where(it => it.DrugId != list.DrugId || it.TotalQuantity > 0).ToList().ForEach(it => it.BoxDisabled = true); + selectedPlan = await planDao.GetPlanById(Convert.ToInt32(list.DrugId)); + } + else + { + _forecasts.Where(it => it.TotalQuantity <= 0).ToList().ForEach(it => it.BoxDisabled = false); + firstFlag = 0; + } + + } + else + { + list.IsChecked = !list.IsChecked; + //未绑定药品则已绑定的不可选 + if (list.IsChecked) + { + _forecasts.Where(it => !string.IsNullOrEmpty(it.DrugId) || it.TotalQuantity > 0).ToList().ForEach(it => it.BoxDisabled = true); + } + else + { + _forecasts.ToList().Where(it => it.TotalQuantity <= 0).ToList().ForEach(it => it.BoxDisabled = false); + firstFlag = 0; + } + + } + + } + else + { + if (!list.BoxDisabled) + { + list.IsChecked = !list.IsChecked; + } + //isChecked==false 1)是否全部是false,是则将所有isChecked==true,不是则不做改变 + if (!_forecasts.Any(b => b.IsChecked == true)) + { + _forecasts.Where(it => it.TotalQuantity <= 0).ToList().ForEach(it => it.BoxDisabled = false); + firstFlag = 0; + } + } + await InvokeAsync(StateHasChanged); + } +} diff --git a/MasaBlazorApp3/Pages/BoxBindNew.razor b/MasaBlazorApp3/Pages/BoxBindNew.razor new file mode 100644 index 0000000..b7bc4f4 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxBindNew.razor @@ -0,0 +1,212 @@ +@page "/Box/BoxBindings123" + + +
+
+ +
+
+ @if (BoxList != null) + { + foreach (var item in BoxList) + { +
+ + @if(item.DrawerNo<51) + { + + } + else + { + + + } +
+ } + } +
+
+
+ + +
+ + + 选择套餐 + + + + + + + + + +
+
+
+ +@code { + @inject IChannelListDao channelListDao; + @inject IDrugInfoDao drugInfoDao; + @inject DialogService dialogService; + @inject NotificationService _message; + @inject IPlanDao planDao; + int count; + private List? _forecasts; + private List? BoxList; + + List drugInfos; + List drugManuNos; + + DrugInfo drugInfo; + + DrugManuNo drugManuNo; + + int firstFlag = 0; + + List plans; + // 默认选中的项 + private Plan selectedPlan = new(); + protected override async Task OnInitializedAsync() + { + await LoadData(); + await base.OnInitializedAsync(); + + //drugInfos = await drugInfoDao.GetAllDrug(); + } + + async Task LoadData() + { + BoxList = await channelListDao.GetAllBox(); + var result = await planDao.GetAllPlanInfo(); + plans = result.Desserts.Where(p=>p._PlanDetails.Count>0).ToList(); + _forecasts = await channelListDao.GetAllChannelList(); + firstFlag = 0; + } + + // 处理选择变更(可选) + private void OnPlanSelected(Plan plan) + { + selectedPlan = plan; + } + + //绑定 + async Task EditChannel() + { + List bindList = BoxList.Where(b => b.IsChecked).ToList(); + if (bindList == null || bindList.Count <= 0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请先选择药箱号再点击按钮", Duration = 4000 } + ); + return; + } + if (!string.IsNullOrEmpty(bindList[0].DrugId)) + { + //之前有绑定,在进行解绑 + foreach (var item in bindList) + { + var b = await channelListDao.UnBindBox(item); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"解除绑定成功", Duration = 4000 } + ); + } + } + await LoadData(); + } + else + {// 否则是进行绑定 + if (selectedPlan != null && selectedPlan.Id > 0) + { + foreach (var item in bindList) + { + var b = await channelListDao.BindBox(item, selectedPlan); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"绑定成功", Duration = 4000 } + ); + } + } + await LoadData(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择套餐", Duration = 4000 } + ); + + } + } + } + + private async Task OnCheckBoxChange(bool isChecked, int DrawerNo) + { + //isChecked==true 1)当前选择的药箱已经绑药套餐且库存<=0,如果有库存则提示不能选择,如果无库存则列出与之绑定相同套餐且库存<=0的药箱号,其他药箱号不可选择 + // 2)当前选择的药箱未绑定套餐则将所有未绑定套餐的药箱号列出来,其他药箱不可操作 + if (firstFlag == 0) + { + if (isChecked) + { + firstFlag = 1; + string drugId = BoxList.Where(b => b.DrawerNo == DrawerNo).Select(b => b.DrugId).FirstOrDefault(); + //所选药箱已绑定套餐 + if (!string.IsNullOrEmpty(drugId)) + { + //查询该药箱下的药品库存是否存在不为0的,存在则不让选择 + List stockList = await channelListDao.GetChannelStockByBox(DrawerNo); + if (stockList != null && stockList.Count > 0) + { + //该药箱下存在库存不为0的药品 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"该药盒下的药品仍有库存,请清库存后再操作", Duration = 4000 } + ); + BoxList.ForEach(it => it.IsChecked = false); + firstFlag = 0; + return; + } + else + { + //无库存则列出与之绑定相同套餐且库存 <= 0的药箱号,其他药箱号不可选择 + // BoxList.Where(b => string.IsNullOrEmpty(b.DrugId)).ToList().ForEach(b => b.BoxDisabled = true); + //1)查询套餐下无库存的药箱号 + List? lists = await channelListDao.GetChannelStockByPlan(drugId); + if (lists != null && lists.Count > 0) + { + int[] boxNum = lists.Select(l => l.DrawerNo).ToArray(); + //不在该lists下的药箱号不可选择 + BoxList.Where(b => !boxNum.Contains(b.DrawerNo)).ToList().ForEach(b => b.BoxDisabled = true); + } + selectedPlan = await planDao.GetPlanById(Convert.ToInt32(drugId)); + } + + } + else + { + + //未绑定套餐 ,列出所有未绑的药箱号,其他不可操作 + BoxList.Where(b => !string.IsNullOrEmpty(b.DrugId)).ToList().ForEach(b => b.BoxDisabled = true); + } + + } + } + else + { + if (!isChecked) + { + //isChecked==false 1)是否全部是false,是则将所有isChecked==true,不是则不做改变 + if (!BoxList.Any(b => b.IsChecked == true)) + { + BoxList.ForEach(b => b.BoxDisabled = false); + firstFlag = 0; + } + } + } + } + + +} diff --git a/MasaBlazorApp3/Pages/BoxRemoveDialog.razor b/MasaBlazorApp3/Pages/BoxRemoveDialog.razor new file mode 100644 index 0000000..0904857 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxRemoveDialog.razor @@ -0,0 +1,398 @@ +@page "/Box/BoxRemove" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + @* 药名: + @(channelStock.Drug.DrugName) + 规格: + @(channelStock.Drug.DrugSpec) + 批次: + @(channelStock.ManuNo) + 效期: + @(channelStock.EffDate) + 库存: + @(channelStock.Quantity) *@ +
+
药品名称
+ @(channelStock.Drug.DrugName) +
+
+
规格
+ @(channelStock.Drug.DrugSpec) +
+
+
批次
+ @(channelStock.ManuNo) +
+
+
效期
+ @(channelStock.EffDate) +
+
+
库存
+ @(channelStock.Quantity) +
+
+
+ + + + 移入 + + + + + + + + @(SelectedDrawerNo) + + + 移入数量 + + + + + + @if (BoxColor.BoxNo == 4) + { + @if (status < 3) + { + + + } + @if (status == 3) + { + + + } + } + else + { + + + } + + +
+ +@code { + @inject Radzen.DialogService dialogService; + @inject IChannelListDao channelListDao; + @inject IOptions setting + @inject IOptions drawerSetting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + bool CompleteIsEnable = true; + bool CancleIsEnable = true; + + int removeQuantity = 0; + int status; + + string[] AllDrawerNos; + string[] DrawerNos; + string SelectedDrawerNo = "1-1"; + + //药盒集合 + List BoxList = new List(); + //药盒颜色集合 + List BoxColorList = new List() + { + new BoxModel{BoxNo=1,BoxName=1 }, + new BoxModel{BoxNo=2 ,BoxName=1}, + new BoxModel{BoxNo=3 ,BoxName=1}, + new BoxModel{BoxNo=4 ,BoxName=1} + }; + BoxModel BoxColor = new BoxModel { BoxNo = 1, BoxName = 1 }; + BoxModel BoxNum; + [Parameter] public ChannelStock channelStock { get; set; } + private bool CanTakeDrug = true; + + // public List data { get; set; } + + + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + + protected override async Task OnInitializedAsync() + { + AllDrawerNos = await channelListDao.GetDrawerNumForRemove(channelStock); + if (AllDrawerNos != null && AllDrawerNos.Count() > 0) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('白')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0) + SelectedDrawerNo = DrawerNos[0]; + // var result = await channelListDao.GetChannelStockByDrug(channelStock, SelectedDrawerNo, 8, 0); + // selectedDrawerData = result.Desserts; + } + else + { + DrawerNos = new string[] { "无库位" }; + } + base.OnInitializedAsync(); + } + + // void RestData() + // { + // PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + // this.status = 0; + // data.ForEach(it => + // { + // it.Status = 0; + // it.BeforeQuantity = new int[9]; + // it.AfterQuantity = new int[9]; + // }); + // this.WeightFinnalQuantity = new int[9]; + // DrawerNoColNoList.Clear(); + // } + + private async Task OnColorChanged(object value) + { + BoxColor = (BoxModel)value; + if (AllDrawerNos != null && AllDrawerNos.Length > 0 && AllDrawerNos[0] != "无库位") + { + if ((((BoxModel)value).BoxNo) == 3) + { + DrawerNos = AllDrawerNos.Where(d => !(d.EndsWith('白')) && !(d.EndsWith('绿')) && !(d.Contains('-'))).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + else + { + if ((((BoxModel)value).BoxNo) == 1) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('白')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + else if ((((BoxModel)value).BoxNo) == 2) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('绿')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + else if ((((BoxModel)value).BoxNo) == 4) + { + DrawerNos = AllDrawerNos.Where(d => !(d.EndsWith('绿')) && !(d.EndsWith('白')) && d.Contains('-')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + + } + } + } + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task Save() + { + if (removeQuantity <= 0) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "请输入移入数量", Duration = 4000 }); + return; + } + if (string.IsNullOrEmpty(SelectedDrawerNo) || SelectedDrawerNo == "无库位") + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "无可移入的药盒", Duration = 4000 }); + return; + } + SelectedDrawerNo = SelectedDrawerNo == "急诊药盒" ? "99-1" : SelectedDrawerNo == "恢复室药盒" ? "111-1" : SelectedDrawerNo; + var b = await channelListDao.BoxRemoveFinish(channelStock, SelectedDrawerNo, removeQuantity); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"药盒移出保存数据失败,数据{JsonConvert.SerializeObject(channelStock)}"); + } + else + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"交换完成", Duration = 4000 }); + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + int drawerNo = 1; + int colNo = 1; + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + var selectSpl = SelectedDrawerNo.Split('-'); + + if (selectSpl != null && selectSpl.Count() > 0) + { + drawerNo = Convert.ToInt32(selectSpl[0]); + colNo = Convert.ToInt32(selectSpl[1]); + } + await Task.Delay(200); + PortUtil.DrawerNo = drawerNo; + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + await promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + // 判断是否为单支抽屉 + if (drawerSetting.Value.single != null && drawerSetting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + } + var b = await PortUtil.OpenDrawerStatus(this.drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,加药"); + this.status = 2; + PortUtil.Operate = true; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + RestData(); + PortUtil.Operate = false; + stop(); + } + + } + // 检测状态 + else if (this.status == 2) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"加药完成,请,点击完成按钮"); + this.status = 3; + PortUtil.Operate = false; + stop(); + } + else + { + if (drawerSetting.Value.single != null && drawerSetting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + removeQuantity = this.AfterQuantity[colNo - 1] - this.BeforeQuantity[colNo - 1]; + await InvokeAsync(StateHasChanged); + } + next(); // continue iteration + } + + } + } + catch (Exception e) + { + logger.Info($"抽屉加药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (drawerSetting.Value.single != null && drawerSetting.Value.single.Contains(this.drawerNo)) + { + PortUtil.PowerOff(); + } + RestData(); + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + // this.BeforeQuantity = new int[9]; + // this.AfterQuantity = new int[9]; + // currentCol = 0; + // ColNos.Clear(); + } + async Task AddFinish() + { + if (removeQuantity <= 0) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "请输入移入数量", Duration = 4000 }); + return; + } + // 保存账册、操作记录 + var b = await channelListDao.RemoveDrugToDrawerFinish(SelectedDrawerNo, channelStock, removeQuantity); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉加药保存数据库失败,数据{JsonConvert.SerializeObject(channelStock)}"); + } + //重置状态 + this.RestData(); + // 关闭弹窗 + dialogService.Close(true); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxReplace.razor b/MasaBlazorApp3/Pages/BoxReplace.razor new file mode 100644 index 0000000..63c7a65 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxReplace.razor @@ -0,0 +1,332 @@ +@page "/Box/BoxReplace" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + @*药名: + @(channelStock.Drug.DrugName) + 规格: + @(channelStock.Drug.DrugSpec) + 批次: + @(channelStock.ManuNo) + 效期: + @(channelStock.EffDate) + 库存: + @(channelStock.Quantity) + 交换药盒: *@ +
+
药品名称
+ @(channelStock.Drug.DrugName) +
+
+
规格
+ @(channelStock.Drug.DrugSpec) +
+
+
批次
+ @(channelStock.ManuNo) +
+
+
效期
+ @(channelStock.EffDate) +
+
+
库存
+ @(channelStock.Quantity) +
+
+ 交换药盒 + + + + + + + + + @(SelectedDrawerNo) + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ +@code { + @inject Radzen.DialogService dialogService; + @inject IChannelListDao channelListDao; + @inject IOptions setting; + @inject IOptions drawerSetting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + bool CompleteIsEnable = true; + bool CancleIsEnable = true; + + int status; + bool isLoading; + int count; + + [Parameter] public ChannelStock channelStock { get; set; } + private bool CanTakeDrug = true; + + // public List data { get; set; } + + public List selectedDrawerData { get; set; } + + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + + //药盒集合 + List BoxList = new List(); + BoxModel BoxColor = new BoxModel { BoxNo = 1, BoxName = 1 }; + string[] AllDrawerNos; + string[] DrawerNos; + string SelectedDrawerNo = "1-1"; + //药盒颜色集合 + List BoxColorList = new List() + { + new BoxModel{BoxNo=1,BoxName=1 }, + new BoxModel{BoxNo=2 ,BoxName=1}, + new BoxModel{BoxNo=3 ,BoxName=1} + }; + protected override async Task OnInitializedAsync() + { + // AllDrawerNos = await channelListDao.GetDrawerNum(channelStock); + // if (AllDrawerNos != null && AllDrawerNos.Count() > 0) + // { + // if (DrawerNos == null || DrawerNos.Length <= 0) + // { + // DrawerNos = new string[] { "无库位" }; + // } + // } + AllDrawerNos = await channelListDao.GetDrawerNumForRemove(channelStock); + if (AllDrawerNos != null && AllDrawerNos.Count() > 0) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('白')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0) + SelectedDrawerNo = DrawerNos[0]; + } + else + { + DrawerNos = new string[] { "无库位" }; + } + base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + if (DrawerNos != null && !DrawerNos.Contains("无库位") && DrawerNos.Count() > 0) + { + SelectedDrawerNo = DrawerNos[0]; + var result = await channelListDao.GetChannelStockByDrug(channelStock, SelectedDrawerNo, args.Top, args.Skip); + selectedDrawerData = result.Desserts; + if (selectedDrawerData != null && selectedDrawerData.Count > 0) + { + if (selectedDrawerData[0].DrawerNo <= 30) + { + if (selectedDrawerData[0].ColNo == 1) + { + BoxColor = BoxColorList[0]; + } + else + { + BoxColor = BoxColorList[1]; + } + } + else + { + BoxColor = BoxColorList[2]; + } + } + count = result.TotalDesserts; + } + isLoading = false; + } + + private async Task OnColorChanged(object value) + { + BoxColor = (BoxModel)value; + if (AllDrawerNos != null && AllDrawerNos.Length > 0 && AllDrawerNos[0] != "无库位") + { + if (BoxColor.BoxNo == 3) + { + DrawerNos = AllDrawerNos.Where(d => !(d.EndsWith('白')) && !(d.EndsWith('绿')) && !(d.Contains('-'))).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + await SelectedDrawerChange(SelectedDrawerNo); + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + else + { + if (BoxColor.BoxNo == 1) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('白')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + await SelectedDrawerChange(SelectedDrawerNo); + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + else if (BoxColor.BoxNo == 2) + { + DrawerNos = AllDrawerNos.Where(d => d.EndsWith('绿')).ToArray(); + if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + { + SelectedDrawerNo = DrawerNos[0]; + await SelectedDrawerChange(SelectedDrawerNo); + } + else + { + SelectedDrawerNo = "无库位"; + } + await InvokeAsync(StateHasChanged); + } + // else if (BoxColor.BoxNo == 4) + // { + // DrawerNos = AllDrawerNos.Where(d => !(d.EndsWith('绿')) && !(d.EndsWith('白')) && d.Contains('-')).ToArray(); + // if (DrawerNos != null && DrawerNos.Length > 0 && DrawerNos[0] != "无库位") + // { + // SelectedDrawerNo = DrawerNos[0]; + // await SelectedDrawerChange(SelectedDrawerNo); + // } + // else + // { + // SelectedDrawerNo = "无库位"; + // } + // await InvokeAsync(StateHasChanged); + + // } + } + } + + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task Save() + { + if (selectedDrawerData != null && selectedDrawerData.Any(cl => cl.AddQuantity != 0 && cl.DrugId != null && cl.ManuNo != null)) + { + if (selectedDrawerData.Where(cs => cs.AddQuantity != 0).Sum(cs => cs.AddQuantity) > channelStock.Quantity) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Warning, Summary = "提示", Detail = $"交换总数量不能大于库存", Duration = 4000 }); + return; + } + var b = await channelListDao.BoxReplaceFinish(channelStock, selectedDrawerData.Where(cl => cl.AddQuantity != 0).ToList()); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"药盒药品替换保存数据库失败,数据{JsonConvert.SerializeObject(selectedDrawerData.Where(cl => cl.AddQuantity != 0).ToList())}"); + } + else + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"交换完成", Duration = 4000 }); + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + else + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Warning, Summary = "提示", Detail = $"无可交换数据或未输入交换数量", Duration = 4000 }); + return; + } + } + + async Task SelectedDrawerChange(object drawerNo) + { + if (drawerNo == "无库位") + { + return; + } + drawerNo = drawerNo == "急诊药盒" ? "99-1" : drawerNo == "恢复室药盒" ? "111-1" : drawerNo == "胃镜药盒" ? "31-1" : drawerNo == "导管药盒" ? "32-1" : drawerNo == "生殖药盒" ? "33-1" : drawerNo == "妇门药盒" ? "34-1" : drawerNo; + + var result = await channelListDao.GetChannelStockByDrug(channelStock, drawerNo.ToString(), 8, 0); + selectedDrawerData = result.Desserts; + } + int currentCol = 0; + + RadzenDataGrid grid; + void OnCellClick(DataGridCellMouseEventArgs args) + { + currentCol = args.Data.ColNo; + grid.EditRow(args.Data); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + // this.BeforeQuantity = new int[9]; + // this.AfterQuantity = new int[9]; + // currentCol = 0; + // ColNos.Clear(); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxStock.razor b/MasaBlazorApp3/Pages/BoxStock.razor new file mode 100644 index 0000000..9bcd3a3 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxStock.razor @@ -0,0 +1,225 @@ +@page "/Box/BoxStock" +@using MasaBlazorApp3.Pojo.Config + + +
+
+ @foreach (var cs in channelStockList) + { + + + } +
+
+
+ + + + +
+
+@code { + @inject IOrderInfoDao orderInfoDao; + @inject IChannelListDao channelListDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message + + private IEnumerable? _forecasts; + bool allowRowSelectOnRowClick = true; + // IEnumerable drugManuNos; + // IList selectedDrugManuNos; + RadzenDataList grid; + // RadzenDataGrid gridManuNo; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + List channelStockList = new(); + int status = 0; + string drawerNo = "1-1"; + string OrderNo; + DateTime OrderDate; + void SelectDrawer(string strDrawerNoColNo) + { + this.drawerNo = strDrawerNoColNo; + grid.Reload(); + } + // void OnCurrentDateChanged(DateTime args) + // { + // OrderDate = new DateTime(args.Year, args.Month, args.Day); + // } + //重置 + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + await grid.Reload(); + } + //确认 + async Task Confirm() + { + // orderInfoDao.CheckOrderInfo(selectedOrderInfos, drawerNo); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelListDao.GetBoxDrugInfo(drawerNo, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + + channelStockList = await orderInfoDao.GetDrawerNum(setting.Value.boxMachineId); + } + //替换按钮 + async Task replaceClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + + string message = cs.DrawerNo + "-" + (cs.ColNo == 1 ? "白" : "绿") + " 药盒替换药品详情"; + var b = await dialogService.OpenAsync( + message, + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0无法替换", Duration = 4000 } + ); + } + } + //移除按钮 + async Task removeClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + string message = cs.DrawerNo + "-" + (cs.ColNo == 1 ? "白" : "绿") + " 药盒移动药品详情"; + var b = await dialogService.OpenAsync( + message, + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0,没有要移出的药品", Duration = 4000 } + ); + } + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxStockNew.razor b/MasaBlazorApp3/Pages/BoxStockNew.razor new file mode 100644 index 0000000..a851b3b --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxStockNew.razor @@ -0,0 +1,234 @@ +@page "/Box/BoxStockAAA" +@using MasaBlazorApp3.Pojo.Config + + +
+
+ @foreach (var cs in channelStockList) + { + + + } +
+
+
+ + + + + + + + + + + + + +
+
+@code { + @inject IOrderInfoDao orderInfoDao; + @inject IChannelListDao channelListDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message + + @inject IDrugInfoDao drugInfoDao; + + private IEnumerable? _forecasts; + bool allowRowSelectOnRowClick = true; + // IEnumerable drugManuNos; + // IList selectedDrugManuNos; + + RadzenDataGrid grid; + // RadzenDataGrid gridManuNo; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + List channelStockList = new(); + int status = 0; + string drawerNo = "1-1"; + string OrderNo; + DateTime OrderDate; + async Task SelectDrawer(string strDrawerNoColNo) + { + this.drawerNo = strDrawerNoColNo; + + BoxModel boxModel = new BoxModel(); + boxModel.BoxName = 1; + boxModel.BoxNo = 1; + // grid.Reload(); + if (drawerNo != null) + { + string[] strArr = drawerNo.Split('-'); + boxModel.BoxName = Convert.ToInt32(strArr[0]); + boxModel.BoxNo = Convert.ToInt32(strArr[1]); + } + var result = await drugInfoDao.GetAllDrugAndStockByBox(boxModel); + _forecasts = result; + } + // void OnCurrentDateChanged(DateTime args) + // { + // OrderDate = new DateTime(args.Year, args.Month, args.Day); + // } + //重置 + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + await grid.Reload(); + } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + isLoading = true; + BoxModel boxModel = new BoxModel(); + + boxModel.BoxName = 1; + boxModel.BoxNo = 1; + isLoading = true; + if (drawerNo != null) + { + string[] strArr = drawerNo.Split('-'); + boxModel.BoxName = Convert.ToInt32(strArr[0]); + boxModel.BoxNo = Convert.ToInt32(strArr[1]); + } + var result = await drugInfoDao.GetAllDrugAndStockByBox(boxModel);// await channelListDao.GetBoxDrugInfo(drawerNo, args.Top, args.Skip); + // Update the Data property + _forecasts = result; + // Update the count + //count = result.TotalDesserts; + + isLoading = false; + + channelStockList = await orderInfoDao.GetDrawerNum(setting.Value.boxMachineId); + + isLoading = false; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await grid.ExpandRows(grid.PagedView.Where(di => di.Stocks.Count > 0)); + } + } + + void RowRender(RowRenderEventArgs args) + { + args.Expandable = args.Data.Stocks.Count > 0; + } + //确认 + async Task Confirm() + { + // orderInfoDao.CheckOrderInfo(selectedOrderInfos, drawerNo); + } + + async Task LoadData(LoadDataArgs args) + { + BoxModel boxModel = new BoxModel(); + + boxModel.BoxName = 1; + boxModel.BoxNo = 1; + isLoading = true; + if (drawerNo != null) + { + string[] strArr = drawerNo.Split(','); + boxModel.BoxName = Convert.ToInt32(strArr[0]); + boxModel.BoxNo = Convert.ToInt32(strArr[1]); + } + var result = await drugInfoDao.GetAllDrugAndStockByBox(boxModel);// await channelListDao.GetBoxDrugInfo(drawerNo, args.Top, args.Skip); + // Update the Data property + _forecasts = result; + // Update the count + //count = result.TotalDesserts; + + isLoading = false; + + channelStockList = await orderInfoDao.GetDrawerNum(setting.Value.boxMachineId); + } + //替换按钮 + async Task replaceClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + var b = await dialogService.OpenAsync( + $"{cs.DrawerNo}号药盒替换药品详情", + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0无法替换", Duration = 4000 } + ); + } + } + //移除按钮 + async Task removeClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + var b = await dialogService.OpenAsync( + $"{cs.DrawerNo}号药盒替换药品详情", + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0,没有要移出的药品", Duration = 4000 } + ); + } + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/BoxStockNewTwo.razor b/MasaBlazorApp3/Pages/BoxStockNewTwo.razor new file mode 100644 index 0000000..2a320a1 --- /dev/null +++ b/MasaBlazorApp3/Pages/BoxStockNewTwo.razor @@ -0,0 +1,212 @@ +@page "/Box/BoxStockAA" +@using MasaBlazorApp3.Pojo.Config + + +
+
+ @foreach (var cs in channelStockList) + { + + + } +
+
+
+ + + + +
+
+@code { + @inject IOrderInfoDao orderInfoDao; + @inject IChannelListDao channelListDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message + + private IEnumerable? _forecasts; + bool allowRowSelectOnRowClick = true; + // IEnumerable drugManuNos; + // IList selectedDrugManuNos; + RadzenDataList grid; + // RadzenDataGrid gridManuNo; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + List channelStockList = new(); + int status = 0; + string drawerNo = "1-1"; + string OrderNo; + DateTime OrderDate; + void SelectDrawer(string strDrawerNoColNo) + { + this.drawerNo = strDrawerNoColNo; + grid.Reload(); + } + // void OnCurrentDateChanged(DateTime args) + // { + // OrderDate = new DateTime(args.Year, args.Month, args.Day); + // } + //重置 + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + await grid.Reload(); + } + //确认 + async Task Confirm() + { + // orderInfoDao.CheckOrderInfo(selectedOrderInfos, drawerNo); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelListDao.GetBoxDrugInfo(drawerNo, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + + channelStockList = await orderInfoDao.GetDrawerNum(setting.Value.boxMachineId); + } + //替换按钮 + async Task replaceClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + var b = await dialogService.OpenAsync( + $"{cs.DrawerNo}号药盒替换药品详情", + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0无法替换", Duration = 4000 } + ); + } + } + //移除按钮 + async Task removeClick(ChannelStock cs) + { + if (cs.Quantity > 0) + { + var b = await dialogService.OpenAsync( + $"{cs.DrawerNo}号药盒替换药品详情", + new Dictionary() { { "channelStock", cs } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + else + { + //库存为0无法操作 + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"库存为0,没有要移出的药品", Duration = 4000 } + ); + } + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/ChangeShifts.razor b/MasaBlazorApp3/Pages/ChangeShifts.razor new file mode 100644 index 0000000..52b9b13 --- /dev/null +++ b/MasaBlazorApp3/Pages/ChangeShifts.razor @@ -0,0 +1,341 @@ +@page "/0" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + + @if (userI == 1) + { + + 请交班操作人 @FromOperator?.NickName +

登录验证

+
+ } + else if (userI == 2) + { + + 请交班复核人 @FromRviewer?.NickName +

登录验证

+
+ } + else + @if (userI == 3) + { + + 请接班操作人 @ToOperator?.NickName +

登录验证

+
+ } + else if (userI == 4) + { + + 请接班复核人 @ToReviewer?.NickName +

登录验证

+
+ } +
+
+ + + + 交接班登录验证 + + +
+ +
+ + + +
+
+
+ +
+ + +
+
+ @if (userI > 2) + { +
+ +
+ +
+
+ } +
+ + +
+
+
+
+ +
+ +@code { + @inject Radzen.DialogService dialogService; + + @inject FingerprintUtil FingerprintUtil; + @inject PortUtil PortUtil; + @inject NavigationManager na; + @inject NotificationService _message + @inject GlobalStateService globalStateService; + @inject IUserDao userDao; + @inject Microsoft.Extensions.Options.IOptions setting; + + + + private readonly ILog logger = LogManager.GetLogger(typeof(LoginDialog)); + + private int loginMode = 1; + private bool opFirst = true; + [Parameter] public int userI { get; set; } + + Pojo.User FromOperator = new Pojo.User(); + Pojo.User FromRviewer = new Pojo.User(); + Pojo.User ToOperator = new Pojo.User(); + Pojo.User ToReviewer = new Pojo.User(); + + HkcChangeShifts hkcChange = new HkcChangeShifts(); + string remarks = string.Empty; + bool isShow; + + private Pojo.User loginModel = new(); + + protected override Task OnInitializedAsync() + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx += axCZKEM1_OnAttTransactionEx; + + loginMode = setting.Value.loginMode; + opFirst = setting.Value.opFirst; + + //查询当前值班信息 + hkcChange = userDao.GetOnDuty(); + if (hkcChange != null && !string.IsNullOrEmpty(hkcChange.FromOperator)) + { + FromOperator = userDao.GetByUsername(hkcChange.FromOperator); + } + if (hkcChange != null && string.IsNullOrEmpty(hkcChange.FromRviewer)) + { + FromRviewer = userDao.GetByUsername(hkcChange.FromRviewer); + } + return base.OnInitializedAsync(); + } + + private async Task SetUser(Pojo.User user) + { + if (userI == 1) + { + if(FromOperator.Id != user.Id) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"值班操作人有误,请核查当前值班人", Duration = 3000 } + ); + return; + } + //交班人操作人登录 + if (FromRviewer != null) + { + userI = 2; + } + else + { + userI = 3; + } + + } + else if (userI == 2) + { + if (FromOperator != null && FromOperator.Id == user.Id) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + return; + } + else + { + if(FromRviewer.Id!=user.Id) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"值班审核人有误,请核查当前值班人", Duration = 3000 } + ); + return; + } + FromRviewer = user; + userI = 3; + } + } + else if (userI == 3) + { + if (loginMode == 2) + { + if (FromOperator.Id == user.Id || (FromRviewer != null && FromRviewer.Id == user.Id)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + return; + } + userI = 4; + ToOperator = user; + } + else + { + if (FromOperator.Id == user.Id || (FromRviewer != null && FromRviewer.Id == user.Id)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + return; + } + else + { + ToOperator = user; + //保存交接班信息 + HkcChangeShifts hkcChangeNew = new HkcChangeShifts + { + FromOperator = ToOperator.Username, + optDate = DateTime.Now, + ToDate = DateTime.Now, + State = "0", //状态为1表示交接班完成 + MachineId = hkcChange.MachineId, + Remarks = remarks + }; + hkcChange.ToOperator = ToOperator.Username; + bool bResult = await userDao.UpdateChangeShift(hkcChange, hkcChangeNew); + if (bResult) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + logger.Info($"交接班完成,交班人{FromOperator.NickName};{FromRviewer?.NickName},接班人{ToOperator?.NickName};{ToOperator?.NickName}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"交接班完成", Duration = 3000 } + ); + dialogService.Close(true); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "交接班保存数据失败", Duration = 3000 } + ); + } + } + } + } + else if (userI == 4) + { + if (FromOperator.Id == user.Id || (FromRviewer != null && FromRviewer.Id == user.Id) || (ToOperator != null && ToOperator.Id == user.Id)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + return; + } + ToReviewer = user; + hkcChange.ToReviewer = ToReviewer?.Username; + //保存交接班信息 + HkcChangeShifts hkcChangeNew = new HkcChangeShifts + { + FromOperator = ToOperator.Username, + FromRviewer = ToReviewer?.Username, + optDate = DateTime.Now, + State = "0", //状态为1表示交接班完成 + MachineId = hkcChange.MachineId, + Remarks = remarks + }; + bool bResult = await userDao.UpdateChangeShift(hkcChange, hkcChangeNew); + if (bResult) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + logger.Info($"交接班完成,交班人{FromOperator.NickName};{FromRviewer?.NickName},接班人{ToOperator?.NickName};{ToReviewer?.NickName}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"交接班完成", Duration = 3000 } + ); + dialogService.Close(true); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = "交接班保存数据失败", Duration = 3000 } + ); + } + } + } + + + + private void Submit(Pojo.User user) + { + Pojo.User u = userDao.GetByUsername(loginModel.Username); + if (u != null) + { + if (Util.MD5.GetMD5Hash(loginModel.Password).ToLower().Equals(u.Password)) + { + SetUser(u); + loginModel.Username = ""; + loginModel.Password = ""; + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"密码错误", Duration = 4000 } + ); + logger.Info($"用户【{u.NickName}】密码输入错误"); + + } + + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"无此用户", Duration = 4000 } + ); + logger.Info($"没有用户:【{loginModel.Username}】"); + } + } + + private void axCZKEM1_OnAttTransactionEx(string sEnrollNumber, int iIsInValid, int iAttState, int iVerifyMethod, int iYear, int iMonth, int iDay, int iHour, int iMinute, int iSecond, int iWorkCode) + { + + Pojo.User u = userDao.GetById(Convert.ToInt32(sEnrollNumber)); + if (u != null) + { + SetUser(u); + InvokeAsync(StateHasChanged); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"系统中没有ID为【{sEnrollNumber}】的用户", Duration = 4000 } + ); + logger.Info($"指纹机验证通过id为【{sEnrollNumber}】,但是华康数据库中无此用户"); + } + + } + + private void Exit() + { + dialogService.Close(false); + } + + + + +} diff --git a/MasaBlazorApp3/Pages/ChangeShiftsList.razor b/MasaBlazorApp3/Pages/ChangeShiftsList.razor new file mode 100644 index 0000000..523d175 --- /dev/null +++ b/MasaBlazorApp3/Pages/ChangeShiftsList.razor @@ -0,0 +1,123 @@ +@page "/stock/Change" + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+ +@code { + @inject IHkcChangeShiftsDao hkcChangeShiftsDao; + @inject DialogService dialogService; + + @inject NavigationManager navigate; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime start; + DateTime end; + + + [Parameter] public string type { get; set; } + + protected override void OnParametersSet() + { + if (grid != null) + { + reloadGrid(); + } + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await hkcChangeShiftsDao.GetChangeShiftRecordAsync(start, end,args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + start = DateTime.MinValue; + end = DateTime.MinValue; + await grid.Reload(); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/CheckOrder.razor b/MasaBlazorApp3/Pages/CheckOrder.razor new file mode 100644 index 0000000..f8d9cca --- /dev/null +++ b/MasaBlazorApp3/Pages/CheckOrder.razor @@ -0,0 +1,522 @@ +@page "/Box/CheckAAA" +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Report +@using Microsoft.Extensions.Options +@using Radzen.Blazor.Rendering +@using log4net; + + + + + @*
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
*@ + @*
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
*@ +
+
+ + @* *@ + + + + + + + + + + + + + @* + + + + *@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @* *@ + + + @* + + + + + + *@ + @* + + + + + + + + + + + + + + + + + + + + + *@ + +
+
+ + + + @* + + *@ + + + + + + + + + @* + *@ + @* + + *@ + + @* *@ + + + + + + @((context as DrugManuNo)?.ManuNo) + @if ((context as DrugManuNo).EffDate != null && (context as DrugManuNo).EffDate.ToString().Length > 10) + { + + @((context as DrugManuNo).EffDate.ToString().Substring(0, 10)) + } + else + { + + @((context as DrugManuNo)?.EffDate) + } + + + + + + + + + + + + + + + +
+
+
+@code { + + private readonly ILog logger = LogManager.GetLogger(typeof(CheckOrder)); + @inject IOrderInfoDao orderInfoDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message; + @inject IReportDataDao reportDataDao; + @inject IOptions setting; + bool allowRowSelectOnRowClick = true; + IEnumerable orderInfos; + IList selectedOrderInfos; + RadzenDataGrid grid; + //麻醉师集合 + List NamesList = new List(); + Anaesthetist NameInfo; + Anaesthetist BoxColor; + //药盒集合 + List BoxList = new List(); + //药盒颜色集合 + List BoxColorList = new List(); + BoxModel BoxNum; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int status = 0; + string OrderNo; + string PatientName; + DateTime? OrderDate = null; + DateTime PortOrderDate = DateTime.Now; + Popup popup; + RadzenButton button; + //第一次加载不执行LoadData方法 + int firstLod = 1; + void OnCheckSeleced(object dete) + { + if (orderInfos != null) + { + orderInfos.ToList().ForEach(it => it.ItemIsChecked = true); + } + } + void OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + } + void OnCurrentPortDateChanged(DateTime args) + { + PortOrderDate = new DateTime(args.Year, args.Month, args.Day); + } + // async Task OnColorChange(object value) + // { + // Anaesthetist v = value as Anaesthetist; + // if (v.Id != BoxColor.Id) + // { + // BoxList = await orderInfoDao.GetOperationNum(BoxColor.Id);// await orderInfoDao.GetDrawerNumByOperationNum(setting.Value.boxMachineId, roomNameList); //roomNameList.Select(it => new BoxModel { BoxName = it, BoxNo = Convert.ToInt32(it.Substring(it.Length - 2, 2)) }).ToList(); + + // BoxNum = BoxList.FirstOrDefault(); + // } + // } + //重置 + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + firstLod = 1; + await grid.Reload(); + } + void OnCellClick(DataGridCellMouseEventArgs args) + { + if (args.Data.DetailInfo.SetManuNo != null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.Where(m => m.ManuNo == args.Data.DetailInfo.SetManuNo).FirstOrDefault(); + } + if (args.Data.DetailInfo.drugManuNo == null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.FirstOrDefault(); + } + args.Data.ItemIsChecked = !args.Data.ItemIsChecked; + grid.EditRow(args.Data); + } + //确认 + async Task Confirm() + { + if (selectedOrderInfos == null) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择处方", Duration = 4000 } + ); + return; + } + if (BoxNum == null) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择药箱", Duration = 4000 } + ); + return; + } + if (selectedOrderInfos.Any(it => it.DetailInfo.drugManuNo == null && (string.IsNullOrEmpty(it.DetailInfo.SetManuNo)))) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择批次信息", Duration = 4000 } + ); + return; + } + selectedOrderInfos.Where(oi => oi.DetailInfo.drugManuNo != null && !string.IsNullOrEmpty(oi.DetailInfo.drugManuNo.ManuNo)).ToList().ForEach(oi => oi.DetailInfo.SetManuNo = oi.DetailInfo.drugManuNo.ManuNo); + selectedOrderInfos.Where(oi => !string.IsNullOrEmpty(oi.DetailInfo.SetManuNo)).ToList().ForEach(oi => oi.DetailInfo.drugManuNo = new() { ManuNo = oi.DetailInfo.SetManuNo }); + //弹出药品合计信息,确认无误后进行核对,取消则不核对 + //弹出确认提示框 + // var b = await dialogService.OpenAsync( + // $"核对确认", + // new Dictionary() { { "selectedOrderInfos", selectedOrderInfos } }, + // new DialogOptions() { Width = "80vw", Resizable = true, Draggable = true, ShowClose = false }); + // if (b) + // { + bool bResult = await orderInfoDao.CheckOrderInfo(selectedOrderInfos, BoxNum); + if (bResult) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"处方已核对完成", Duration = 4000 } + ); + //await GetInitialDate(); + await grid.Reload(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"处方已核对失败", Duration = 4000 } + ); + } + // } + } + PageData result; + protected override async Task OnInitializedAsync() + { + BoxColorList = setting.Value.boxColor.Split(',').Select(it => new Anaesthetist { Name = it,Id=it=="白"?1:2 }).ToList(); + BoxColor = BoxColorList.FirstOrDefault(); + NamesList = setting.Value.anaesthetist_name.Split(',').Select(it => new Anaesthetist { Name = it }).ToList(); + NameInfo = NamesList.FirstOrDefault(); + BoxList = await orderInfoDao.GetOperationNum(0);// await orderInfoDao.GetDrawerNumByOperationNum(setting.Value.boxMachineId, roomNameList); //roomNameList.Select(it => new BoxModel { BoxName = it, BoxNo = Convert.ToInt32(it.Substring(it.Length - 2, 2)) }).ToList(); + + BoxNum = BoxList.FirstOrDefault(); + + //await GetInitialDate(); + await base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + if (firstLod == 1) + { + + return; + } + // BoxList=BoxList.Where(bl => bl.BoxNo == BoxColor.Id).ToList(); + // BoxNum = BoxList.FirstOrDefault(); + string? anaesthetistName = NameInfo.Name == "未选择" ? null : NameInfo.Name; + string? roomName = BoxNum == null ? "" : setting.Value.roomName + BoxNum.BoxName.ToString().PadLeft(2, '0'); + result = await orderInfoDao.GetAllOrderInfo(anaesthetistName, roomName, PatientName, OrderNo, OrderDate, args.Top, args.Skip); + isLoading = true; + orderInfos = result.Desserts; + count = result.TotalDesserts; + // if (result != null) + // { + // isLoading = true; + // orderInfos = result.Desserts; + // // Update the count + // count = result.TotalDesserts; + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()}"); + // // Update the Data property + // if (Name != null) + // { + // orderInfos = orderInfos.Where(it => it.anaesthetistName == Name.Name); + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()},Name{Name.Name}"); + // count = orderInfos.Count(); + // } + // if (OrderDate != null && OrderDate != DateTime.MinValue) + // { + // orderInfos = orderInfos.Where(it => it.ChargeDate.Date >= OrderDate.Value.Date); + + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()}"); + // // Update the count + // count = orderInfos.Count(); + // } + // if (!string.IsNullOrEmpty(OrderNo)) + // { + // orderInfos = orderInfos.Where(it => it.OrderNo.Contains(OrderNo)); + + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()}-OrderNo{OrderNo}"); + // // Update the count + // count = orderInfos.Count(); + // } + // if (Name != null && OrderDate != null && OrderDate != DateTime.MinValue && !string.IsNullOrEmpty(OrderNo)) + // { + // orderInfos = orderInfos.Where(it => it.anaesthetistName == Name.Name && it.ChargeDate.Date == OrderDate.Value.Date && it.OrderNo.Contains(OrderNo)); + + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()}"); + // // Update the count + // count = orderInfos.Count(); + // } + // if (BoxNum != null&&BoxNum.BoxName!=99&&BoxNum.BoxName!=111) + // { + // string roomName = setting.Value.roomName + BoxNum.BoxName.ToString().PadLeft(2, '0'); + + // orderInfos = orderInfos.Where(it => it.RoomName == roomName); + + // logger.Info($"LoadData:{DateTime.Now},{orderInfos.Count()};roomName{roomName}"); + // count = orderInfos.Count(); + // } + + // logger.Info($"LoadData结束:{DateTime.Now},{orderInfos.Count()}"); + + // orderInfos = orderInfos.Skip(args.Skip.Value).Take(args.Top.Value).ToList(); + + // logger.Info($"LoadData结束:{DateTime.Now},{orderInfos.Count()} -{args.Skip.Value}-{args.Top.Value}"); + + // await InvokeAsync(StateHasChanged); + // //查找该麻醉师对应的手术室 + // //List roomNameList = orderInfos.Select(it => it.RoomName).Distinct().ToList(); + // // List roomNameList = orderInfos.Select(it => Convert.ToInt32(it.RoomName.Substring(6, it.RoomName.Length - 6))).Distinct().ToList(); + // // BoxList = await orderInfoDao.GetDrawerNumByOperationNum(setting.Value.boxMachineId, roomNameList); //roomNameList.Select(it => new BoxModel { BoxName = it, BoxNo = Convert.ToInt32(it.Substring(it.Length - 2, 2)) }).ToList(); + + // // BoxNum = BoxList.FirstOrDefault(); + + isLoading = false; + + // } + } + //麻醉药品使用登记本导出 + async Task StockExport() + { + if (PortOrderDate == DateTime.MinValue) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择处方时间再导出", Duration = 4000 } + ); + return; + } + List pageData = await reportDataDao.GetOrderInfoData(PortOrderDate); + Dictionary parameters = new Dictionary(); + parameters.Add("PortOrderDate", pageData); + GridReportUtil.PrintReport("Usage_Temp.grf", parameters); + } + // protected override async Task OnInitializedAsync() + // { + // await base.OnInitializedAsync(); + + // // orderInfos = dbContext.Employees; + + // var result = await orderInfoDao.GetAllOrderInfo(OrderNo, OrderDate, args.Top, args.Skip); + // // Update the Data property + // orderInfos = result.Desserts; + // // Update the count + // count = result.TotalDesserts; + + // isLoading = false; + // } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/CheckOrderConfirmDialog.razor b/MasaBlazorApp3/Pages/CheckOrderConfirmDialog.razor new file mode 100644 index 0000000..282d5b9 --- /dev/null +++ b/MasaBlazorApp3/Pages/CheckOrderConfirmDialog.razor @@ -0,0 +1,358 @@ +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Util +@using MasaBlazorApp3.Pojo.Vo; +@using Microsoft.Extensions.Options +@using log4net; + + + +
+ + @* + + *@ + + + + +
+ + + + @* + + *@ + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status <= 2) + { + + } + + +
+ +@code { + @inject Radzen.DialogService dialogService; + @inject IOptions setting; + @inject PortUtil PortUtil; + @inject NotificationService _message; + @inject IOrderInfoDao orderInfoDao; + [Parameter] public IList csList { get; set; } + List orderDetailList = new(); + ChannelStock listBoxSelectedcsList = new(); + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + int status; + + List data = new(); + //计数取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + // //取药数量小于库存 + // tempData.Add(new OrderTakeVo() + // { + // Drug = detail.Drug, + // OrderDetail = detail, + // ChannelStock = stock, + // StockQuantity = total, + // Quantity = Quantity, + // }); + protected override async Task OnInitializedAsync() + { + for (int i = 0; i < csList.Count; i++) + { + if (csList[i].EmptyStock != null && csList[i].EmptyStock.ReturnQuantity > 0) + { + data.Add(new OrderTakeVo() + { + ChannelStock = csList[i].EmptyStock + }); + } + if (csList[i].DrawerChanneStockList != null && csList[i].DrawerChanneStockList.Count > 0) + { + for (int j = 0; j < csList[i].DrawerChanneStockList.Count; j++) + { + data.Add(new OrderTakeVo() + { + ChannelStock = csList[i].DrawerChanneStockList[j] + }); + } + } + } + base.OnInitializedAsync(); + } + // async Task ConfirmOK() + // { + // // 关闭弹窗 + // dialogService.Close(true); + // } + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + List drawerNos = this.data.GroupBy(it => it.ChannelStock.DrawerNo).Select(it => it.First()).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + + await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + { + var orderTakeVo = drawerNos[options._data]; + var drawerNo = orderTakeVo.ChannelStock.DrawerNo; + var drawerType = orderTakeVo.ChannelStock.DrawerType; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (orderTakeVo.Status == 0) + { + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + + await PortUtil.HasLightOnByCol(drawerNo, data.Where(ot => ot.ChannelStock.DrawerNo == drawerNo).Select(ot => ot.ChannelStock.ColNo).ToArray()); + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + if (drawerType==1) + { + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,环药"); + } + else + { + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,环空瓶"); + } + orderTakeVo.Status = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (orderTakeVo.Status == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + + data.ForEach(cl => + { + if (cl.ChannelStock.DrawerNo == drawerNo) + { + cl.GetQuantity = cl.Quantity; + + } + }); + orderTakeVo.Status = 2; + PortUtil.PowerOff(); + if (options._data == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"抽屉关闭,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + //检查是否称重抽屉,核对实际取出数量是否与应取数量一致,不一致则弹出提示 + for (int i = 0; i < data.Count; i++) + { + + if (data[i].ChannelStock.BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = orderTakeVo.BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}应取数量【{orderTakeVo.Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + } + } + } + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + //弹出确认提示框 + var confirm = await dialogService.OpenAsync( + $"保存确认", + new Dictionary() { { "confirmInfo", alertMessage } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + logger.Info(alertMessage); + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + // 关闭弹窗 + dialogService.Close(false); + } + } + stop(); + } + else + { + options._data += 1; + next(); + } + } + else + { + next(); // continue iteration + } + } + + + } + + } + catch (Exception e) + { + RestData(); + logger.Info($"处方取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + data.ForEach(it => + { + it.Status = 0; + it.BeforeQuantity = new int[9]; + it.AfterQuantity = new int[9]; + }); + this.WeightFinnalQuantity = new int[9]; + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task TakeFinish() + { + + // 保存账册、操作记录 + bool bResult = await orderInfoDao.CheckOrderInfoByChannelStock(csList.ToList(), null); + if (bResult) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"处方已核对完成", Duration = 4000 } + ); + // 关闭弹窗 + dialogService.Close(true); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"处方核对失败", Duration = 4000 } + ); + } + //重置状态 + this.RestData(); + } + +} diff --git a/MasaBlazorApp3/Pages/CheckOrderImportDialog.razor b/MasaBlazorApp3/Pages/CheckOrderImportDialog.razor new file mode 100644 index 0000000..f577d26 --- /dev/null +++ b/MasaBlazorApp3/Pages/CheckOrderImportDialog.razor @@ -0,0 +1,253 @@ +@page "/Box/OrderImport" +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Report +@using Microsoft.Extensions.Options +@using Radzen.Blazor.Rendering +@using log4net; + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + @* + + + *@ + + + + + + + + + + @* *@ + + @* + *@ + @* + + *@ + + + @* + + + + + @((context as DrugManuNo)?.ManuNo) + @if ((context as DrugManuNo).EffDate != null && (context as DrugManuNo).EffDate.ToString().Length > 10) + { + + @((context as DrugManuNo).EffDate.ToString().Substring(0, 10)) + } + else + { + + @((context as DrugManuNo)?.EffDate) + } + + + + + *@ + + + @* + + + *@ + + + +
+
+
+@code { + + private readonly ILog logger = LogManager.GetLogger(typeof(CheckOrder)); + @inject IOrderInfoDao orderInfoDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message; + @inject IReportDataDao reportDataDao; + @inject IOptions setting; + + + + [Parameter] public BoxModel boxModel { get; set; } + + bool allowRowSelectOnRowClick = true; + IEnumerable orderInfos; + IList selectedOrderInfos = new List(); + RadzenDataGrid grid; + //麻醉师集合 + List NamesList = new List(); + Anaesthetist NameInfo; + Anaesthetist BoxColor; + //药盒集合 + List BoxList = new List(); + //药盒颜色集合 + List BoxColorList = new List(); + BoxModel BoxNum; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int status = 0; + string OrderNo; + string PatientName; + DateTime OrderDate = DateTime.Now; + DateTime PortOrderDate = DateTime.Now; + Popup popup; + RadzenButton button; + //第一次加载不执行LoadData方法 + // int firstLod = 1; + void OnCheckSeleced(object dete) + { + if (orderInfos != null) + { + orderInfos.ToList().ForEach(it => it.ItemIsChecked = true); + } + } + void OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + } + void OnCellClick(DataGridCellMouseEventArgs args) + { + if (args.Data.DetailInfo.SetManuNo != null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.Where(m => m.ManuNo == args.Data.DetailInfo.SetManuNo).FirstOrDefault(); + } + if (args.Data.DetailInfo.drugManuNo == null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.FirstOrDefault(); + } + args.Data.ItemIsChecked = !args.Data.ItemIsChecked; + grid.EditRow(args.Data); + } + //确认 + async Task Confirm() + { + if (selectedOrderInfos == null || selectedOrderInfos.Count<=0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择处方", Duration = 4000 } + ); + return; + } + // 关闭弹窗selectedOrderInfos + dialogService.Close(selectedOrderInfos); + + } + PageData result; + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + // if (firstLod == 1) + if (boxModel != null && boxModel.BoxName > 0) + { + //查询除本药箱外的处方信息 + result = await orderInfoDao.GetAllOrderInfoForImport(PatientName, OrderNo, OrderDate, boxModel, args.Top, args.Skip); + orderInfos = result.Desserts; + selectedOrderInfos = orderInfos.ToList(); + count = result.TotalDesserts; + isLoading = true; + } + isLoading = false; + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/CheckOrderNew.razor b/MasaBlazorApp3/Pages/CheckOrderNew.razor new file mode 100644 index 0000000..ae09b17 --- /dev/null +++ b/MasaBlazorApp3/Pages/CheckOrderNew.razor @@ -0,0 +1,581 @@ +@page "/Box/Check" +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Report +@using Microsoft.Extensions.Options +@using Radzen.Blazor.Rendering +@using log4net; + + + +@* *@ +
+ @* *@ + + + + + + + + + + + + + + + + + + @* *@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ @* + + + + + + + + + *@ + + + + +
+
+ @if ((listBoxSelectedcsList != null && string.IsNullOrEmpty(listBoxSelectedcsList.ListId) && listBoxSelectedcsList.Quantity > listBoxSelectedcsList.UseQuantity) || (listBoxSelectedcsList.Quantity > listBoxSelectedcsList.BaseQuantity)) + { + //ListId为空则是没有在套餐里的药,库存量大于使用量时需要把药还到抽屉里 + //列出需要还到抽屉里的药品的抽屉库位 + @* + + + + + + + + + + + + + + + + *@ + @if (listBoxSelectedcsList?.DrawerChanneStockList != null) + { + + + + } + @* + *@ + } + + + + + @* + + + *@ + + + + + + + + + + + + +
+
+@*
*@ +@code { + private readonly ILog logger = LogManager.GetLogger(typeof(CheckOrder)); + @inject IOrderInfoDao orderInfoDao; + @inject DialogService dialogService; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject NotificationService _message; + @inject IReportDataDao reportDataDao; + @inject IOptions setting; + //bool allowRowSelectOnRowClick = true; + IEnumerable csList; + IList selectedcsList; + ChannelStock listBoxSelectedcsList = new(); + ChannelStock returnList = new(); + IEnumerable orderList; + IList selectedOrderList; + RadzenListBox listBox; + RadzenDataGrid gridOrder; + + //麻醉师集合 + List NamesList = new List(); + Anaesthetist NameInfo; + BoxModel BoxColor; + //全部药盒集合 + List AllBoxList = new List(); + //药盒集合 + List BoxList = new List(); + //药盒颜色集合 + List BoxColorList = new List() + { + new BoxModel{BoxNo=1,BoxName=1 }, + new BoxModel{BoxNo=2 ,BoxName=1}, + new BoxModel{BoxNo=3 ,BoxName=1} + }; + BoxModel BoxNum; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int status = 0; + string OrderNo; + string PatientName; + DateTime? OrderDate = DateTime.Now; + DateTime PortOrderDate = DateTime.Now; + Popup popup; + RadzenButton button; + private async Task OnColorChanged(object value) + { + if ((((BoxModel)value).BoxNo) == 3) + { + BoxList = AllBoxList.Where(bl => bl.BoxName > 30).ToList(); + BoxNum = BoxList.FirstOrDefault(); + await InvokeAsync(StateHasChanged); + } + else + { + BoxList = AllBoxList.Where(bl => bl.BoxNo == ((BoxModel)value).BoxNo && bl.BoxName <= 30).ToList(); + BoxNum = BoxList.FirstOrDefault(); + } + await LoadData(null); + + } + //药箱选中修改 + private async Task OnBoxChanged(object value) + { + // BoxList = BoxList.Where(bl => bl.BoxNo == ((BoxModel)value).BoxNo && bl.BoxName == ((BoxModel)value).BoxName).ToList(); + BoxNum = (BoxModel)value; + + await LoadData(null); + } + bool? boolHeader = true; + //全选/反选 + void ChangeHeaderCheckBox(bool? args) + { + if (args != null) + { + boolHeader = args; + listBoxSelectedcsList?.OrderList.ToList().ForEach(it => it.ItemIsChecked = (bool)args); + } + } + void OnCheckSeleced(object dete) + { + //listBoxSelectedcsList?.OrderList.ToList().Where(it => it.OrderNo == (OrderInfo as (dete).))(oi => oi.ItemIsChecked = true)); + } + //日期修改 + async Task OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + + await LoadData(null); + } + void OnCurrentPortDateChanged(DateTime args) + { + PortOrderDate = new DateTime(args.Year, args.Month, args.Day); + } + void OnDrugCellClick(DataGridCellMouseEventArgs args) + { + + } + void OnCellClick(DataGridCellMouseEventArgs args) + { + if (args.Data.DetailInfo.SetManuNo != null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.Where(m => m.ManuNo == args.Data.DetailInfo.SetManuNo).FirstOrDefault(); + } + if (args.Data.DetailInfo.drugManuNo == null) + { + args.Data.DetailInfo.drugManuNo = args.Data.DetailInfo.Drug.Manus.FirstOrDefault(); + } + args.Data.ItemIsChecked = !args.Data.ItemIsChecked; + // gridOrder.EditRow(args.Data); + } + //查询 + async Task Search() + { + await LoadData(null); + } + //确认 + async Task Confirm() + { + csList = csList.ToList(); + List checkChannelStock = new(); + string errMessage = string.Empty; + foreach (var item in csList) + { + if (item.SelectedOrderList.Aggregate(0, (a, b) => a + b.DetailInfo.Quantity)>item.Quantity) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"用药数不可大于库存数,请仔细核对!", Duration = 4000 } + ); + return; + } + int i = 0; + if (item.OrderList != null && item.SelectedOrderList.Count > 0) + { + item.UseQuantity = item.SelectedOrderList.Sum(oi => oi.DetailInfo.Quantity); + item.OrderQuantity = item.SelectedOrderList.Count; + // checkChannelStock.Add(item); + i = 1; + } + if (item.DrawerChanneStockList != null && item.DrawerChanneStockList.Any(d => d.ReturnQuantity > 0)) + { + //还药数量:使用量==库存?还0 :库存>基数? (库存数-使用数)>基数? 还 库存数-使用数:0; + item.ReturnQuantity = + (item.UseQuantity == item.Quantity) ? 0 : + (item.Quantity <= item.BaseQuantity) ? 0 : + ((item.Quantity - item.UseQuantity) > item.BaseQuantity) ? + (item.Quantity - item.UseQuantity - item.BaseQuantity) : 0; + //还药库位 + if (item.ReturnQuantity > 0) + { + //药品未在套餐中绑定需要把药还到对应抽屉 + List allDrugStock = await orderInfoDao.GetStockByDRrug(item.DrugId, item.ManuNo, 1);// await _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 1 && cs.DrugId == csList[i].DrugId && cs.ManuNo == csList[i].ManuNo).OrderBy(cs => cs.Quantity).ToListAsync(); + if (allDrugStock != null && allDrugStock.Count > 0) + { + item.DrawerChanneStockList = new(); + int iReturnQuantity = item.Quantity - item.UseQuantity - item.BaseQuantity; + for (int j = 0; j < allDrugStock.Count; j++) + { + if (allDrugStock[j].BoardType.ToString().Contains("2") && allDrugStock[j].Quantity >= 25) + continue; + if (allDrugStock[j].BoardType.ToString().Contains("2") && allDrugStock[j].Quantity + item.Quantity - item.UseQuantity > 25) + { + if (iReturnQuantity <= allDrugStock.Sum(it => it.Quantity)) + { + for (int q = 0; iReturnQuantity > 0; q++) + { + + allDrugStock[j].ReturnQuantity = 25 - allDrugStock[q].Quantity; + item.DrawerChanneStockList.Add(allDrugStock[q]); + iReturnQuantity = iReturnQuantity - allDrugStock[q].ReturnQuantity; + if (iReturnQuantity <= 0) + break; + } + } + else + { + //库位不足,有药品无库位可放 + allDrugStock[j].ReturnQuantity = iReturnQuantity; + item.DrawerChanneStockList.Add(allDrugStock[j]); + logger.Info($"还药品【{item.Drug.DrugName}】库位不足,有药品无库位可放"); + errMessage += $"库位不足,药品【{item.Drug.DrugName}】无库位可放"; + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = errMessage, Duration = 4000 } + ); + break; ; + } + } + else + { + allDrugStock[j].ReturnQuantity = iReturnQuantity; + item.DrawerChanneStockList.Add(allDrugStock[j]); + break; + } + } + } + } + // checkChannelStock.Add(item); + i = 1; + } + + //还空瓶数 + item.EmptyQuantity = item.SelectedOrderList.Sum(oi => oi.DetailInfo.Quantity); + if (item.EmptyQuantity > 0) + { + //还空瓶库位 + //查询还空瓶库位 + //checkChannelStock[i].EmptyStock; + + List allDrugStock = await orderInfoDao.GetStockByDRrug(item.DrugId, item.ManuNo, 2);// await _connection.ChannelStock.Where(cs => cs.MachineId == _setting.machineId && cs.DrawerType == 1 && cs.DrugId == csList[i].DrugId && cs.ManuNo == csList[i].ManuNo).OrderBy(cs => cs.Quantity).ToListAsync(); + if (allDrugStock.Count > 0) + { + item.EmptyStock = allDrugStock.FirstOrDefault(); + item.EmptyStock.ReturnQuantity = item.EmptyQuantity; + i = 1; + } + // checkChannelStock.Add(item); + } + if (i == 1) + { + checkChannelStock.Add(item); + } + } + if (errMessage.Length > 0) + { + return; + } + if (checkChannelStock == null || checkChannelStock.Count <= 0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"无可操作的数据", Duration = 4000 } + ); + return; + } + // //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"核对确认", + new Dictionary() { { "csList", checkChannelStock } }, + new DialogOptions() { Width = "90vw", Resizable = true, Draggable = true, ShowClose = false }); + // if (b) + // { + // bool bResult = await orderInfoDao.CheckOrderInfoByChannelStock(csList.ToList(), BoxNum); + // if (bResult) + // { + // _message.Notify( + // new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"处方已核对完成", Duration = 4000 } + // ); + // await LoadData(null); + // } + // else + // { + // _message.Notify( + // new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"处方已核对失败", Duration = 4000 } + // ); + // } + // } + if (b) + { + LoadData(null); + } + + } + //导处方 + async Task AddOrderMethod() + { + var b = await dialogService.OpenAsync( + $"导入处方信息", + new Dictionary() { { "boxModel", BoxNum } }, + new DialogOptions() { Width = "80vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b != null) + { + try + { + + List importOrderInfo = b; + if (importOrderInfo.Count > 0) + { + string errorMessage = string.Empty; + for (int i = 0; i < importOrderInfo.Count; i++) + { + if (!(bool)listBoxSelectedcsList?.OrderList.Contains(importOrderInfo[i])) + { + if (csList.Where(c => c.DrugId == importOrderInfo[i].DetailInfo.DrugId && c.ManuNo == importOrderInfo[i].DetailInfo.SetManuNo).FirstOrDefault() == null) + { + errorMessage += $"处方{importOrderInfo[i].OrderNo}导入失败,药品{importOrderInfo[i].DetailInfo.Drug.DrugName}不存在或批次{importOrderInfo[i].DetailInfo.SetManuNo}不存在"; + } + else + { + csList.Where(c => c.DrugId == importOrderInfo[i].DetailInfo.DrugId && c.ManuNo == importOrderInfo[i].DetailInfo.SetManuNo).FirstOrDefault()?.SelectedOrderList.Add(importOrderInfo[i]); + //csList.Where(c => c.DrugId == importOrderInfo[i].DetailInfo.DrugId && c.ManuNo == importOrderInfo[i].DetailInfo.SetManuNo).FirstOrDefault()?.OrderList.Add(importOrderInfo[i]); + } + } + csList = csList; + } + if (!string.IsNullOrEmpty(errorMessage)) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = errorMessage, Duration = 4000 } + ); + return; + } + else + { + StateHasChanged(); // 刷新UI + } + } + } + catch (Exception) + { + + } + + } + } + + PageData result; + protected override async Task OnInitializedAsync() + { + BoxColor = BoxColorList.FirstOrDefault(); + AllBoxList = await orderInfoDao.GetOperationNum(0); + BoxList = AllBoxList.Where(bl => bl.BoxNo == BoxColor.BoxNo && bl.BoxName <= 30).ToList(); + BoxNum = AllBoxList.FirstOrDefault(); + await base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + string? roomName = BoxNum == null ? "" : setting.Value.roomName + BoxNum.BoxName.ToString().PadLeft(2, '0'); + result = await orderInfoDao.GetAllOrderInfoDrugByBox(BoxNum, roomName, OrderDate); + isLoading = true; + csList = result.Desserts; + if (csList != null && csList.Count() > 0) + { + listBoxSelectedcsList = csList.ElementAt(0); + } + count = result.TotalDesserts; + isLoading = false; + StateHasChanged(); // 刷新UI + } + //麻醉药品使用登记本导出 + async Task StockExport() + { + if (PortOrderDate == DateTime.MinValue) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择处方时间再导出", Duration = 4000 } + ); + return; + } + // PageData pageParentData = await reportDataDao.GetOrderInfoParentData(PortOrderDate); + // PageData pageData = await reportDataDao.GetOrderInfoData(PortOrderDate); + + List pageParentData = await reportDataDao.GetOrderInfoParentData(PortOrderDate); + List pageData = await reportDataDao.GetOrderInfoData(PortOrderDate); + Dictionary parameters = new Dictionary(); + parameters.Add("parent", pageParentData); + parameters.Add("child", pageData); + GridReportUtil.PrintReport("use_book.grf", parameters); + } + // protected override async Task OnInitializedAsync() + // { + // await base.OnInitializedAsync(); + + // // orderInfos = dbContext.Employees; + + // var result = await orderInfoDao.GetAllOrderInfo(OrderNo, OrderDate, args.Top, args.Skip); + // // Update the Data property + // orderInfos = result.Desserts; + // // Update the count + // count = result.TotalDesserts; + + // isLoading = false; + // } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/ConfirmDialog.razor b/MasaBlazorApp3/Pages/ConfirmDialog.razor new file mode 100644 index 0000000..d97134b --- /dev/null +++ b/MasaBlazorApp3/Pages/ConfirmDialog.razor @@ -0,0 +1,28 @@ + + + + @(confirmInfo) + + + + + + + + + + +@code { + @inject Radzen.DialogService dialogService; + [Parameter] public string confirmInfo { get; set; } + protected override async Task OnInitializedAsync() + { + var info = confirmInfo; + base.OnInitializedAsync(); + } + async Task ConfirmOK() + { + // 关闭弹窗 + dialogService.Close(true); + } +} diff --git a/MasaBlazorApp3/Pages/Demo.razor b/MasaBlazorApp3/Pages/Demo.razor new file mode 100644 index 0000000..424c1d6 --- /dev/null +++ b/MasaBlazorApp3/Pages/Demo.razor @@ -0,0 +1,77 @@ +@page "/Box/CheckDDD" +@using Radzen.Blazor +@using System.ComponentModel + + +@* + + + + + + + + + + *@ + +@code { + RadzenDataGrid grid; + List orders = new(); + IEnumerable summaryData; + + protected override void OnInitialized() + { + // 模拟数据 + orders = new List { + new Order { Category = "电子产品", Quantity = 15 }, + new Order { Category = "电子产品", Quantity = 8 }, + new Order { Category = "家居用品", Quantity = 23 } + }; + + CalculateSummary(); + } + + void CalculateSummary() + { + summaryData = orders + .GroupBy(o => o.Category) + .Select(g => new + { + Category = g.Key, + TotalQuantity = g.Sum(x => x.Quantity) + }).ToList(); + } + + public class Order : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public string Category { get; set; } + private int _quantity; + public int Quantity + { + get => _quantity; + set + { + _quantity = value; + PropertyChanged?.Invoke(this, + new PropertyChangedEventArgs(nameof(Quantity))); + } + } + } +} diff --git a/MasaBlazorApp3/Pages/DrawerAdd.razor b/MasaBlazorApp3/Pages/DrawerAdd.razor new file mode 100644 index 0000000..4d2f738 --- /dev/null +++ b/MasaBlazorApp3/Pages/DrawerAdd.razor @@ -0,0 +1,538 @@ +@page "/add/drawer" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + +
+ @if (DrawerNos.Count() > 8) + { +
+
+ @foreach (int i in DrawerNos) + { + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(i)) + { + + } + else + { + + } + } +
+
+ } + else + { +
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
+ } +
+ + + + @if (status < 3) + { + + } + @if (status == 3) + { + + } + @if (status > 0 && status <= 3) + { + + } + + + + + + + + + + + + @if (channel.Quantity == 0 && !String.IsNullOrEmpty(channel.DrugId)) + { + + + + + @((context as DrugManuNo)?.ManuNo) + @if ((context as DrugManuNo).EffDate != null && (context as DrugManuNo).EffDate.ToString().Length > 10) + { + + @((context as DrugManuNo).EffDate.ToString().Substring(0, 10)) + } + else + { + + @((context as DrugManuNo)?.EffDate) + } + + + + + } + else + { + + @channel.drugManuNo?.ManuNo + @channel.drugManuNo?.EffDate + } + + + + + + + +
+ 加药
数量 +
+
+ + @if (cs.BoardType.ToString().Contains("2") || cs.BoardType.ToString().Contains("3")) + { + @cs.AddQuantity + } + else + { + + + } + +
+
+
+ +
+@code { + @inject IChannelListDao channelListDao; + @inject NavigationManager na; + @inject PortUtil PortUtil; + @inject NotificationService _message + @inject IOptions setting; + int status = 0; + int drawerNo = 1; + RadzenDataGrid grid; + private List? channels; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + private readonly ILog logger = LogManager.GetLogger(typeof(DrawerAdd)); + + // 当前操作的库位号列表 + public List ColNos { get; set; } = new List(); + int currentCol = 0; + bool CompleteIsEnable = true; + bool CancleIsEnable = true; + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelListDao.GetChannelStockByDrawerNoWithDrawers(drawerNo); + // var result = await channelListDao.GetChannelStockByDrawerNo(drawerNo); + // Update the Data property + DrawerNos = result.DrawerArray; + channels = result.ChannelStocks; + // Update the count + count = result.ChannelStocks.Count; + + + isLoading = false; + } + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + PortUtil.DrawerNo = this.drawerNo; + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + await promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + // 判断是否为单支抽屉 + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + } + // 判断是否为称重抽屉 + // if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + // { + // //开抽屉前先查数 + // for (int i = 0; i < 9; i++) + // { + // int beforeQuantity = await PortUtil.CheckQuantityForSingle(i + 1); + // BeforeQuantity[i] = beforeQuantity; + // logger.Info($"BeforeQuantity:{i++}-{beforeQuantity}数量{string.Join(",", BeforeQuantity)}"); + // } + // } + + var b = await PortUtil.OpenDrawerStatus(this.drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,加药"); + this.status = 2; + PortUtil.Operate = true; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + RestData(); + PortUtil.Operate = false; + stop(); + } + + } + // 检测状态 + else if (this.status == 2) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"加药完成,请,核对,或,录入,正确的,添加数量"); + // 判断是否为称重抽屉 + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + //关闭抽屉后获取称重稳定数量 + await GetWeightQuantity(); + } + this.status = 3; + PortUtil.Operate = false; + stop(); + } + else + { + //药盒抽屉,开药盒 + if (setting.Value.box != null && setting.Value.box.Contains(this.drawerNo)) + { + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + if (currentCol > 0) + { + //开药盒前先查数 + int beforeQuantity = await PortUtil.CheckQuantityForSingle(currentCol); + BeforeQuantity[currentCol - 1] = beforeQuantity; + logger.Info($"BeforeQuantity:{currentCol}-{beforeQuantity}数量{string.Join(",", BeforeQuantity)}"); + await Task.Delay(200); + ColNos.Add(currentCol); + } + } + //药盒抽屉,开药盒 + if (currentCol > 0) + { + await PortUtil.OpenBoxByColNo(currentCol); + } + currentCol = 0; + } + + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + channels.ForEach(cl => + { + cl.AddQuantity = this.AfterQuantity[cl.ColNo - 1] - this.BeforeQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + // 判断是否为称重抽屉 + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + //开抽屉后查数 + for (int i = 0; i < ColNos.Count; i++) + { + int afterQuantity = await PortUtil.CheckQuantityForSingle(ColNos[i]); + AfterQuantity[ColNos[i] - 1] = afterQuantity; + logger.Info($"AfterQuantity:{ColNos[i]}-{string.Join(",", AfterQuantity)}数量{string.Join(", ", BeforeQuantity)}"); + } + channels.Where(cl => ColNos.Contains(cl.ColNo)).ToList().ForEach(cl => + { + cl.AddQuantity = this.AfterQuantity[cl.ColNo - 1] - this.BeforeQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + next(); // continue iteration + } + + } + } + catch (Exception e) + { + logger.Info($"抽屉加药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + PortUtil.PowerOff(); + } + RestData(); + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + this.BeforeQuantity = new int[9]; + this.AfterQuantity = new int[9]; + currentCol = 0; + ColNos.Clear(); + } + //关闭抽屉后获取称重稳定数量 + public async Task GetWeightQuantity() + { + List finallyQuantity = new List(); + await new PromiseUtil().taskAsyncLoop(200, 0, async (options, next, stop) => + { + if (!PortUtil.Operate || this.status == 0) + { + stop(); + } + else + { + try + { + logger.Info("关闭抽屉后获取称重稳定数量"); + if (finallyQuantity.Count >= 10) + { + for (int i = 0; i < finallyQuantity.Count; i++) + { + logger.Info($"finallyQuantity{i} {string.Join(",", finallyQuantity[i])}"); + } + if (AreAllArraysEqual(finallyQuantity)) + { + stop(); + channels.ForEach(cl => + { + cl.AddQuantity = this.AfterQuantity[cl.ColNo - 1] - this.BeforeQuantity[cl.ColNo - 1]; + }); + CompleteIsEnable = true; + CancleIsEnable = true; + logger.Info("对比成功停止循环"); + await InvokeAsync(StateHasChanged); + } + else + { + finallyQuantity.RemoveAt(0); + next(); + } + } + else + { + if (finallyQuantity.Count >= 9) + { + CancleIsEnable = true; + } + else + { + CancleIsEnable = false; + } + CompleteIsEnable = false; + PortUtil.DrawerNo = drawerNo; + PortUtil.ColNoLst = ColNos; + int[] quantity = await PortUtil.CheckQuantityByAddrForMulti(); + AfterQuantity = quantity; + int[] Quantitys = new int[BeforeQuantity.Length]; + for (int i = 0; i < BeforeQuantity.Length; i++) + { + Quantitys[i] = BeforeQuantity[i] - AfterQuantity[i]; + } + finallyQuantity.Add(Quantitys); + logger.Info($"Quantity{string.Join(",", Quantitys)}"); + + channels.ForEach(cl => + { + cl.AddQuantity = this.AfterQuantity[cl.ColNo - 1] - this.BeforeQuantity[cl.ColNo - 1]; + }); + next(); + } + } + catch (Exception ex) + { + logger.Info($"关闭抽屉后获取称重稳定数量异常{ex.Message}"); + next(); + } + } + }); + } + public bool AreAllArraysEqual(List arrays) + { + if (arrays == null || arrays.Count == 0) return false; + // 取第一个数组作为参照进行比较 + var referenceArray = arrays[0]; + // 检查列表中除了第一个数组外的所有数组是否与第一个数组相等 + return arrays.Skip(1).All(array => array.SequenceEqual(referenceArray)); + } + async Task AddFinish() + { + if (channels.Any(cl => cl.AddQuantity != 0 && cl.DrugId != null && cl.drugManuNo != null)) + { + // 保存账册、操作记录 + var b = await channelListDao.DrawerOperationFinish(channels.Where(cl => cl.AddQuantity != 0).ToList(), 1,null,null); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉加药保存数据库失败,数据{JsonConvert.SerializeObject(channels)}"); + } + else + { + // 判断是否为标签抽屉 + if (setting.Value != null && setting.Value.label != null && setting.Value.label.Contains(this.drawerNo)) + { + //写标签数量 + channels.Where(it => it.AddQuantity > 0).ToList().ForEach(async it => + { + await PortUtil.WriteQuantityMethod(it.Quantity + it.AddQuantity, it.DrawerNo, it.ColNo); + await Task.Delay(20); + }); + } + ColNos.Clear(); + } + } + + //重置状态 + this.RestData(); + // 重新查询库存 + await grid.Reload(); + } + + void Cancel() + { + RestData(); + } + + void SelectDrawer(int drawerNo) + { + this.drawerNo = drawerNo; + grid.Reload(); + } + + void OnCellClick(DataGridCellMouseEventArgs args) + { + // if (args.Data.BoardType.ToString().Contains("3")) + // { + // //是药盒抽屉则点击行,打开对应行的药盒 + // if (!ColNos.Contains(args.Data.ColNo)) + // { + // ColNos.Add(args.Data.ColNo); + // } + // } + if (setting.Value.box.Contains(args.Data.DrawerNo) && status != 2) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("请先点取药按钮打开抽屉"); + } + currentCol = args.Data.ColNo; + grid.EditRow(args.Data); + } + private IDisposable? registration; + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + registration = na.RegisterLocationChangingHandler(OnLocationChanging); + } + } + + private ValueTask OnLocationChanging(LocationChangingContext context) + { + // 操作中不可跳转页面 + if (status > 0) + { + context.PreventNavigation(); //阻止导航 + } + return ValueTask.CompletedTask; + } + //在生命周期函数Dispose中,移除订阅的事件,并销毁非托管资源registration=========================================== + public void Dispose() + { + registration?.Dispose(); + } +} diff --git a/MasaBlazorApp3/Pages/DrawerTake.razor b/MasaBlazorApp3/Pages/DrawerTake.razor new file mode 100644 index 0000000..482c0b8 --- /dev/null +++ b/MasaBlazorApp3/Pages/DrawerTake.razor @@ -0,0 +1,603 @@ +@page "/take/drawer" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + +
+ @if (DrawerNos.Count() > 8) + { +
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
+ } + else + { +
+
+ @foreach (int i in DrawerNos) + { + + + } +
+
+ } +
+ + + + @if (status < 3) + { + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(drawerNo)) + { + + + } + else + { + + } + } + @if (status == 3) + { + + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(drawerNo)) + { } + else + { + + + + + + + + + + + + + + } + + } + @if (status > 0 && status <= 3) + { + + } + + + + + + + + + + + + + + + +
+ 取药
数量 +
+
+ + @if (channel.BoardType.ToString().Contains("2") || channel.BoardType.ToString().Contains("3")) + { + @channel.TakeQuantity + } + else + { + + @* *@ + } + +
+
+
+ +
+@code { + @inject IChannelListDao channelListDao; + @inject NavigationManager na; + @inject PortUtil PortUtil; + @inject NotificationService _message + @inject IOptions setting; + + @inject IOrderInfoDao orderInfoDao; + int status = 0; + int drawerNo = 1; + RadzenDataGrid grid; + private List? channels; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + + // 当前操作的库位号列表 + public List ColNos { get; set; } = new List(); + int currentCol = 0; + bool CompleteIsEnable = true; + bool CancleIsEnable = true; + + BoxModel BoxNum; + + + BoxModel BoxColor; + //全部药盒集合 + List AllBoxList = new List(); + //药盒集合 + List BoxList = new List(); + //药盒颜色集合 + List BoxColorList = new List() + { + new BoxModel{BoxNo=1,BoxName=1 }, + new BoxModel{BoxNo=2 ,BoxName=1}, + new BoxModel{BoxNo=3 ,BoxName=1} + }; + private readonly ILog logger = LogManager.GetLogger(typeof(DrawerTake)); + protected override async Task OnInitializedAsync() + { + BoxColor = BoxColorList.FirstOrDefault(); + AllBoxList = await orderInfoDao.GetOperationNum(0); + BoxList = AllBoxList.Where(bl => bl.BoxNo == BoxColor.BoxNo && bl.BoxName <= 30).ToList(); + BoxNum = AllBoxList.FirstOrDefault(); + await base.OnInitializedAsync(); + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + // var result = await channelListDao.GetChannelStockByDrawerNo(drawerNo, 1); + var result = await channelListDao.GetChannelStockByDrawerNoWithDrawers(drawerNo, 1); + DrawerNos = result.DrawerArray; + // Update the Data property + channels = result.ChannelStocks; + // Update the count + count = result.ChannelStocks.Count; + + + isLoading = false; + } + private async Task OnColorChanged(object value) + { + if ((((BoxModel)value).BoxNo) == 3) + { + BoxList = AllBoxList.Where(bl => bl.BoxName > 30).ToList(); + BoxNum = BoxList.FirstOrDefault(); + await InvokeAsync(StateHasChanged); + } + else + { + BoxList = AllBoxList.Where(bl => bl.BoxNo == ((BoxModel)value).BoxNo && bl.BoxName <= 30).ToList(); + BoxNum = BoxList.FirstOrDefault(); + } + } + //药箱选中修改 + private async Task OnBoxChanged(object value) + { + // BoxList = BoxList.Where(bl => bl.BoxNo == ((BoxModel)value).BoxNo && bl.BoxName == ((BoxModel)value).BoxName).ToList(); + BoxNum = (BoxModel)value; + } + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + PortUtil.DrawerNo = this.drawerNo; + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + await promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + // 判断是否为单支抽屉 + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + } + + var b = await PortUtil.OpenDrawerStatus(this.drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(drawerNo)) + { + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取空瓶"); + } + else + { + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + } + PortUtil.Operate = true; + this.status = 2; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + RestData(); + stop(); + } + + } + // 检测状态 + else if (this.status == 2) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(drawerNo)) + { + + PortUtil.SpeakAsync($"取空瓶完成,请核对或录入正确的取出数量"); + } + else + { + PortUtil.SpeakAsync($"取药完成,请核对或录入正确的取出数量"); + } + // 判断是否为称重抽屉 + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + //关闭抽屉后获取称重稳定数量 + await GetWeightQuantity(); + } + logger.Info($"关闭抽屉,称重抽屉获取稳定数量后日志"); + this.status = 3; + PortUtil.Operate = false; + stop(); + } + else + { + if (setting.Value.box != null && setting.Value.box.Contains(this.drawerNo)) + { + // 判断是否为称重抽屉 + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + //开抽屉前先查数 + if (currentCol > 0) + { + int beforeQuantity = await PortUtil.CheckQuantityForSingle(currentCol); + BeforeQuantity[currentCol - 1] = beforeQuantity; + logger.Info($"BeforeQuantity:{currentCol}-{beforeQuantity}数量{string.Join(",", BeforeQuantity)}"); + await Task.Delay(200); + ColNos.Add(currentCol); + } + } + //药盒抽屉,开药盒 + if (currentCol > 0) + { + await PortUtil.OpenBoxByColNo(currentCol); + } + currentCol = 0; + } + + + if (setting.Value.single != null && setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + if (!BeforeQuantity.SequenceEqual(AfterQuantity)) + { + channels.ForEach(cl => + { + cl.TakeQuantity = this.BeforeQuantity[cl.ColNo - 1] - this.AfterQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + } + // 判断是否为称重抽屉 + if (setting.Value.weigh != null && setting.Value.weigh.Contains(this.drawerNo)) + { + //开抽屉后查数 + for (int i = 0; i < ColNos.Count; i++) + { + int afterQuantity = await PortUtil.CheckQuantityForSingle(ColNos[i]); + AfterQuantity[ColNos[i] - 1] = afterQuantity; + logger.Info($"AfterQuantity:{ColNos[i]}-{afterQuantity}数量{string.Join(",", AfterQuantity)}"); + } + if (!BeforeQuantity.SequenceEqual(AfterQuantity)) + { + channels.Where(cl => ColNos.Contains(cl.ColNo)).ToList().ForEach(cl => + { + cl.TakeQuantity = this.BeforeQuantity[cl.ColNo - 1] - this.AfterQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + } + next(); // continue iteration + } + + } + } + catch (Exception e) + { + logger.Info($"抽屉取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(this.drawerNo)) + { + PortUtil.PowerOff(); + } + RestData(); + stop(); + } + }); + PortUtil.PowerOff(); + } + //关闭抽屉后获取称重稳定数量 + public async Task GetWeightQuantity() + { + List finallyQuantity = new List(); + await new PromiseUtil().taskAsyncLoop(200, 0, async (options, next, stop) => + { + if (!PortUtil.Operate || this.status == 0) + { + stop(); + CancleIsEnable = true; + CompleteIsEnable = true; + logger.Info($"停止循环{!PortUtil.Operate}-{this.status}"); + } + else + { + try + { + logger.Info("关闭抽屉后获取称重稳定数量"); + if (finallyQuantity.Count >= 10) + { + for (int i = 0; i < finallyQuantity.Count; i++) + { + logger.Info($"finallyQuantity{i} {string.Join(",", finallyQuantity[i])}"); + } + if (AreAllArraysEqual(finallyQuantity)) + { + stop(); + CancleIsEnable = true; + CompleteIsEnable = true; + + logger.Info("对比成功停止循环"); + + channels.ForEach(cl => + { + cl.TakeQuantity = this.BeforeQuantity[cl.ColNo - 1] - this.AfterQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + else + { + finallyQuantity.RemoveAt(0); + CancleIsEnable = true; + next(); + } + } + else + { + if (finallyQuantity.Count >= 9) + { + CancleIsEnable = true; + } + else + { + CancleIsEnable = false; + } + CompleteIsEnable = false; + PortUtil.DrawerNo = drawerNo; + PortUtil.ColNoLst = ColNos; + int[] quantity = await PortUtil.CheckQuantityByAddrForMulti(); + AfterQuantity = quantity; + int[] Quantitys = new int[BeforeQuantity.Length]; + for (int i = 0; i < BeforeQuantity.Length; i++) + { + Quantitys[i] = BeforeQuantity[i] - AfterQuantity[i]; + } + finallyQuantity.Add(Quantitys); + logger.Info($"Quantity{string.Join(",", Quantitys)}"); + if (!BeforeQuantity.SequenceEqual(AfterQuantity)) + { + channels.ForEach(cl => + { + cl.TakeQuantity = this.BeforeQuantity[cl.ColNo - 1] - this.AfterQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + next(); + } + } + catch (Exception ex) + { + logger.Info($"关闭抽屉后获取称重稳定数量异常{ex.Message}"); + next(); + } + } + }); + } + public bool AreAllArraysEqual(List arrays) + { + if (arrays == null || arrays.Count == 0) return false; + // 取第一个数组作为参照进行比较 + var referenceArray = arrays[0]; + // 检查列表中除了第一个数组外的所有数组是否与第一个数组相等 + return arrays.Skip(1).All(array => array.SequenceEqual(referenceArray)); + } + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + this.BeforeQuantity = new int[9]; + this.AfterQuantity = new int[9]; + ColNos.Clear(); + currentCol = 0; + + // InvokeAsync(StateHasChanged); + } + + async Task TakeFinish() + { + if (channels.Any(cl => cl.TakeQuantity != 0)) + { + CheckInfo checkInfo = null; + // if(BoxNum!=null&&BoxNum.BoxNo!=0) + // { + // //查询本次加药的药盒里是否有绑该药,有则正常入库,无则提示无绑定不可添加 + // checkInfo = await channelListDao.CheckBoxDrugInfo(BoxNum, channels.Where(cl => cl.TakeQuantity != 0).ToList()); + // if (!string.IsNullOrEmpty(checkInfo.StrInfo)) + // { + // _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"该药盒中未绑定该批次药品无法添加", Duration = 4000 }); + // logger.Error($"该药盒中未绑定该批次药品无法添加,数据{JsonConvert.SerializeObject(channels)}"); + // return; + // } + // } + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(drawerNo)) + { + BoxNum = null; + } + // 保存账册、操作记录 + var b = await channelListDao.DrawerOperationFinish(channels.Where(cl => cl.TakeQuantity != 0).ToList(), 2, BoxNum, null); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉取药保存数据库失败,数据{JsonConvert.SerializeObject(channels)}"); + } + else + { + // 判断是否为标签抽屉 + if (setting.Value.label != null && setting.Value.label.Contains(this.drawerNo)) + { + //写标签数量 + channels.Where(it => it.TakeQuantity > 0).ToList().ForEach(async it => + { + await PortUtil.WriteQuantityMethod(it.Quantity - it.TakeQuantity, it.DrawerNo, it.ColNo); + }); + } + } + } + //重置状态 + this.RestData(); + // 重新查询库存 + await grid.Reload(); + } + + void Cancel() + { + RestData(); + } + + void SelectDrawer(int drawerNo) + { + this.drawerNo = drawerNo; + grid.Reload(); + } + + void OnCellClick(DataGridCellMouseEventArgs args) + { + // if (args.Data.BoardType.ToString().Contains("3")) + // { + // //是药盒抽屉则点击行,打开对应行的药盒 + // if (!ColNos.Contains(args.Data.ColNo)) + // { + // ColNos.Add(args.Data.ColNo); + // } + // } + // else + // { + // grid.EditRow(args.Data); + // } + if (setting.Value.box.Contains(args.Data.DrawerNo) && status != 2) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync("请先点取药按钮打开抽屉"); + } + currentCol = args.Data.ColNo; + grid.EditRow(args.Data); + } + private IDisposable? registration; + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + registration = na.RegisterLocationChangingHandler(OnLocationChanging); + } + } + + private ValueTask OnLocationChanging(LocationChangingContext context) + { + // 操作中不可跳转页面 + if (status > 0) + { + context.PreventNavigation(); //阻止导航 + } + return ValueTask.CompletedTask; + } + //在生命周期函数Dispose中,移除订阅的事件,并销毁非托管资源registration=========================================== + public void Dispose() + { + registration?.Dispose(); + } +} diff --git a/MasaBlazorApp3/Pages/DrugList.razor b/MasaBlazorApp3/Pages/DrugList.razor new file mode 100644 index 0000000..530b365 --- /dev/null +++ b/MasaBlazorApp3/Pages/DrugList.razor @@ -0,0 +1,350 @@ +@page "/stock/drug" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ @* + б + *@ + @if (SelectedDrugs.Count > 0) + { + +
+ + @* + + + + *@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ } +
+
+
+ +@code { + @inject IDrugInfoDao drugInfoDao; + @inject DialogService dialogService; + @inject IDrugManuNoDao drugManuNoDao; + RadzenDataGrid grid; + RadzenDataGrid ManusGrid; + + + List manuNoToInsert = new List(); + List manuNoToUpdate = new List(); + + bool isLoading; + int count; + private IEnumerable? _forecasts; + + IList SelectedDrugs { get; set; } = new List(); + string DrugId; + string DrugName; + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await drugInfoDao.GetAllDrug(DrugId, DrugName, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + count = result.TotalDesserts; + SelectedDrugs = new List() { _forecasts.FirstOrDefault() }; + + isLoading = false; + } + + async Task reloadGrid() + { + DrugId = String.Empty; + DrugName = String.Empty; + await grid.Reload(); + } + + void Reset() + { + manuNoToInsert.Clear(); + manuNoToUpdate.Clear(); + } + void Reset(DrugManuNo drugManuNo) + { + manuNoToInsert.Remove(drugManuNo); + manuNoToUpdate.Remove(drugManuNo); + } + /// ҩƷ + async Task InsertDrugRow() + { + var drugInfo = new DrugInfo(); + drugInfo.Manus.Add(new DrugManuNo()); + SelectedDrugs.Add(drugInfo); + await grid.InsertRow(drugInfo); + } + // //ҩƷϢ + async Task OnDrugUpdateRow(DrugInfo drugInfo) + { + // ݿҩƷ + drugInfoDao.UpdateDrugInfo(drugInfo); + grid.Reload(); + } + //ҩƷϢ + async Task OnDrugCreateRow(DrugInfo drugInfo) + { + // ݿҩƷ + drugInfoDao.AddDrugInfo(drugInfo); + grid.Reload(); + } + async Task EditDrugRow(DrugInfo drugInfo) + { + drugInfoDao.UpdateDrugInfo(drugInfo); + await grid.EditRow(drugInfo); + } + async Task SaveDrugRow(DrugInfo drugInfo) + { + await grid.UpdateRow(drugInfo); + } + void CancelDrugEdit(DrugInfo drugInfo) + { + Reset(); + grid.CancelEditRow(drugInfo); + grid.Reload(); + } + async Task DeleteDrugRow(DrugInfo drugInfo) + { + Reset(); + if (!string.IsNullOrEmpty(drugInfo.DrugId)) + { + //ȷʾ + var b = await dialogService.OpenAsync( + $"ɾȷ", + new Dictionary() { { "confirmInfo", "ȷҪɾҩƷ" + drugInfo.DrugName + "" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b) + { + // ݿɾ + drugInfoDao.DeleteDrugInfo(drugInfo.DrugId); + } + grid.Reload(); + } + } + + /// + async Task InsertRow() + { + var drugManuNo = new Pojo.DrugManuNo() + { + // Id = Guid.NewGuid().ToString(), + DrugId = SelectedDrugs.FirstOrDefault().DrugId + }; + SelectedDrugs.FirstOrDefault().Manus.Add(drugManuNo); + await ManusGrid.InsertRow(drugManuNo); + } + + async Task EditRow(DrugManuNo drugManuNo) + { + + Reset(); + + manuNoToUpdate.Add(drugManuNo); + await ManusGrid.EditRow(drugManuNo); + } + async Task SaveRow(DrugManuNo drugManuNo) + { + drugManuNo.Id = string.IsNullOrEmpty(drugManuNo.Id) ? Guid.NewGuid().ToString() : drugManuNo.Id; + await ManusGrid.UpdateRow(drugManuNo); + } + + void CancelEdit(DrugManuNo drugManuNo) + { + Reset(drugManuNo); + // SelectedDrugs.FirstOrDefault().Manus.Remove(drugManuNo); + SelectedDrugs.FirstOrDefault().Manus.RemoveAll(mn=>string.IsNullOrEmpty(mn.Id)); + ManusGrid.CancelEditRow(drugManuNo); + ManusGrid.Reload(); + } + + async Task DeleteRow(DrugManuNo drugManuNo) + { + Reset(drugManuNo); + + if (SelectedDrugs.FirstOrDefault().Manus.Contains(drugManuNo)) + { + //ȷʾ + var b = await dialogService.OpenAsync( + $"ȷɾ", + new Dictionary() { { "confirmInfo", "ȷҪɾΣ" + drugManuNo.ManuNo + "" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + SelectedDrugs.FirstOrDefault().Manus.Remove(drugManuNo); + // ݿɾ + drugManuNoDao.DeleteDrugManuNo(drugManuNo.Id); + await ManusGrid.Reload(); + } + } + else + { + ManusGrid.CancelEditRow(drugManuNo); + await ManusGrid.Reload(); + } + } + void OnUpdateRow(DrugManuNo dm) + { + dm.Id = string.IsNullOrEmpty(dm.Id) ? Guid.NewGuid().ToString() : dm.Id; + Reset(dm); + + // ݿ + drugManuNoDao.UpdateDrugManuNo(dm); + ManusGrid.Reload(); + } + void OnCreateRow(DrugManuNo dm) + { + // ݿ + drugManuNoDao.AddDrugManuNo(dm); + manuNoToInsert.Remove(dm); + ManusGrid.Reload(); + } + +} diff --git a/MasaBlazorApp3/Pages/EditPasswordDialog.razor b/MasaBlazorApp3/Pages/EditPasswordDialog.razor new file mode 100644 index 0000000..573d5b3 --- /dev/null +++ b/MasaBlazorApp3/Pages/EditPasswordDialog.razor @@ -0,0 +1,136 @@ +@page "/EditPasswordDialog" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + @* + + @if (userI == 1) + { + + 操作人 @globalStateService.Operator?.NickName +

正在修改密码

+
+ } + else if (userI == 2) + { + + 复核人 @globalStateService.Reviewer?.NickName +

正在修改密码

+
+ } +
+
*@ + + + @* + 密码修改 + *@ + +
+ +
+ + +
+
+
+ +
+ + +
+
+
+ + +
+
+
+
+ +
+ +@code { + @inject NotificationService _message + @inject GlobalStateService globalStateService; + @inject IUserDao userDao; + @inject Radzen.DialogService dialogService; + + private Pojo.User loginModel = new(); + private readonly ILog logger = LogManager.GetLogger(typeof(LoginDialog)); + [Parameter] public int userI { get; set; } + + + private void Submit(Pojo.User user) + { + if (userI == 1) + { + user.Username = globalStateService.Operator.Username; + } + else if (userI == 2) + { + user.Username = globalStateService.Reviewer.Username; + } + else + { + return; + } + Pojo.User u = userDao.GetByUsername(loginModel.Username); + if (u != null) + { + if (Util.MD5.GetMD5Hash(loginModel.OldPassword).ToLower().Equals(u.Password)) + { + u.Password = loginModel.Password; + bool iRet=userDao.UpdateUserPassword(u); + if (iRet) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"修改完成,退出后登录请使用新密码", Duration = 4000 }); + logger.Error($"{loginModel.Username}修改密码失败,数据{JsonConvert.SerializeObject(u)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"修改失败", Duration = 4000 }); + logger.Error($"{loginModel.Username}修改密码失败,数据{JsonConvert.SerializeObject(u)}"); + // 关闭弹窗 + dialogService.Close(false); + } + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"原密码错误", Duration = 4000 } + ); + logger.Info($"用户【{u.Username}】修改密码,原密码输入错误"); + + } + + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"无此用户", Duration = 4000 } + ); + logger.Info($"修改密码没有用户:【{loginModel.Username}】"); + } + } + private void Exit() + { + dialogService.Close(false); + } +} diff --git a/MasaBlazorApp3/Pages/FingerRegDialog.razor b/MasaBlazorApp3/Pages/FingerRegDialog.razor new file mode 100644 index 0000000..381b818 --- /dev/null +++ b/MasaBlazorApp3/Pages/FingerRegDialog.razor @@ -0,0 +1,70 @@ +@page "/user/finger/{userId}" +@page "/finger/{userId}" +@using log4net; + + + + + + + + + + + + + + + +@code { + [Parameter] public int userId { get; set; } + + + @inject DialogService dialogService; + @inject FingerprintUtil FingerprintUtil; + + + private readonly ILog logger = LogManager.GetLogger(typeof(FingerRegDialog)); + + List fingerNames = new List() + { + "左小拇指","左无名指","左中指", "左食指", "左大拇指", "右小拇指", "右无名指", "右中指" ,"右食指", "右大拇指" + + }; + + string fingerName = "左小拇指"; + bool regLoading = false; + + + void RegZWJSubmit() + { + regLoading = true; + InvokeAsync(StateHasChanged); + FingerprintUtil.axCZKEM1.OnEnrollFingerEx += axCZKEM1_OnEnrollFingerEx; + FingerprintUtil.SaveFingerprint(userId, fingerNames.FindIndex(n => n.Equals(fingerName))); + } + + void RegZWJCancel() + { + + FingerprintUtil.axCZKEM1.CancelOperation(); + regLoading = false; + InvokeAsync(StateHasChanged); + FingerprintUtil.axCZKEM1.OnEnrollFingerEx -= axCZKEM1_OnEnrollFingerEx; + dialogService.Close(); + } + + private void axCZKEM1_OnEnrollFingerEx(string iEnrollNumber, int iFingerIndex, int iActionResult, int iTemplateLength) + { + + FingerprintUtil.axCZKEM1.StartIdentify(); + FingerprintUtil.axCZKEM1.RefreshData(1); + regLoading = false; + InvokeAsync(StateHasChanged); + dialogService.Close(); + logger.Info($"触发用户登记指纹事件1,用户id:{iEnrollNumber}指纹索引:{iFingerIndex}登记结果:{(iActionResult == 0)}"); + FingerprintUtil.axCZKEM1.OnEnrollFingerEx -= axCZKEM1_OnEnrollFingerEx; + + } + +} diff --git a/MasaBlazorApp3/Pages/FridgeSetting.razor b/MasaBlazorApp3/Pages/FridgeSetting.razor new file mode 100644 index 0000000..da60a45 --- /dev/null +++ b/MasaBlazorApp3/Pages/FridgeSetting.razor @@ -0,0 +1,119 @@ +@page "/manage/setting/Fridge" +@using MasaBlazorApp3.Util +@using Newtonsoft.Json.Linq +@using log4net +@layout SettingLayout +
+
+ + + 保存设置 + + +
+ +
+ + + + 冰箱温度区间 + + + + 冰箱状态 + fridgeStateValue = args)> + + + + + + + + 报警状态 + + + + + + + + + +
+
+ + +@inject Microsoft.Extensions.Options.IOptions setting; +@inject PortUtil port; +@inject NotificationService _message + +@code { + private readonly ILog logger = LogManager.GetLogger(typeof(LoginDialog)); + int fridgeStateValue = 1; + int alertStateValue = 1; + string temperatureRange = "2-8"; + protected override void OnInitialized() + { + fridgeStateValue = setting.Value.fridgeState; + alertStateValue = setting.Value.alertState; + temperatureRange = setting.Value.temperatureRange; + base.OnInitialized(); + } + //保存 + async Task SaveMethod() + { + // 获取当前工作目录 + string currentDirectory = Directory.GetCurrentDirectory(); + // setting.Value.fridgeState = fridgeStateValue; + // setting.Value.alertState = alertStateValue; + // setting.Value.temperatureRange = temperatureRange; + string filePath =Path.Combine(currentDirectory, "appsettings.json"); + string jsonString= File.ReadAllText(filePath); + var jsonNode = JObject.Parse(jsonString); + jsonNode["fridge"]["temperatureRange"] = temperatureRange; + jsonNode["fridge"]["fridgeState"]= fridgeStateValue; + jsonNode["fridge"]["alertState"] = alertStateValue; + var options = new JsonSerializerOptions { WriteIndented = true }; + File.WriteAllText(filePath, jsonNode.ToString(Newtonsoft.Json.Formatting.Indented)); + if (fridgeStateValue==0) + { + await port.FridegOpen(1); + } + else + { + await port.FridgeOff(1); + } + if (alertStateValue==0) + { + await port.FridgeAlarmOn(1); + } + else + { + await port.FridgeAlarmOff(1); + } + string[] newRange = temperatureRange.Split('-'); + if(newRange.Length>=2) + { + string[] range= setting.Value.temperatureRange.Split('-'); + bool bMix = float.TryParse(newRange[0], out float Min); + bool bMax = float.TryParse(newRange[1], out float Max); + if (bMix && bMax) + { + if (range == null || range[0] == null||(range != null && range[0] != null && range[0] != newRange[0])) + { + //设定冰箱温度最小值 + await port.FridgeMinSetting(Min, 1); + } + if (range == null || range[0] == null || (range != null && range[1] != null && range[1] != newRange[1])) + { + //设定冰箱温度最大值 + await port.FridgeMaxSetting(Max, 1); + } + } + } + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"保存成功", Duration = 4000 } + ); + logger.Info($"修改冰箱设置"); + } +} diff --git a/MasaBlazorApp3/Pages/Home.razor b/MasaBlazorApp3/Pages/Home.razor new file mode 100644 index 0000000..1023ef2 --- /dev/null +++ b/MasaBlazorApp3/Pages/Home.razor @@ -0,0 +1,414 @@ +@page "/" +@using MasaBlazorApp3.Util +@using log4net +@layout EmptyLayout + + + + + + + + + + + + @if (globalStateService.Operator != null) + { + //操作人:@globalStateService.Operator.NickName + //操作人:@globalStateService.Operator.NickName + + + + + + + + + + } + @if (globalStateService.Reviewer != null) + { + //复核人:@globalStateService.Reviewer.NickName + //复核人:@globalStateService.Reviewer.NickName + + + + + + + + + } + + +
+ +
交接班
+
+
+
+ + + +
+
+
+ + + + + 出库 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 10 < 10)) + { +
+ +
+ } + } +
+ + + 入库 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 20 > 0 && id - 20 < 10)) + { +
+ +
+ } + } +
+ + 药盒 + 管理 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 60 > 0 && id - 60 < 10)) + { +
+ +
+ } + } +
+
+
+ + + 归还 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 30 > 0 && id - 30 < 10)) + { +
+ +
+ } + } +
+ + + 库存管理 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 40 > 0 && id - 40 < 10)) + { +
+ +
+ } + } +
+ + 系统管理 + @if (globalStateService.Operator != null) + { + @if (!globalStateService.Operator.role.permissionIds.Any(id => id - 50 > 0 && id - 50 < 10)) + { +
+ +
+ } + } +
+ +
+
+
+
+ + +@code { + @inject Radzen.DialogService dialogService; + @inject NotificationService _message + @inject NavigationManager na; + @inject TooltipService tooltipService + private List userPremissions { get; set; } = new(); + @inject GlobalStateService globalStateService; + + Timer timer; + @inject PortUtil _portUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(Home)); + @inject Microsoft.Extensions.Options.IOptions setting; + bool currentPage = true; + + protected override void OnInitialized() + { + // timer = new Timer(state => + // { + // var now = DateTime.Now; + + + // InvokeAsync(StateHasChanged); + // }, null, 0, 1000); + if (setting.Value.autoOutLog > 0) + { + // 是否需要自动退出 + var promiseUtil = new PromiseUtil(); + promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + if (globalStateService.Operator == null || !currentPage) + { + logger.Info($"Home页自动退出循环停止{globalStateService.Operator == null},{!currentPage}"); + stop(); + } + else + { + try + { + //没有在操作抽屉 + if (!_portUtil.Operate) + { + // 无人操作鼠标键盘 + if ((DateTime.Now - _portUtil.dateTime).TotalSeconds > setting.Value.autoOutLog && (DateTime.Now-_portUtil.mouseClickTime).TotalSeconds > setting.Value.autoOutLog) + { + logger.Info($"设备{setting.Value.autoOutLog}内无人操作,用户【{globalStateService.Operator?.NickName}】自动退出登录,_portUtil.Operate:{_portUtil.Operate},totalSecond:{(DateTime.Now - _portUtil.dateTime).TotalSeconds},lastInputTime:{CheckComputerFreeState.GetLastInputTime()},autoOutLog:{setting.Value.autoOutLog}"); + globalStateService.Operator.NickName = string.Empty; + globalStateService.Operator = null; + if (globalStateService.Reviewer != null) + { + globalStateService.Reviewer.NickName = string.Empty; + globalStateService.Reviewer = null; + } + await InvokeAsync(StateHasChanged); + stop(); + } + else + { + logger.Info($"{setting.Value.autoOutLog}未自动退出{(DateTime.Now - _portUtil.dateTime).TotalSeconds}-{(DateTime.Now - _portUtil.mouseClickTime).TotalSeconds}"); + next(); + } + } + else + { + next(); + } + } + catch (Exception ex) + { + logger.Info($"检查是否自动退出循环异常:{ex.Message}"); + next(); + } + } + }); + } + base.OnInitialized(); + } + + public void Dispose() + { + timer?.Dispose(); + } + + async void init() + { + var b = await dialogService.OpenAsync( + $"调拨入库详情", + new Dictionary() { }, + new DialogOptions() { ShowTitle = false, Style = "min-height:auto;min-width:auto;width:auto", CloseDialogOnEsc = false, Resizable = true, Draggable = true, ShowClose = false } + ); + + } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender && !globalStateService.isInit) + { + this.init(); + } + } + + + async void jump2Page(int parentId) + { + bool a = true; + if ((setting.Value.loginMode == 2 && (globalStateService.Operator == null || globalStateService.Reviewer == null)) + || setting.Value.loginMode == 1 && globalStateService.Operator == null) + { + a = await dialogService.OpenAsync( + "", + null, + new DialogOptions() { Width = "55vw", Resizable = false, Draggable = false, ShowClose = false, ShowTitle = false }); + + } + // bool a = globalStateService.Operator != null; + // if (!a) + // { + // a = await dialogService.OpenAsync( + // "", + // null, + // new DialogOptions() { Width = "55vw", Resizable = false, Draggable = false, ShowClose = false, ShowTitle = false }); + // } + if (a) + { + List childrenIds = globalStateService.Operator.role.permissionIds.Where(id => id - (parentId * 10) > 0 && id - (parentId * 10) < 10).ToList(); + if (childrenIds.Count > 0) + { + currentPage = false; + childrenIds.Sort(); + int minId = childrenIds[0]; + string path = new Premission().getAdminPremission().Find(p => p.Id == parentId).Items.ToList().Find(p2 => p2.Id == minId).PremissionPath; + na.NavigateTo(path); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"没有权限不能访问", Duration = 3000 } + ); + await InvokeAsync(StateHasChanged); + } + } + } + void logout() + { + if (globalStateService.Operator != null) + { + globalStateService.Operator = null; + globalStateService.Reviewer = null; + } + else + { + Environment.Exit(0); + } + + } + //修改密码 + async void EditPassword(int i) + { + //修改复核人 + await dialogService.OpenAsync( + "", + new Dictionary() { { "userI", i } }, + new DialogOptions() { Width = "55vw", Resizable = false, Draggable = false, ShowClose = false, ShowTitle = false }); + + } + async void MenuClick(RadzenProfileMenuItem item) + { + + string strValue = item.Value.Substring(0, 1); + Pojo.User user = new Pojo.User(); + switch (strValue) + { + case "1": + int userId = 0; + if (item.Value == "11") + { + user = globalStateService.Operator; + } + else + { + user = globalStateService.Reviewer; + } + await dialogService.OpenAsync( + $"录入指纹-{user.Username}", + new Dictionary() { { "userId", user.Id } }, + new DialogOptions() { Width = "55vw", Resizable = true, Draggable = false, ShowClose = false } + ); + break; + case "2": + if (item.Value == "21") + { + user = globalStateService.Operator; + } + else + { + user = globalStateService.Reviewer; + } + await dialogService.OpenAsync( + $"签名-{user.NickName}", + new Dictionary() { { "user", user } }, + new DialogOptions() { Width = "55vw", Resizable = true, Draggable = false, ShowClose = true } + ); + + break; + case "3": + if (item.Value == "31") + { + user = globalStateService.Operator; + } + else + { + user = globalStateService.Reviewer; + } + int userI = Convert.ToInt32(item.Value.Substring(1, 1)); + await dialogService.OpenAsync( + $"修改密码-{user.Username}", + new Dictionary() { { "userI", userI } }, + new DialogOptions() { Width = "55vw", Resizable = false, Draggable = false, ShowClose = false, ShowTitle = true } + ); + break; + } + } + //交接班 + async void changeShifts() + { + //修改复核人 + await dialogService.OpenAsync( + "", + new Dictionary() { { "userI", 1 } }, + new DialogOptions() { Width = "55vw", Resizable = false, Draggable = false, ShowClose = false, ShowTitle = false }); + + } +} diff --git a/MasaBlazorApp3/Pages/Index.razor b/MasaBlazorApp3/Pages/Index.razor new file mode 100644 index 0000000..26b1d60 --- /dev/null +++ b/MasaBlazorApp3/Pages/Index.razor @@ -0,0 +1,237 @@ +@page "/login" +@layout EmptyLayout + +@using System.ComponentModel; +@using log4net; + + + + + + + + + + + + + @if(loginMode == 2) + { + ˣ@globalStateService.Operator?.NickName + ˣ@globalStateService.Reviewer?.NickName + } + + + + + + ¼ + + +
+ +
+ + +
+
+
+ +
+ + +
+
+
+ + +
+
+
+
+ +
+
+ + + +@code { + + @inject FingerprintUtil FingerprintUtil; + @inject PortUtil PortUtil; + @inject NavigationManager na; + @inject NotificationService _message + @inject GlobalStateService globalStateService; + @inject IUserDao userDao; + @inject Microsoft.Extensions.Options.IOptions setting; + + + + private readonly ILog logger = LogManager.GetLogger(typeof(Index)); + + private int loginMode = 1; + private bool opFirst = true; + + + + bool isShow; + + private Pojo.User loginModel = new(); + + protected override Task OnInitializedAsync() + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx += axCZKEM1_OnAttTransactionEx; + + loginMode = setting.Value.loginMode; + opFirst = setting.Value.opFirst; + + return base.OnInitializedAsync(); + } + + private void SetUser(Pojo.User user) + { + + // жǷΪ˫˵¼ģʽ + if (loginMode == 2) + { + // жǷDzȵ¼ + if (opFirst) + { + // жϲǷѾ¼Ѿ¼˵ʱΪڶ˵¼ + if (globalStateService.Operator != null) + { + // жǷDz˵֤ + if (globalStateService.Operator.Id != user.Id) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Reviewer = user; + PortUtil.mouseClickTime = DateTime.Now; + na.NavigateTo("/home"); + logger.Info($"˫˵¼ģʽˡ{globalStateService.Operator.NickName}ˡ{user.NickName}¼"); + } else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "ʾ", Detail = $"֤ظʹ˺", Duration = 3000 } + ); + } + } else + { + // ʱΪһ˵¼ + globalStateService.Operator = user; + InvokeAsync(StateHasChanged); + loginModel = new(); + } + } + // Ϊڶ˵¼ + else + { + // жϸǷѾ¼Ѿ¼˵ʱΪڶ˵¼ + if (globalStateService.Reviewer != null) + { + // жǷǸ˵֤ + if (globalStateService.Reviewer.Id != user.Id) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Operator = user; + PortUtil.mouseClickTime = DateTime.Now; + na.NavigateTo("/home"); + logger.Info($"˫˵¼ģʽˡ{user.NickName}ˡ{globalStateService.Reviewer.NickName}¼"); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "ʾ", Detail = $"֤ظʹ˺", Duration = 3000 } + ); + } + } + else + { + // ʱΪһ˵¼ + globalStateService.Reviewer = user; + InvokeAsync(StateHasChanged); + loginModel = new(); + } + + } + + } else + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Operator = user; + PortUtil.mouseClickTime = DateTime.Now; + na.NavigateTo("/home"); + logger.Info($"˵¼ģʽû{user.NickName}¼"); + } + } + + + + private void Submit(Pojo.User user) + { + Pojo.User u = userDao.GetByUsername(loginModel.Username); + if (u != null) + { + if (Util.MD5.GetMD5Hash(loginModel.Password).ToLower().Equals(u.Password)) + { + SetUser(u); + } else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "ʾ", Detail = $"", Duration = 4000 } + ); + logger.Info($"û{u.NickName}"); + + } + + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "ʾ", Detail = $"޴û", Duration = 4000 } + ); + logger.Info($"ûû{loginModel.Username}"); + } + } + + private void axCZKEM1_OnAttTransactionEx(string sEnrollNumber, int iIsInValid, int iAttState, int iVerifyMethod, int iYear, int iMonth, int iDay, int iHour, int iMinute, int iSecond, int iWorkCode) + { + + Pojo.User u = userDao.GetById(Convert.ToInt32(sEnrollNumber)); + if(u != null) + { + SetUser(u); + } else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "ʾ", Detail = $"ϵͳûIDΪ{sEnrollNumber}û", Duration = 4000 } + ); + logger.Info($"ָƻ֤ͨidΪ{sEnrollNumber}ǻݿ޴û"); + } + + } + + private void Exit() + { + + Environment.Exit(0); + } + + +} diff --git a/MasaBlazorApp3/Pages/InitPage.razor b/MasaBlazorApp3/Pages/InitPage.razor new file mode 100644 index 0000000..47a83f8 --- /dev/null +++ b/MasaBlazorApp3/Pages/InitPage.razor @@ -0,0 +1,160 @@ +@page "/init" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + 加载程序必要连接中,请稍等。。。 + @msg + @errMsg + + +@code { + @inject Radzen.DialogService dialogService; + @inject IOptions setting; + @inject NotificationService _message; + @inject PortUtil PortUtil; + @inject FingerprintUtil FingerprintUtil; + @inject GlobalStateService globalStateService; + @inject IOptions portSetting; + + + string msg; + string errMsg; + + private readonly ILog logger = LogManager.GetLogger(typeof(InitPage)); + + + protected override async Task OnInitializedAsync() + { + + base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await Task.Delay(15); + msg = "开始连接指纹模块"; + InvokeAsync(StateHasChanged); + try + { + bool flag = await FingerprintUtil.ConnectionMain(); + if (flag) + { + msg = "指纹模块连接成功"; + } + else + { + msg = "指纹模块连接失败"; + } + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "指纹模块连接失败"; + errMsg += "【指纹模块连接失败】"; + logger.Info($"指纹模块连接失败【{e.Message}】"); + InvokeAsync(StateHasChanged); + } + await Task.Delay(500); + msg = "开始连接抽屉串口"; + InvokeAsync(StateHasChanged); + try + { + PortUtil.drawerSerial.Open(); + logger.Info($"抽屉串口打开结果【{PortUtil.drawerSerial.IsOpen}】"); + msg = "抽屉串口连接成功"; + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "抽屉串口连接失败"; + errMsg += "【抽屉串口连接失败】"; + logger.Info($"抽屉串口连接失败【{e.Message}】"); + InvokeAsync(StateHasChanged); + } + await Task.Delay(500); + msg = "开始连接CanBus模块"; + InvokeAsync(StateHasChanged); + try + { + PortUtil.canBusSerial.Open(); + logger.Info($"CanBus模块打开结果【{PortUtil.canBusSerial.IsOpen}】"); + msg = "CanBus模块连接成功"; + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "CanBus模块连接失败"; + errMsg += "【CanBus模块连接失败】"; + logger.Info($"模块连接失败【{e.Message}】"); + InvokeAsync(StateHasChanged); + } + await Task.Delay(500); + msg = "开始连接第二个CanBus模块"; + InvokeAsync(StateHasChanged); + try + { + PortUtil.canBusSerialTwo.Open(); + logger.Info($"第二个CanBus模块打开结果【{PortUtil.canBusSerialTwo.IsOpen}】"); + msg = "CanBus模块连接成功"; + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "第二个CanBus模块连接失败"; + logger.Info($"模块连接失败【{e.Message}】"); + errMsg += "【第二个CanBus模块连接失败】"; + InvokeAsync(StateHasChanged); + } + await Task.Delay(500); + msg = "开始连接条码扫描模块"; + InvokeAsync(StateHasChanged); + try + { + PortUtil.scanCodeSerial.Open(); + logger.Info($"条码扫描模块打开结果【{PortUtil.scanCodeSerial.IsOpen}】"); + msg = "条码扫描模块连接成功"; + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "条码扫描模块连接失败"; + errMsg += "【条码扫描模块连接失败】"; + logger.Info($"条码扫描模块打开结果【{e.Message}】"); + InvokeAsync(StateHasChanged); + } + if (portSetting.Value.fridgePortExist) + { + try + { + PortUtil.fridgeSerial.Open(); + logger.Info($"冰箱串口打开结果【{PortUtil.fridgeSerial.IsOpen}】"); + msg = "冰箱串口连接成功"; + InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + msg = "冰箱串口打开失败"; + errMsg += "【冰箱串口打开失败】"; + logger.Info($"冰箱串口打开失败【{e.Message}】"); + InvokeAsync(StateHasChanged); + } + } + globalStateService.isInit = true; + dialogService.Close(); + } + } + + + + +} diff --git a/MasaBlazorApp3/Pages/InvoiceAdd.razor b/MasaBlazorApp3/Pages/InvoiceAdd.razor new file mode 100644 index 0000000..846794a --- /dev/null +++ b/MasaBlazorApp3/Pages/InvoiceAdd.razor @@ -0,0 +1,122 @@ +@page "/add/invoice" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + +
+
+
+ +@code { + @inject IInOutInvoiceDao inOutInvoiceDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + string InvoiceNo; + DateTime InvoiceDate = DateTime.Now; + + void OnCurrentDateChanged(DateTime args) + { + InvoiceDate = new DateTime(args.Year, args.Month, args.Day); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await inOutInvoiceDao.GetAllInvoiceByType(InvoiceNo, InvoiceDate, args.Top, args.Skip, 1); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + InvoiceNo = ""; + InvoiceDate = DateTime.MinValue; + await grid.Reload(); + } + + async Task InvoiceSelected(InOutInvoice oi) + { + + var b = await dialogService.OpenAsync( + $"", + new Dictionary() { { "invoice", oi } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/InvoiceAddDialog.razor b/MasaBlazorApp3/Pages/InvoiceAddDialog.razor new file mode 100644 index 0000000..42bb8d0 --- /dev/null +++ b/MasaBlazorApp3/Pages/InvoiceAddDialog.razor @@ -0,0 +1,472 @@ +@page "/invoice/add/{invoice}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + 单据号: + @(invoice?.InvoiceNo) + 时间: + @(invoice?.InvoiceDate) + + + + + + + + + + + + + + + + + + + + + + + + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status < 2) + { + + } + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IInOutInvoiceDao inOutInvoiceDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + + RadzenDataGrid grid; + + + private readonly ILog logger = LogManager.GetLogger(typeof(InvoiceAddDialog)); + + [Parameter] public InOutInvoice invoice { get; set; } + private bool CanTakeDrug = true; + int status = 0; + + public List data { get; set; } + + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + // 当前操作的库位号列表 + public List ColNos { get; set; } = new List(); + int currentCol = 0; + //开抽屉前操作标识 + private List _flagList = new List(); + async Task StartAdd() + { + if (data.Any(it => it.Quantity != it.ChannelStocks.Sum(cs => cs.AddQuantity))) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请填写正确的入库数量!", Duration = 4000 } + ); + + } + else + { + await OpenDrawer(); + } + } + + async Task CancelOpera() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + status = 0; + dialogService.Close(false); + } + + + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + List channels = new(); + for (int i = 0; i < data.Count; i++) + { + channels = channels.Concat(data[i].ChannelStocks.Where(cs => cs.AddQuantity > 0)).ToList(); + } + + List drawerNos = channels.GroupBy(it => it.DrawerNo).Select(it => it.Key).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + int index = 0; + var BeforeQuantity = new int[9]; + var AfterQuantity = new int[9]; + await new PromiseUtil().taskAsyncLoop(500, 0, async (options, next, stop) => + { + var drawerNo = drawerNos[index]; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (options._data == 0) + { + BeforeQuantity = new int[9]; + AfterQuantity = new int[9]; + for (int j = 0; j < data[index].ChannelStocks.Count; j++) + { + // _flagList.Add(flag); + //单支-查数 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(data[index].ChannelStocks[j].DrawerNo); + data[index].BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", data[index].BeforeQuantity)}】"); + + await PortUtil.NoLightOnByCol(drawerNo, data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)).Cast().ToArray()); + } + //称重-查数 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[index].ChannelStocks[j].DrawerNo;// drawerNo; + PortUtil.ColNoLst.Add(data[index].ChannelStocks[j].ColNo); + + data[index].BeforeQuantity[data[index].ChannelStocks[j].ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[index].ChannelStocks[j].ColNo); + logger.Info($"称重抽屉【{data[index].ChannelStocks[j].DrawerNo}】,开抽屉前检测数量【{string.Join(",", data[index].BeforeQuantity)}】"); + await Task.Delay(200); + } + //药盒-开药盒 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("3")) + { + PortUtil.DrawerNo = data[index].ChannelStocks[j].DrawerNo; + await PortUtil.OpenBoxByColNo(data[index].ChannelStocks[j].ColNo); + await Task.Delay(200); + } + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,加药"); + options._data = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (options._data == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + options._data = 0; + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + if (index == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"加药完成,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + bool cancelFlag = false; + for (int i = 0; i < data.Count; i++) + { + for (int j = 0; j < data[i].ChannelStocks.Count; j++) + { + string flag = "关" + data[i].ChannelStocks[j].DrawerNo.ToString() + data[i].ChannelStocks[j].ColNo.ToString(); + + if (!_flagList.Contains(flag)) + { + _flagList.Add(flag); + //关闭抽屉后获取称重数量 + PortUtil.DrawerNo = data[i].ChannelStocks[j].DrawerNo;// drawerNo; + // 判断是否为称重抽屉 + //单支-查数 + if (data[i].ChannelStocks[j].BoardType.ToString().Contains("6")) + { + PortUtil.ColNoLst = this.ColNos; + + AfterQuantity[data[i].ChannelStocks[j].ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStocks[j].ColNo); + logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStocks[j].ColNo - 1] - AfterQuantity[data[i].ChannelStocks[j].ColNo - 1]; + if (data[i].ChannelStocks[j].Quantity != WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]) + { + //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]}】"; + + } + } + //单支-查数 + if (data[i].ChannelStocks[j].BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStocks[j].ColNo - 1] - AfterQuantity[data[i].ChannelStocks[j].ColNo - 1]; + if (data[i].ChannelStocks[j].Quantity != WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].ChannelStocks[j].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]}】"; + } + } + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + //弹出确认提示框 + var confirm = await dialogService.OpenAsync + ( + $"保存确认", + new Dictionary + () { { "confirmInfo", alertMessage } }, + new DialogOptions() + { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + cancelFlag = true; + // 关闭弹窗 + dialogService.Close(false); + break; + } + else + { + logger.Info(alertMessage); + } + alertMessage = string.Empty; + } + } + } + if (cancelFlag) + { + break; + } + } + stop(); + } + else + { + index += 1; + next(); + } + } + else + { + // if (setting.Value.single.Contains(drawerNo)) + // { + // byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + // AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + // logger.Info($"单支抽屉【{drawerNo}】,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + // data.ForEach(cl => + // { + // cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + // { + // logger.Info($"单支抽屉【{drawerNo}】,应加药品数量【{cs.AddQuantity}】,现实取数量【{AfterQuantity[cs.ColNo - 1] - BeforeQuantity[cs.ColNo - 1]}】"); + // }); + + // }); + // } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"调拨加药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + this.status = 0; + _flagList.Clear(); + this.ColNos.Clear(); + } + + async Task AddFinish() + { + + // 保存账册、操作记录 + var b = await inOutInvoiceDao.InvoiceAddFinish(data); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉加药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + + protected override async Task OnInitializedAsync() + { + data = await inOutInvoiceDao.getAddInfoByInvoiceNo(invoice.InvoiceNo); + // 如果有库位列表未空则说明不能取药,需要增加库位 + if (data.Any(it => it.ChannelStocks.Count == 0)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await Task.Delay(15); + await grid.ExpandRows(grid.PagedView.Where(it => it.ChannelStocks.Count > 0)); + } + } + + + void RowRender(RowRenderEventArgs + args) + { + args.Expandable = args.Data.ChannelStocks != null && args.Data.ChannelStocks.Count > 0; + } + + + void OnCellClick(DataGridCellMouseEventArgs + args, RadzenDataGrid + Grid) + { + Grid.EditRow(args.Data); + } +} diff --git a/MasaBlazorApp3/Pages/InvoiceOut.razor b/MasaBlazorApp3/Pages/InvoiceOut.razor new file mode 100644 index 0000000..c828325 --- /dev/null +++ b/MasaBlazorApp3/Pages/InvoiceOut.razor @@ -0,0 +1,114 @@ +@page "/take/invoice" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + +
+
+
+ +@code { + @inject IInOutInvoiceDao inOutInvoiceDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + string InvoiceNo; + DateTime InvoiceDate = DateTime.MinValue; + + void OnCurrentDateChanged(DateTime args) + { + InvoiceDate = new DateTime(args.Year, args.Month, args.Day); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await inOutInvoiceDao.GetAllInvoiceByType(InvoiceNo, InvoiceDate, args.Top, args.Skip, 2); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + InvoiceNo = ""; + InvoiceDate = DateTime.MinValue; + await grid.Reload(); + } + + async Task InvoiceSelected(InOutInvoice oi) + { + + var b = await dialogService.OpenAsync( + $"", + new Dictionary() { { "invoice", oi } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/InvoiceOutDialog.razor b/MasaBlazorApp3/Pages/InvoiceOutDialog.razor new file mode 100644 index 0000000..30e1397 --- /dev/null +++ b/MasaBlazorApp3/Pages/InvoiceOutDialog.razor @@ -0,0 +1,445 @@ +@page "/invoice/out/{invoice}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + 单据号: + @(invoice?.InvoiceNo) + 时间: + @(invoice?.InvoiceDate) + + + + + + + + + + + + + + + + + + + + + + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status <= 2) + { + + } + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IInOutInvoiceDao inOutInvoiceDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + + RadzenDataGrid grid; + + private readonly ILog logger = LogManager.GetLogger(typeof(InvoiceOutDialog)); + + [Parameter] public InOutInvoice invoice { get; set; } + private bool CanTakeDrug = true; + + int status = 0; + + public List data { get; set; } + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + // 当前操作的库位号列表 + public List ColNos { get; set; } = new List(); + int currentCol = 0; + //开抽屉前操作标识 + private List _flagList = new List(); + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + + async Task StartTake() + { + if (data.Any(it => it.Quantity != it.ChannelStocks.Sum(cs => cs.TakeQuantity))) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请填写正确的出库数量!", Duration = 4000 } + ); + + } + else + { + await OpenDrawer(); + } + } + async Task CancelOpera() + { + RestData(); + dialogService.Close(false); + } + async Task OpenDrawer() + { + this.status = 1; + // 解析需要打开的抽屉列表 + List channels = new(); + for (int i = 0; i < data.Count; i++) + { + channels = channels.Concat(data[i].ChannelStocks.Where(cs => cs.TakeQuantity > 0)).ToList(); + } + + List drawerNos = channels.GroupBy(it => it.DrawerNo).Select(it => it.Key).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + int index = 0; + await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + { + var drawerNo = drawerNos[index]; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (options._data == 0) + { + BeforeQuantity = new int[9]; + AfterQuantity = new int[9]; + for (int j = 0; j < data[index].ChannelStocks.Count; j++) + { + //单支-查数 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(data[index].ChannelStocks[j].DrawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + + await PortUtil.NoLightOnByCol(drawerNo, data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)).Cast().ToArray()); + } + //称重-查数 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[index].ChannelStocks[j].DrawerNo;// drawerNo; + PortUtil.ColNoLst.Add(data[index].ChannelStocks[j].ColNo); + + data[j].BeforeQuantity[data[index].ChannelStocks[j].ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[index].ChannelStocks[j].ColNo); + logger.Info($"称重抽屉【{data[index].ChannelStocks[j].DrawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + await Task.Delay(200); + } + //药盒-开药盒 + if (data[index].ChannelStocks[j].BoardType.ToString().Contains("3")) + { + PortUtil.DrawerNo = data[index].ChannelStocks[j].DrawerNo; + await PortUtil.OpenBoxByColNo(data[index].ChannelStocks[j].ColNo); + await Task.Delay(200); + } + } + // // 判断是否为单支抽屉 + // if (setting.Value.single != null && setting.Value.single.Contains(drawerNo)) + // { + // byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + // BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + // logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + + // await PortUtil.HasLightOnByCol(drawerNo, data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)).Cast().ToArray()); + // } + // // 称重抽屉关上则查数 + // if (setting.Value.weigh != null && setting.Value.weigh.Contains(drawerNo)) + // { + // for (int i = 0; i < data.Count; i++) + // { + // for (int j = 0; j < data[i].ChannelStocks.Count; j++) + // { + // if (data[i].ChannelStocks[j].BoardType.ToString().Contains("6")) + // { + // PortUtil.DrawerNo = drawerNo; + // PortUtil.ColNoLst.Add(data[i].ChannelStocks[j].ColNo); + + // BeforeQuantity[data[i].ChannelStocks[j].ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStocks[j].ColNo); + // logger.Info($"称重抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + // await Task.Delay(200); + // } + // } + // } + // } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + options._data = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (options._data == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + options._data = 0; + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + + if (index == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"取药完成,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + bool cancelFlag = false; + for (int i = 0; i < data.Count; i++) + { + for (int j = 0; j < data[i].ChannelStocks.Count; j++) + { + string flag = "关" + data[i].ChannelStocks[j].DrawerNo.ToString() + data[i].ChannelStocks[j].ColNo.ToString(); + + if (!_flagList.Contains(flag)) + { + _flagList.Add(flag); + // 判断是否为称重抽屉 + if (data[i].ChannelStocks[j].BoardType.ToString().Contains("6")) + { + //关闭抽屉后获取称重数量 + PortUtil.DrawerNo = data[i].ChannelStocks[j].DrawerNo;// drawerNo; + PortUtil.ColNoLst = this.ColNos; + + AfterQuantity[data[i].ChannelStocks[j].ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStocks[j].ColNo); + logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStocks[j].ColNo - 1] - AfterQuantity[data[i].ChannelStocks[j].ColNo - 1]; + if (data[i].ChannelStocks[j].Quantity != WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]) + { + //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]}】"; + + } + } + if (data[i].ChannelStocks[j].BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(data[i].ChannelStocks[j].DrawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1] = BeforeQuantity[data[i].ChannelStocks[j].ColNo - 1] - AfterQuantity[data[i].ChannelStocks[j].ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].ChannelStocks[j].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStocks[j].ColNo - 1]}】"; + } + } + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + //弹出确认提示框 + var confirm = await dialogService.OpenAsync( + $"保存确认", + new Dictionary() { { "confirmInfo", alertMessage } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + logger.Info(alertMessage); + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + cancelFlag = true; + // 关闭弹窗 + dialogService.Close(false); + break; + } + else + { + logger.Info(alertMessage); + } + alertMessage = string.Empty; + } + } + } + if (cancelFlag) + { + break; + } + } + stop(); + } + else + { + index += 1; + next(); + } + } + else + { + if (setting.Value.single != null && setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + data.ForEach(cl => + { + cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + { + logger.Info($"单支抽屉【{drawerNo}】,应取药品数量【{cs.TakeQuantity}】,现实取数量【{BeforeQuantity[cs.ColNo - 1] - AfterQuantity[cs.ColNo - 1]}】"); + }); + + }); + } + //是药盒抽屉开药盒 + if (setting.Value.box != null && setting.Value.box.Contains(drawerNo) && currentCol != null) + { + PortUtil.DrawerNo = drawerNo; + await PortUtil.OpenBoxByColNo(currentCol); + ColNos.Add(currentCol); + currentCol = 0; + await Task.Delay(200); + } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"调拨取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + this.BeforeQuantity = new int[9]; + this.AfterQuantity = new int[9]; + currentCol = 0; + ColNos.Clear(); + _flagList.Clear(); + } + + async Task TakeFinish() + { + + // 保存账册、操作记录 + var b = await inOutInvoiceDao.InvoiceOutFinish(data); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉加药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + + protected override async Task OnInitializedAsync() + { + data = await inOutInvoiceDao.getTakeInfoByInvoiceNo(invoice.InvoiceNo); + // 如果有【stockQuantity】字段说明有药品库存不足 + if (data.Any(it => it.ChannelStocks == null || it.ChannelStocks.Count == 0)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await Task.Delay(15); + await grid.ExpandRows(grid.PagedView.Where(it => it.ChannelStocks.Count > 0)); + } + } + + + void RowRender(RowRenderEventArgs args) + { + args.Expandable = args.Data.ChannelStocks != null && args.Data.ChannelStocks.Count > 0; + } + + void OnCellClick(DataGridCellMouseEventArgs args, RadzenDataGrid Grid) + { + currentCol = args.Data.ColNo; + Grid.EditRow(args.Data); + } + + +} diff --git a/MasaBlazorApp3/Pages/LoginDialog.razor b/MasaBlazorApp3/Pages/LoginDialog.razor new file mode 100644 index 0000000..b35a0fc --- /dev/null +++ b/MasaBlazorApp3/Pages/LoginDialog.razor @@ -0,0 +1,234 @@ +@page "/loginDialog" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + + + @if (loginMode == 2) + { + 操作人:@globalStateService.Operator?.NickName + 复核人:@globalStateService.Reviewer?.NickName + } + + + + + + 登录 + + +
+ +
+ + + +
+
+
+ +
+ + +
+
+
+ + +
+
+
+
+ +
+ +@code { + @inject Radzen.DialogService dialogService; + + @inject FingerprintUtil FingerprintUtil; + @inject PortUtil PortUtil; + @inject NavigationManager na; + @inject NotificationService _message + @inject GlobalStateService globalStateService; + @inject IUserDao userDao; + @inject Microsoft.Extensions.Options.IOptions setting; + + + + private readonly ILog logger = LogManager.GetLogger(typeof(LoginDialog)); + + private int loginMode = 1; + private bool opFirst = true; + + + + bool isShow; + + private Pojo.User loginModel = new(); + + protected override Task OnInitializedAsync() + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx += axCZKEM1_OnAttTransactionEx; + + loginMode = setting.Value.loginMode; + opFirst = setting.Value.opFirst; + + return base.OnInitializedAsync(); + } + + private void SetUser(Pojo.User user) + { + + // 判断是否为双人登录模式 + if (loginMode == 2) + { + // 判断是否是操作人优先登录 + if (opFirst) + { + // 判断操作人是否已经登录,已经登录说明此时为第二人登录 + if (globalStateService.Operator != null) + { + // 判断是否还是操作人的验证 + if (globalStateService.Operator.Id != user.Id) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Reviewer = user; + logger.Info($"双人登录模式:操作人【{globalStateService.Operator.NickName}】复核人【{user.NickName}】登录"); + PortUtil.mouseClickTime = DateTime.Now; + dialogService.Close(true); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + } + } + else + { + // 此时为第一人登录 + globalStateService.Operator = user; + InvokeAsync(StateHasChanged); + } + } + // 操作人为第二人登录 + else + { + // 判断复核人是否已经登录,已经登录说明此时为第二人登录 + if (globalStateService.Reviewer != null) + { + // 判断是否还是复核人的验证 + if (globalStateService.Reviewer.Id != user.Id) + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Operator = user; + logger.Info($"双人登录模式:操作人【{user.NickName}】复核人【{globalStateService.Reviewer.NickName}】登录"); + PortUtil.mouseClickTime = DateTime.Now; + dialogService.Close(true); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"验证重复,请使用其他账号", Duration = 3000 } + ); + } + } + else + { + // 此时为第一人登录 + globalStateService.Reviewer = user; + InvokeAsync(StateHasChanged); + } + + } + + } + else + { + FingerprintUtil.axCZKEM1.OnAttTransactionEx -= axCZKEM1_OnAttTransactionEx; + globalStateService.Operator = user; + PortUtil.mouseClickTime = DateTime.Now; + logger.Info($"单人登录模式:用户【{user.NickName}】登录"); + dialogService.Close(true); + } + } + + + + private void Submit(Pojo.User user) + { + Pojo.User u = userDao.GetByUsername(loginModel.Username); + if (u != null) + { + if (Util.MD5.GetMD5Hash(loginModel.Password).ToLower().Equals(u.Password)) + { + SetUser(u); + loginModel.Username=""; + loginModel.Password = ""; + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"密码错误", Duration = 4000 } + ); + logger.Info($"用户【{u.NickName}】密码输入错误"); + + } + + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"无此用户", Duration = 4000 } + ); + logger.Info($"没有用户:【{loginModel.Username}】"); + } + } + + private void axCZKEM1_OnAttTransactionEx(string sEnrollNumber, int iIsInValid, int iAttState, int iVerifyMethod, int iYear, int iMonth, int iDay, int iHour, int iMinute, int iSecond, int iWorkCode) + { + + Pojo.User u = userDao.GetById(Convert.ToInt32(sEnrollNumber)); + if (u != null) + { + SetUser(u); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"系统中没有ID为【{sEnrollNumber}】的用户", Duration = 4000 } + ); + logger.Info($"指纹机验证通过id为【{sEnrollNumber}】,但是华康数据库中无此用户"); + } + + } + + private void Exit() + { + if (globalStateService.Operator != null) + { + globalStateService.Operator = null; + globalStateService.Reviewer = null; + } + dialogService.Close(false); + } + + + + +} diff --git a/MasaBlazorApp3/Pages/LoginSetting.razor b/MasaBlazorApp3/Pages/LoginSetting.razor new file mode 100644 index 0000000..0605af1 --- /dev/null +++ b/MasaBlazorApp3/Pages/LoginSetting.razor @@ -0,0 +1,74 @@ +@page "/manage/setting/login" +@page "/manage/setting" +@using Newtonsoft.Json.Linq +@using log4net +@layout SettingLayout +
+
+ + + 保存设置 + + +
+
+ + + + 登录模式 + loginValue = args)> + + + + + + + @* + 优先登录 + preValue = args)> + + + + + + *@ + + +
+
+ +@inject Microsoft.Extensions.Options.IOptions setting; +@inject Microsoft.Extensions.Options.IOptions setting; +@inject NotificationService _message + + +@code { + + private readonly ILog logger = LogManager.GetLogger(typeof(LoginDialog)); + int loginValue = 1; + // int preValue = 1; + protected override void OnInitialized() + { + loginValue = setting.Value.loginMode; + base.OnInitialized(); + } + //保存 + async Task SaveMethod() + { + // 获取当前工作目录 + string currentDirectory = Directory.GetCurrentDirectory(); + // setting.Value.fridgeState = fridgeStateValue; + // setting.Value.alertState = alertStateValue; + // setting.Value.temperatureRange = temperatureRange; + string filePath = Path.Combine(currentDirectory, "appsettings.json"); + string jsonString = File.ReadAllText(filePath); + var jsonNode = JObject.Parse(jsonString); + jsonNode["setting"]["loginMode"] = loginValue; + var options = new JsonSerializerOptions { WriteIndented = true }; + File.WriteAllText(filePath, jsonNode.ToString(Newtonsoft.Json.Formatting.Indented)); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"保存成功", Duration = 4000 } + ); + logger.Info($"修改用户登录设置"); + } +} diff --git a/MasaBlazorApp3/Pages/MachineRecordList.razor b/MasaBlazorApp3/Pages/MachineRecordList.razor new file mode 100644 index 0000000..dec05d4 --- /dev/null +++ b/MasaBlazorApp3/Pages/MachineRecordList.razor @@ -0,0 +1,134 @@ +@page "/take/record/{type}" +@page "/add/record/{type}" +@page "/return/record1/{type}" +@page "/return/record2/{type}" +@page "/stock/record/{type}" +@using MasaBlazorApp3.Report + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + @* + + + *@ + + +
+
+
+ + + + + + + + + + + + + + + +
+
+
+ +@code { + @inject IMachineRecordDao machineRecordDao; + @inject DialogService dialogService; + + @inject NavigationManager navigate; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime start; + DateTime end; + + + [Parameter] public string type { get; set; } + + protected override void OnParametersSet() + { + if(grid != null) + { + reloadGrid(); + } + } + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await machineRecordDao.GetMachineRecordAsync(start, end, 0, "", int.Parse(type), args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + start = DateTime.MinValue; + end = DateTime.MinValue; + await grid.Reload(); + } + + //浼 + void StockExport() + { + + } + //ר˲ᵼ + void AccountBookExport() + { + // string drugId = drugName != null ? drugName.Split('/').Last().Trim():""; + // GridReportUtil gridReportUtil = new GridReportUtil(); + GridReportUtil.PrintReport("stock_template.grf", null); + } + + + +} diff --git a/MasaBlazorApp3/Pages/OrderDetailDialog.razor b/MasaBlazorApp3/Pages/OrderDetailDialog.razor new file mode 100644 index 0000000..6216ce6 --- /dev/null +++ b/MasaBlazorApp3/Pages/OrderDetailDialog.razor @@ -0,0 +1,344 @@ +@page "/orderDetail/{order}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + 处方号: + @(order?.OrderNo) + 患者姓名: + @(order?.PatientName) + 性别: + @(order?.Sex) + 年龄: + @(order?.Age) + + + @if (CanTakeDrug) + { + + + + + + + + + + + + + } + else + { + + + + + + + + + } + + + + + + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status <= 2) + { + + } + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IOrderInfoDao orderInfoDao; + @inject IChannelListDao channelListDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + int status; + + [Parameter] public OrderInfo order { get; set; } + private bool CanTakeDrug = true; + + public List data { get; set; } + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + + protected override async Task OnInitializedAsync() + { + data = await orderInfoDao.getTakeInfoByOrderNo(order.OrderNo); + // 如果有【stockQuantity】字段说明有药品库存不足 + if (data.Any(it => it.ChannelStock == null)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + List drawerNos = this.data.GroupBy(it => it.ChannelStock.DrawerNo).Select(it => it.First()).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + + await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + { + var orderTakeVo = drawerNos[options._data]; + var drawerNo = orderTakeVo.ChannelStock.DrawerNo; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (orderTakeVo.Status == 0) + { + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + + await PortUtil.HasLightOnByCol(drawerNo, data.Where(ot => ot.ChannelStock.DrawerNo == drawerNo).Select(ot => ot.ChannelStock.ColNo).ToArray()); + } + for (int i = 0; i < data.Count; i++) + { + if (!DrawerNoColNoList.Contains(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo)) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + await Task.Delay(200); + } + + //是药盒抽屉开药盒 + if (data[i].ChannelStock.BoardType.ToString().Contains("3")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + await PortUtil.OpenBoxByColNo(data[i].ChannelStock.ColNo); + await Task.Delay(200); + } + DrawerNoColNoList.Add(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo); + } + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + orderTakeVo.Status = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (orderTakeVo.Status == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + + data.ForEach(cl => + { + if (cl.ChannelStock.DrawerNo == drawerNo) + { + cl.GetQuantity = cl.Quantity; + + } + }); + orderTakeVo.Status = 2; + PortUtil.PowerOff(); + if (options._data == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"取药完成,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + //检查是否称重抽屉,核对实际取出数量是否与应取数量一致,不一致则弹出提示 + for (int i = 0; i < data.Count; i++) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo;// drawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + + } + await Task.Delay(200); + } + + if (data[i].ChannelStock.BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = orderTakeVo.BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}应取数量【{orderTakeVo.Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + } + } + } + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + //弹出确认提示框 + var confirm = await dialogService.OpenAsync( + $"保存确认", + new Dictionary() { { "confirmInfo", alertMessage } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + logger.Info(alertMessage); + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + // 关闭弹窗 + dialogService.Close(false); + } + } + stop(); + } + else + { + options._data += 1; + next(); + } + } + else + { + next(); // continue iteration + } + } + + + } + + } + catch (Exception e) + { + RestData(); + logger.Info($"处方取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + data.ForEach(it => + { + it.Status = 0; + it.BeforeQuantity = new int[9]; + it.AfterQuantity = new int[9]; + }); + this.WeightFinnalQuantity = new int[9]; + DrawerNoColNoList.Clear(); + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task TakeFinish() + { + + // 保存账册、操作记录 + var b = await orderInfoDao.OrderTakeFinish(data); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"处方取药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // for (int i = 0; i < data.Count; i++) + // { + // // 判断是否为标签抽屉 + // if (setting.Value.label.Contains(data[i].ChannelStock.DrawerNo)) + // { + // //写标签数量 + // await PortUtil.WriteQuantityMethod(data[i].Quantity + data[i].GetQuantity, data[i].ChannelStock.DrawerNo, data[i].ChannelStock.ColNo); + // } + + // } + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + +} diff --git a/MasaBlazorApp3/Pages/OrderDetailReturnDialog.razor b/MasaBlazorApp3/Pages/OrderDetailReturnDialog.razor new file mode 100644 index 0000000..405cf5d --- /dev/null +++ b/MasaBlazorApp3/Pages/OrderDetailReturnDialog.razor @@ -0,0 +1,289 @@ +@page "/orderDetailReturn/{order}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + 处方号: + @(order?.OrderNo) + 患者姓名: + @(order?.PatientName) + 性别: + @(order?.Sex) + 年龄: + @(order?.Age) + + + + + + + + + + + + + + + + + + + + @if(status < 2) + { + + } + @if(status == 2) + { + + } + @if(status < 2) + { + + } + + + +@code { + @inject Radzen.DialogService dialogService; + @inject IOrderInfoDao orderInfoDao; + @inject IChannelListDao channelListDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + RadzenDataGrid> grid; + + int status; + + [Parameter] public OrderInfo order { get; set; } + private bool CanReturnDrug = true; + + public List> data { get; set; } + + + + protected override async Task OnInitializedAsync() + { + data = await orderInfoDao.getReturnInfoByOrderNo(order.OrderNo); + // 如果有【stockQuantity】字段说明有药品库存不足 + if (data.Any(it => it.ChannelStocks == null)) + { + CanReturnDrug = false; + } + base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await Task.Delay(15); + await grid.ExpandRows(grid.PagedView.Where(it => it.ChannelStocks.Count > 0)); + } + } + + async Task OpenDrawer() + { + this.status = 1; + // 解析需要打开的抽屉列表 + List channels = new(); + for (int i = 0; i < data.Count; i++) + { + channels = channels.Concat(data[i].ChannelStocks.Where(cs => cs.AddQuantity > 0)).ToList(); + } + + List drawerNos = channels.GroupBy(it => it.DrawerNo).Select(it => it.Key).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + int index = 0; + var BeforeQuantity = new int[9]; + var AfterQuantity = new int[9]; + await new PromiseUtil().taskAsyncLoop(500, 0, async (options, next, stop) => + { + var drawerNo = drawerNos[index]; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (options._data == 0) + { + BeforeQuantity = new int[9]; + AfterQuantity = new int[9]; + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + + await PortUtil.NoLightOnByCol(drawerNo, data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)).Cast().ToArray()); + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,放置退回药品"); + options._data = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"处方退药抽屉【{drawerNo}】打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (options._data == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + options._data = 0; + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + if (index == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"退药完成,请,点击完成按钮进行确认"); + this.status = 2; + stop(); + } + else + { + index += 1; + next(); + } + } + else + { + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + data.ForEach(cl => + { + cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + { + logger.Info($"单支抽屉【{drawerNo}】,应退药品数量【{cs.AddQuantity}】,现实退数量【{AfterQuantity[cs.ColNo - 1] - BeforeQuantity[cs.ColNo - 1]}】"); + }); + + }); + } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"处方退药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + } + void Cancel() + { + RestData(); + // 关闭弹窗 + dialogService.Close(false); + } + async Task TakeFinish() + { + + // 保存账册、操作记录 + var b = await orderInfoDao.OrderReturnFinish(data, order.OrderNo); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"处方取药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + void RowRender(RowRenderEventArgs> args) + { + args.Expandable = args.Data.ChannelStocks != null && args.Data.ChannelStocks.Count > 0; + } + + + void OnCellClick(DataGridCellMouseEventArgs args, RadzenDataGrid Grid) + { + Grid.EditRow(args.Data); + } + + + +} diff --git a/MasaBlazorApp3/Pages/OrderReturn.razor b/MasaBlazorApp3/Pages/OrderReturn.razor new file mode 100644 index 0000000..af1a5b6 --- /dev/null +++ b/MasaBlazorApp3/Pages/OrderReturn.razor @@ -0,0 +1,118 @@ +@page "/return/order" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + +
+
+
+ +@code { + @inject IOrderInfoDao orderInfoDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + string OrderNo; + DateTime OrderDate; + + void OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await orderInfoDao.GetAllCanReturnOrderInfo(OrderNo, OrderDate, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + await grid.Reload(); + } + + async Task OrderSelected(OrderInfo oi) + { + + var b = await dialogService.OpenAsync( + $"ҩ", + new Dictionary() { { "order", oi } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if(b) + { + await reloadGrid(); + } + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/OrderTake.razor b/MasaBlazorApp3/Pages/OrderTake.razor new file mode 100644 index 0000000..002032e --- /dev/null +++ b/MasaBlazorApp3/Pages/OrderTake.razor @@ -0,0 +1,118 @@ +@page "/take/order" + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + +
+
+
+ +@code { + @inject IOrderInfoDao orderInfoDao; + @inject DialogService dialogService; + + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + string OrderNo; + DateTime OrderDate; + + void OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await orderInfoDao.GetAllOrderInfo(OrderNo, OrderDate, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + OrderNo = ""; + OrderDate = DateTime.MinValue; + await grid.Reload(); + } + + async Task OrderSelected(OrderInfo oi) + { + + var b = await dialogService.OpenAsync( + $"", + new Dictionary() { { "order", oi } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if(b) + { + await reloadGrid(); + } + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/PlanManagement.razor b/MasaBlazorApp3/Pages/PlanManagement.razor new file mode 100644 index 0000000..a6734e6 --- /dev/null +++ b/MasaBlazorApp3/Pages/PlanManagement.razor @@ -0,0 +1,483 @@ +@page "/Box/Plan" + + +
+
+
+ + + + + + + + + + +
+
+ + + + + + + + + @* + + + + + *@ + + + + + + + + + + + + + + +
+
+ + @* + + + + *@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+ +@code { + @inject IPlanDao planDao; + @inject DialogService dialogService; + @inject NotificationService _message + @inject GlobalStateService globalStateService; + + RadzenDataGrid grid; + RadzenDataGrid PlanDetailsGrid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + IList? SelectedPlan { get; set; } = new List(); + List SelectedPlanDetails = new List(); + List drugInfos; + + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await planDao.GetAllPlanInfo(); + // Update the Data property + _forecasts = result.Desserts; + count = result.TotalDesserts; + SelectedPlan = new List() { _forecasts.FirstOrDefault() }; + + isLoading = false; + drugInfos = result.Other; + } + // async Task LoadDetailDate(LoadDataArgs args) + // { + // // SelectedPlan = new List() { await planDao.GetPlanById(SelectedPlan.FirstOrDefault().Id) }; + // } + async Task reloadGrid() + { + await grid.Reload(); + } + void OnUpdatePlanRow(Plan dl) + { + // Reset(dl); + + // 数据库更新 + planDao.UpdatePlanInfo(dl); + grid.Reload(); + } + async Task OnCreatePlanRow(Plan dl) + { + // 数据库添加套餐 + bool bFlag = await planDao.InsertPlanInfo(dl); + if (!bFlag) + { + SelectedPlan.Remove(dl); + } + grid.Reload(); + } + //新增套餐 + async Task InsertPlanRow() + { + var planInfo = new Plan(); + if (_forecasts.Count() <= 0) + { + _forecasts = new List + { + new Plan() + }; + await grid.InsertRow(_forecasts.FirstOrDefault()); + } + else + { + await grid.InsertRow(planInfo); + } + } + //修改套餐 + async Task EditPlanRow(Plan planInfo) + { + await grid.EditRow(planInfo); + } + //删除套餐 + async Task DeletePlanRow(Plan planInfo) + { + if (planInfo.Id > 0) + { + //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"删除确认", + new Dictionary() { { "confirmInfo", "确认要删除套餐:" + planInfo.Name + "吗?" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b) + { + //查询要删除的套餐下是否有绑定,且绑定有库存 + if (!(await planDao.CheckPlanBind(planInfo.Id))) + { + _message.Notify + ( + new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = $"该套餐还有库存绑定且有库存,请先清库存", + Duration = 4000 + } + ); + return; + } + + + // 数据库删除 + if (await planDao.DeletePlanInfo(planInfo.Id)) + { + _message.Notify + ( + new NotificationMessage + { + Severity = NotificationSeverity.Success, + Summary = "提示", + Detail = $"删除成功", + Duration = 4000 + } + ); + } + else + { + _message.Notify + ( + new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "删除失败", + Duration = 4000 + } + ); + } + } + await grid.Reload(); + } + else + { + grid.CancelEditRow(planInfo); + await grid.Reload(); + } + } + //保存套餐信息 + async Task SavePlanRow(Plan planInfo) + { + await grid.UpdateRow(planInfo); + } + async Task CancelPlanEdit(Plan planInfo) + { + grid.CancelEditRow(planInfo); + await grid.Reload(); + await PlanDetailsGrid.Reload(); + } + + + + void Reset(PlanDetails pd) + { + SelectedPlanDetails.Remove(pd); + } + //修改药品 + async Task EditRow(PlanDetails planDetail) + { + // planDetail.DrugId = null; + + await PlanDetailsGrid.EditRow(planDetail); + } + //保存修改药品 + async Task InsertRow(PlanDetails planDetail) + { + await PlanDetailsGrid.UpdateRow(planDetail); + } + //取消修改药品 + async Task CancelEdit(PlanDetails planDetail) + { + PlanDetailsGrid.CancelEditRow(planDetail); + SelectedPlan.FirstOrDefault()._PlanDetails.RemoveAll(pd => pd.Id == 0); + await PlanDetailsGrid.Reload(); + } + //删除药品 + async Task DeleteRow(PlanDetails planDetail) + { + // Reset(planDetail); + + if (planDetail.Id > 0) + { + //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"确认删除", + new Dictionary() { { "confirmInfo", "确认要删除药品:" + planDetail._DrugInfo.DrugName + "吗?" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + //查询要删除的药品是否有绑定且库存大于0 + if (!(await planDao.CheckPlanDetailBind(planDetail))) + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "该药品有绑定且库存不为0,请先清库存", + Duration = 4000 + }); + return; + } + + // 数据库删除 + if (await planDao.DeletePlanDetail(planDetail)) + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Success, + Summary = "提示", + Detail = "删除成功", + Duration = 4000 + } + ); + SelectedPlan.FirstOrDefault()._PlanDetails.Remove(planDetail); + } + else + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "删除失败", + Duration = 4000 + } + ); + } + await PlanDetailsGrid.Reload(); + } + } + else + { + PlanDetailsGrid.CancelEditRow(planDetail); + } + SelectedPlan.FirstOrDefault()._PlanDetails.RemoveAll(pd => pd.Id == 0); + } + async void OnUpdateRow(PlanDetails planDetail) + { + // Reset(planDetail); + + SelectedPlanDetails.Add(planDetail); + // 数据库更新 + if (await planDao.UpdatePlanDetail(planDetail)) + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Success, + Summary = "提示", + Detail = "修改成功", + Duration = 4000 + } + ); + } + else + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "修改失败", + Duration = 4000 + } + ); + } + + await PlanDetailsGrid.Reload(); + } + //保存套餐下添加的药品 + async void OnCreateRow(PlanDetails planDetail) + { + if (SelectedPlan.FirstOrDefault() != null) + { + + planDetail.PlanId = SelectedPlan.FirstOrDefault().Id; + planDetail.DrugId = planDetail.DrugId == null ? planDetail._DrugInfo.DrugId : planDetail.DrugId; + planDetail.UseState = 1; + planDetail.OperatorUser = globalStateService.Operator?.Username; + planDetail.ReviewerUser = globalStateService.Reviewer?.Username; + if (await planDao.AddPlanDetail(planDetail)) + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Success, + Summary = "提示", + Detail = "保存成功", + Duration = 4000 + } + ); + + + } + else + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "保存失败", + Duration = 4000 + } + ); + } + } + // await grid.Reload(); + await PlanDetailsGrid.Reload(); + + + } + //新增药品 + async Task InsertRow() + { + //查询要删除的套餐下是否有绑定,且绑定有库存 + if (SelectedPlan.FirstOrDefault()!=null) + { + if (!(await planDao.CheckPlanBind((int)SelectedPlan.FirstOrDefault().Id))) + { + _message.Notify(new NotificationMessage + { + Severity = NotificationSeverity.Error, + Summary = "提示", + Detail = "该药品有绑定且库存不为0,请先清库存", + Duration = 4000 + }); + return; + } + } + var detail = new Pojo.PlanDetails() + { + PlanId = SelectedPlan.FirstOrDefault().Id + }; + SelectedPlan.FirstOrDefault()._PlanDetails.Add(detail); + await PlanDetailsGrid.InsertRow(detail); + + } + //验证药品是否已存在套餐中 + bool ValidatroDrug(PlanDetails planDetail) + { + if (planDetail.PlanId == 0) + { + //新增的 + planDetail.PlanId = SelectedPlan.FirstOrDefault().Id; + } + return planDao.CheckDrugById(planDetail); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pages/RecordRetunDrug.razor b/MasaBlazorApp3/Pages/RecordRetunDrug.razor new file mode 100644 index 0000000..43623d0 --- /dev/null +++ b/MasaBlazorApp3/Pages/RecordRetunDrug.razor @@ -0,0 +1,191 @@ +@page "/return/byRecord" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + +
+ ѻ
ҩƷ +
+
+
+ + +
+ ѻ
ƿ +
+
+
+ + +
+
黹 +
+
+ + + +
+
+
+
+
+
+ +@code { + @inject IMachineRecordDao machineRecordDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private List? _forecasts; + + DateTime start; + DateTime end; + + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await machineRecordDao.GetCanReturnRecords(start, end, 0, "", args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + start = DateTime.MinValue; + end = DateTime.MinValue; + await grid.Reload(); + } + async Task OpenReturnDialog() + { + var list = _forecasts.Where(mr => mr.CurrentReturnQuantity > 0).ToList(); + + var b = await dialogService.OpenAsync( + $"¼ҩ", + new Dictionary() { { "records", list } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + + } + + void OnCellClick(DataGridCellMouseEventArgs args) + { + grid.EditRow(args.Data); + } + + + + +} diff --git a/MasaBlazorApp3/Pages/RecordReturnDrugDialog.razor b/MasaBlazorApp3/Pages/RecordReturnDrugDialog.razor new file mode 100644 index 0000000..4f11b95 --- /dev/null +++ b/MasaBlazorApp3/Pages/RecordReturnDrugDialog.razor @@ -0,0 +1,326 @@ +@page "/return/drug/{records}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + + + + + + + + + + + + + + + +
+ 还药
总数 +
+
+
+ +
+
+ + + +
+ + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status < 2) + { + + } + +
+ +@code { + @inject Radzen.DialogService dialogService; + @inject IMachineRecordDao machineRecordDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + + RadzenDataGrid>> grid; + + + private readonly ILog logger = LogManager.GetLogger(typeof(InvoiceAddDialog)); + + [Parameter] public List records { get; set; } + private bool CanTakeDrug = true; + int status = 0; + + public List>> data { get; set; } + + async Task StartAdd() + { + if (data.Any(it => it.Quantity != it.ChannelStocks.Sum(cs => cs.ReturnQuantity))) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请填写正确的入库数量!", Duration = 4000 } + ); + + } + else + { + await OpenDrawer(); + } + } + + async Task CancelOpera() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + status = 0; + dialogService.Close(false); + } + + + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + List channels = new(); + for (int i = 0; i < data.Count; i++) + { + channels = channels.Concat(data[i].ChannelStocks.Where(cs => cs.ReturnQuantity > 0)).ToList(); + } + if (channels.Count == 0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请填写正确的入库数量!", Duration = 4000 } + ); + return; + } + + List drawerNos = channels.GroupBy(it => it.DrawerNo).Select(it => it.Key).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + int index = 0; + var BeforeQuantity = new int[9]; + var AfterQuantity = new int[9]; + await new PromiseUtil().taskAsyncLoop(500, 0, async (options, next, stop) => + { + var drawerNo = drawerNos[index]; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (options._data == 0) + { + BeforeQuantity = new int[9]; + AfterQuantity = new int[9]; + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + var colNo = data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)); + await PortUtil.NoLightOnByCol(drawerNo, colNo.SelectMany(x => x).ToArray()); + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,加药"); + options._data = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (options._data == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + options._data = 0; + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + if (index == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"加药完成,请,点击完成按钮进行确认"); + this.status = 2; + stop(); + } + else + { + index += 1; + next(); + } + } + else + { + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + data.ForEach(cl => + { + // cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + // { + // logger.Info($"单支抽屉【{drawerNo}】,应加药品数量【{cs.AddQuantity}】,现实加药数量【{AfterQuantity[cs.ColNo - 1] - BeforeQuantity[cs.ColNo - 1]}】"); + // }); + cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + { + cl.ReturnQuantity = AfterQuantity[cs.ColNo - 1] - BeforeQuantity[cs.ColNo - 1]; + }); + }); + } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"还药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + this.status = 0; + } + + async Task AddFinish() + { + + // 保存账册、操作记录 + var b = await machineRecordDao.ReturnDrugFinish(data); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"抽屉加药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + + + protected override async Task OnInitializedAsync() + { + data = await machineRecordDao.getReturnDrugInfoByRecords(records); + // 如果有库位列表未空则说明不能取药,需要增加库位 + if (data.Any(it => it.ChannelStocks.Count == 0)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await Task.Delay(15); + await grid.ExpandRows(grid.PagedView.Where(it => it.ChannelStocks.Count > 0)); + } + } + + + void RowRender(RowRenderEventArgs>> args) + { + args.Expandable = args.Data.ChannelStocks != null && args.Data.ChannelStocks.Count > 0; + } + + + void OnCellClick(DataGridCellMouseEventArgs args, RadzenDataGrid Grid) + { + Grid.EditRow(args.Data); + } + + +} diff --git a/MasaBlazorApp3/Pages/RecordReturnEmpty.razor b/MasaBlazorApp3/Pages/RecordReturnEmpty.razor new file mode 100644 index 0000000..5e40ba3 --- /dev/null +++ b/MasaBlazorApp3/Pages/RecordReturnEmpty.razor @@ -0,0 +1,129 @@ +@page "/return/empty" + + +
+
+ @*
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
*@ +
+ + + @* + + + + *@ + + + + @* *@ + + + + + @* + + + + *@ + + +
+
+
+ +@code { + @inject IMachineRecordDao machineRecordDao; + @inject DialogService dialogService; + @inject NotificationService _message + RadzenDataGrid grid; + bool isLoading; + int count; + private List? _forecasts; + + // DateTime start; + // DateTime end; + + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + _forecasts = await machineRecordDao.GetReturnEmptyWithCanReturnQuantiy(); + // _forecasts = await machineRecordDao.GetReturnEmpty(); + + isLoading = false; + } + + async Task reloadGrid() + { + await grid.Reload(); + } + async Task OnCellClick(DataGridCellMouseEventArgs args) + { + if (string.IsNullOrEmpty(args.Data.DrugId)) + { + _message.Notify( + new NotificationMessage { Style = "position: absolute; inset-inline-start: -1000px;", Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"该库位无药品,请先绑药!", Duration = 4000 } + ); + return; + } + // grid.EditRow(args.Data); + var list = args.Data;// _forecasts.Where(mr => mr.DrawerNo > 0).ToList(); + + var b = await dialogService.OpenAsync( + $"归还空瓶", + new Dictionary() { { "records", list } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + await reloadGrid(); + } + } +} diff --git a/MasaBlazorApp3/Pages/RecordReturnEmptyDialog.razor b/MasaBlazorApp3/Pages/RecordReturnEmptyDialog.razor new file mode 100644 index 0000000..bf52e2b --- /dev/null +++ b/MasaBlazorApp3/Pages/RecordReturnEmptyDialog.razor @@ -0,0 +1,312 @@ +@page "/return/empty/{records}" +@using MasaBlazorApp3.Pojo.Config; +@using MasaBlazorApp3.Pojo.Vo; +@using MasaBlazorApp3.Util; +@using Microsoft.Extensions.Options; +@using Newtonsoft.Json; +@using log4net; + + + + + 药品:@drugName + + + 规格:@drugSpec + + + 厂家:@drugManufactory + + + 可还空瓶数:@emptyQuantity + + + +
+ + + + + 选择 + + + + + + + + + + + + + + + + + + +
+ + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status < 2) + { + + } + +@code +{ + @inject IMachineRecordDao machineRecordDao; + @inject Radzen.DialogService dialogService; + @inject IMachineRecordDao machineRecordDao; + @inject IOptions setting; + @inject NotificationService _message + @inject PortUtil PortUtil; + + [Parameter] + public ChannelStock records { get; set; } + // public PageData data { get; set; } + string drugName = string.Empty; + string drugSpec = string.Empty; + string drugManufactory = string.Empty; + int emptyQuantity = 0; + + RadzenDataGrid grid; + bool isLoading; + int count; + private List? _returnEmptys; + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + drugName = records.Drug.DrugName; + drugSpec = records.Drug.DrugSpec; + drugManufactory = records.Drug.Manufactory; + + var result = await machineRecordDao.getReturnEmptyInfoByRecords(records); + // Update the Data property + _returnEmptys = result.Desserts; + emptyQuantity = _returnEmptys.Sum(it => it.Quantity - it.ReturnQuantity1 - it.ReturnQuantity2); + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + await grid.Reload(); + } + void OnCellClick(DataGridCellMouseEventArgs args) + { + MachineRecord machineRecord = args.Data; + grid.EditRow(machineRecord); + if (machineRecord.CurrentReturnQuantity > 0 && args.Column.ColumnPickerTitle == "本次归还") + { + machineRecord.IsSelected = true; + } + else + { + machineRecord.IsSelected = !machineRecord.IsSelected; + if (machineRecord.IsSelected) + { + machineRecord.CurrentReturnQuantity = machineRecord.Quantity - machineRecord.ReturnQuantity1 - machineRecord.ReturnQuantity2; + } + else + { + machineRecord.CurrentReturnQuantity = 0; + } + } + } + + + private readonly ILog logger = LogManager.GetLogger(typeof(RecordReturnEmptyDialog)); + int status = 0; + async Task StartAdd() + { + if (_returnEmptys.Where(it => it.CurrentReturnQuantity > 0).Count() <= 0) + { + _message.Notify( + new NotificationMessage { Style = "position: absolute; inset-inline-start: -1000px;", Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请选择药品!", Duration = 4000 } + ); + + } + else + { + await OpenDrawer(); + } + } + + async Task CancelOpera() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + status = 0; + dialogService.Close(false); + } + + + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 解析需要打开的抽屉列表 + + int drawerNo = records.DrawerNo; + + // 根据抽屉类型来决定打开前是否需要查询数量 + int index = 0; + var BeforeQuantity = new int[9]; + var AfterQuantity = new int[9]; + await new PromiseUtil().taskAsyncLoop(500, 0, async (options, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (options._data == 0) + { + BeforeQuantity = new int[9]; + AfterQuantity = new int[9]; + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + + //await PortUtil.NoLightOnByCol(drawerNo, data.Select(ot => ot.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).Select(cs => cs.ColNo)).Cast().ToArray()); + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请放入空瓶"); + options._data = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (options._data == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + options._data = 0; + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"加药完成,请,点击完成按钮进行确认"); + this.status = 2; + stop(); + } + else + { + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉【{drawerNo}】,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + // data.ForEach(cl => + // { + // cl.ChannelStocks.Where(cs => cs.DrawerNo == drawerNo).ToList().ForEach(cs => + // { + // logger.Info($"单支抽屉【{drawerNo}】,应还空瓶数量【{cs.AddQuantity}】,现实还数量【{AfterQuantity[cs.ColNo - 1] - BeforeQuantity[cs.ColNo - 1]}】"); + // }); + + // }); + } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"还空瓶发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + this.status = 0; + } + + async Task AddFinish() + { + + // 保存账册、操作记录 + var b = await machineRecordDao.ReturnEmptyFinish(_returnEmptys.Where(it => it.CurrentReturnQuantity > 0).ToList(), records); + if (!b) + { + _message.Notify(new NotificationMessage { Style = "position: absolute; inset-inline-start: -1000px;", Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"还空瓶保存数据库失败,数据{JsonConvert.SerializeObject(_returnEmptys)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + _message.Notify(new NotificationMessage { Style = "position: absolute; inset-inline-start: -1000px;", Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"还空瓶操作完成!", Duration = 4000 }); + + } + //重置状态 + this.RestData(); + } +} diff --git a/MasaBlazorApp3/Pages/ReturnRecord2.razor b/MasaBlazorApp3/Pages/ReturnRecord2.razor new file mode 100644 index 0000000..33a9bac --- /dev/null +++ b/MasaBlazorApp3/Pages/ReturnRecord2.razor @@ -0,0 +1,101 @@ +@page "/return/record2" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + +
+
+
+ +@code { + @inject IMachineRecordDao machineRecordDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime start; + DateTime end; + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await machineRecordDao.GetMachineRecordAsync(start, end, 0, "", 32, args.Top, args.Skip); + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + start = DateTime.MinValue; + end = DateTime.MinValue; + await grid.Reload(); + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/Role.razor b/MasaBlazorApp3/Pages/Role.razor new file mode 100644 index 0000000..0455210 --- /dev/null +++ b/MasaBlazorApp3/Pages/Role.razor @@ -0,0 +1,268 @@ +@page "/manage/role" + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + @string.Join(", ", allPremissions.Where(g => role.permissionIds?.Contains(g.Id) == true).Take(dd.MaxSelectedLabels).Select(g => $"{g.PremissionName}")) + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +@code { + @inject IRoleDao roleDao; + @inject DialogService dialogService; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? roleList; + + + RadzenDropDown> dd; + IEnumerable allPremissions; + + string RoleName; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + List t = new Premission().getAdminPremission(); + IEnumerable t2 = Enumerable.Empty(); + for (var i = 0; i < t.Count; i++) + { + t2 = t2.Concat(new Premission[] { t[i] }); + t2 = t2.Concat(t[i].Items); + } + + allPremissions = t2; + } + + + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await roleDao.GetRolesByName(RoleName, args.Top, args.Skip); + // Update the Data property + roleList = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + RoleName = ""; + await grid.Reload(); + } + + + List rolesToInsert = new List(); + List rolesToUpdate = new List(); + + void Reset() + { + rolesToInsert.Clear(); + rolesToUpdate.Clear(); + } + + void Reset(Pojo.Role role) + { + rolesToInsert.Remove(role); + rolesToUpdate.Remove(role); + } + + async Task EditRow(Pojo.Role role) + { + + Reset(); + + rolesToUpdate.Add(role); + await grid.EditRow(role); + } + + void OnUpdateRow(Pojo.Role role) + { + Reset(role); + + // 数据库更新 + roleDao.UpdateRole(role); + } + + async Task SaveRow(Pojo.Role role) + { + await grid.UpdateRow(role); + } + + void CancelEdit(Pojo.Role role) + { + Reset(role); + + grid.CancelEditRow(role); + grid.Reload(); + } + + async Task DeleteRow(Pojo.Role role) + { + Reset(role); + + if (roleList.Contains(role)) + { + //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"删除确认", + new Dictionary() { { "confirmInfo", "确认要删除角色:" + role.RoleName+"吗?" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b) + { + // 数据库删除 + roleDao.DeleteRole(role.Id); + } + await grid.Reload(); + } + else + { + grid.CancelEditRow(role); + await grid.Reload(); + } + } + + async Task InsertRow() + { + + Reset(); + var role = new Pojo.Role(); + rolesToInsert.Add(role); + await grid.InsertRow(role); + } + + void OnCreateRow(Pojo.Role role) + { + // 数据库添加用户 + int id = roleDao.InsertRole(role); + rolesToInsert.Remove(role); + grid.Reload(); + } + + void ItemRender(DropDownItemRenderEventArgs> args) + { + // Use this code to prevent default item selection. + args.Disabled = true; + args.Attributes.Add("style", $"opacity:1;{(((Premission)args.Item).Parent == null ? "" : "margin-inline-start:1rem")}"); + } + + + + + + bool? IsGroupSelected(Pojo.Role role,Premission p) + { + IEnumerable permissionIds = role.permissionIds; + if (p.Parent == null) + { + return p.Items.Any() && p.Items.All(i => permissionIds?.Contains(i.Id) == true) ? true : + p.Items.Any(i => permissionIds?.Contains(i.Id) == true) ? null : false; + } + + return permissionIds?.Contains(p.Id) == true; + } + + void SelectGroup(bool? value, Pojo.Role role, Premission p) + { + IEnumerable permissionIds = role.permissionIds; + var newValues = permissionIds ?? Enumerable.Empty(); + var items = p.Parent == null ? p.Items.Select(i => i.Id) : new int[] { p.Id }; + role.permissionIds = value == true ? newValues.Concat(items) : newValues.Except(items); + } + + + + +} diff --git a/MasaBlazorApp3/Pages/SelfTake.razor b/MasaBlazorApp3/Pages/SelfTake.razor new file mode 100644 index 0000000..ef8e7a4 --- /dev/null +++ b/MasaBlazorApp3/Pages/SelfTake.razor @@ -0,0 +1,294 @@ +@page "/take/self" +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + @* *@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+@code { + @inject IChannelListDao channelListDao; + @inject IDrugInfoDao drugInfoDao; + @inject NotificationService _message + @inject DialogService dialogService; + RadzenDataGrid grid; + List orderDetails = new(); + + List drugInfos = new(); + + List detailsToInsert = new(); + List detailsToUpdate = new(); + + + OrderInfo orderInfo = new OrderInfo() + { + OrderDate = DateTime.Now + }; + + + + void Reset() + { + detailsToInsert.Clear(); + detailsToUpdate.Clear(); + } + void Reset(OrderDetail orderDetail) + { + detailsToInsert.Remove(orderDetail); + detailsToUpdate.Remove(orderDetail); + } + + async Task InsertRow() + { + + Reset(); + var orderDetail = new OrderDetail(); + detailsToInsert.Add(orderDetail); + await grid.InsertRow(orderDetail); + } + + async Task EditRow(OrderDetail orderDetail) + { + + Reset(); + + detailsToUpdate.Add(orderDetail); + await grid.EditRow(orderDetail); + } + + async Task SaveRow(OrderDetail orderDetail) + { + await grid.UpdateRow(orderDetail); + } + + void CancelEdit(OrderDetail orderDetail) + { + Reset(orderDetail); + + grid.CancelEditRow(orderDetail); + grid.Reload(); + } + + async Task DeleteRow(OrderDetail orderDetail) + { + Reset(orderDetail); + orderDetails.Remove(orderDetail); + grid.CancelEditRow(orderDetail); + await grid.Reload(); + } + + void OnUpdateRow(OrderDetail orderDetail) + { + Reset(orderDetail); + + grid.Reload(); + } + + void OnCreateRow(OrderDetail orderDetail) + { + // 数据库添加用户 + detailsToInsert.Remove(orderDetail); + orderDetails.Add(orderDetail); + grid.Reload(); + } + + async void Submit(OrderInfo orderInfo) + { + if (orderDetails.Count == 0) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"请添加用药详情", Duration = 3000 } + ); + } + else + { + //弹出待取药品所在库位、库存信息 + var b = await dialogService.OpenAsync( + $"取药详情", + new Dictionary() { { "order", orderInfo }, { "orderDetails", orderDetails } }, + new DialogOptions() { Width = "85vw", Resizable = true, Draggable = true, ShowClose = false } + ); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"取药完成", Duration = 3000 } + ); + } + } + } + async Task reloadGrid() + { + + await grid.Reload(); + } + bool ValidateDrug(DrugInfo drugInfo) + { + return !orderDetails.Any(od => od.Drug.DrugId.Equals(drugInfo?.DrugId)); + } + + protected override async Task OnInitializedAsync() + { + drugInfos = await drugInfoDao.GetAllDrugAndStock(); + + base.OnInitializedAsync(); + } + + void OnCurrentDateChanged(DateTime args) + { + orderInfo.ChargeDate = new DateTime(args.Year, args.Month, args.Day, args.Hour, args.Minute, args.Second); + } +} diff --git a/MasaBlazorApp3/Pages/SelfTakeDialog.razor b/MasaBlazorApp3/Pages/SelfTakeDialog.razor new file mode 100644 index 0000000..6f754e8 --- /dev/null +++ b/MasaBlazorApp3/Pages/SelfTakeDialog.razor @@ -0,0 +1,334 @@ +@page "/selfDetail/{order}" +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Pojo.Vo +@using MasaBlazorApp3.Util +@using Microsoft.Extensions.Options +@using Newtonsoft.Json +@using log4net + + + + + 处方号: + @(order?.OrderNo) + 患者姓名: + @(order?.PatientName) + 性别: + @(order?.Sex) + 年龄: + @(order?.Age) + + + @if (CanTakeDrug) + { + + + + + + + + + + + + + } + else + { + + + + + + + + + } + + + + + + @if (status < 2) + { + + } + @if (status == 2) + { + + } + @if (status <= 2) + { + + } + + +@code { +@inject Radzen.DialogService dialogService; + @inject NotificationService _message + @inject PortUtil PortUtil; + @inject ISelfTakeDao selfTakeDao; + @inject IOptions setting; + private readonly ILog logger = LogManager.GetLogger(typeof(OrderDetailDialog)); + + int status; + + [Parameter] public OrderInfo order { get; set; } + [Parameter] public List orderDetails { get; set; } + + + private bool CanTakeDrug = true; + //开抽屉前操作标识 + List DrawerNoColNoList = new List(); + public List data { get; set; } + //称重取药数量 + int[] WeightFinnalQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + protected override async Task OnInitializedAsync() + { + data = await selfTakeDao.getTakeInfoByOrderNo(orderDetails); + // 如果有【stockQuantity】字段说明有药品库存不足 + if (data.Any(it => it.ChannelStock == null)) + { + CanTakeDrug = false; + } + base.OnInitializedAsync(); + } + + async Task OpenDrawer() + { + this.status = 1; + // 解析需要打开的抽屉列表 + List drawerNos = this.data.GroupBy(it => it.ChannelStock.DrawerNo).Select(it => it.First()).ToList(); + + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + + await promiseUtil.taskAsyncLoop(500, 0, async (options, next, stop) => + { + var orderTakeVo = drawerNos[options._data]; + var drawerNo = orderTakeVo.ChannelStock.DrawerNo; + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + if (orderTakeVo.Status == 0) + { + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", orderTakeVo.BeforeQuantity)}】"); + + await PortUtil.HasLightOnByCol(drawerNo, data.Where(ot => ot.ChannelStock.DrawerNo == drawerNo).Select(ot => ot.ChannelStock.ColNo).ToArray()); + } + for (int i = 0; i < data.Count; i++) + { + if (!DrawerNoColNoList.Contains(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo)) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = data[i].ChannelStock.DrawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,开抽屉前检测数量【{string.Join(",", data[i].BeforeQuantity)}】"); + await Task.Delay(200); + } + + //是药盒抽屉开药盒 + if (data[i].ChannelStock.BoardType.ToString().Contains("3")) + { + PortUtil.DrawerNo = drawerNo; + await PortUtil.OpenBoxByColNo(data[i].ChannelStock.ColNo); + await Task.Delay(200); + } + DrawerNoColNoList.Add(data[i].ChannelStock.DrawerNo.ToString() + data[i].ChannelStock.ColNo); + } + } + var b = await PortUtil.OpenDrawerStatus(drawerNo); + if (b) + { + PortUtil.Operate = true; + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,取药"); + orderTakeVo.Status = 1; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + PortUtil.PowerOff(); + RestData(); + stop(); + } + } + // 检测状态 + else if (orderTakeVo.Status == 1) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + + data.ForEach(cl => + { + if (cl.ChannelStock.DrawerNo == drawerNo) + { + cl.GetQuantity = cl.Quantity; + + } + }); + PortUtil.Operate = false; + orderTakeVo.Status = 2; + PortUtil.PowerOff(); + if (options._data == drawerNos.Count - 1) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"取药完成,请,点击完成按钮进行确认"); + this.status = 2; + string alertMessage = string.Empty; + //检查是否称重抽屉,核对实际取出数量是否与应取数量一致,不一致则弹出提示 + for (int i = 0; i < data.Count; i++) + { + if (data[i].ChannelStock.BoardType.ToString().Contains("6")) + { + PortUtil.DrawerNo = drawerNo; + PortUtil.ColNoLst.Add(data[i].ChannelStock.ColNo); + + orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1] = await PortUtil.CheckQuantityForSingle(data[i].ChannelStock.ColNo); + logger.Info($"称重抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = orderTakeVo.BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + //称重自动计数数量与实际要取数量不一致弹出提示,确认后保存数据 + alertMessage += $"{data[i].Drug.DrugName}应取数量【{data[i].Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + + } + await Task.Delay(200); + } + + if (data[i].ChannelStock.BoardType.ToString().Contains("2")) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,关抽屉后检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1] = data[i].BeforeQuantity[data[i].ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[data[i].ChannelStock.ColNo - 1]; + if (data[i].Quantity != WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]) + { + alertMessage += $"{data[i].Drug.DrugName}应取数量【{orderTakeVo.Quantity}】,实际取出数量【{WeightFinnalQuantity[data[i].ChannelStock.ColNo - 1]}】"; + } + } + } + if (!string.IsNullOrEmpty(alertMessage)) + { + //弹出确认对话框 + alertMessage += "应取数与实际取出数不一致确认要保存吗?"; + //弹出确认提示框 + var confirm = await dialogService.OpenAsync( + $"保存确认", + new Dictionary() { { "confirmInfo", alertMessage } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + logger.Info(alertMessage); + if (!confirm) + { + RestData(); + logger.Info("取消保存"); + // 关闭弹窗 + dialogService.Close(false); + } + } + stop(); + } + else + { + options._data += 1; + next(); + } + } + else + { + // if (setting.Value.single.Contains(drawerNo)) + // { + // byte[] quantity = await PortUtil.CheckQuantityByDrawer(drawerNo); + // orderTakeVo.AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + // logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", orderTakeVo.AfterQuantity)}】"); + + // data.ForEach(cl => + // { + // if (cl.ChannelStock.DrawerNo == drawerNo) + // { + // logger.Info($"单支抽屉【{drawerNo}】,应取药品数量【{orderTakeVo.Quantity}】,现实取数量【{orderTakeVo.BeforeQuantity[cl.ChannelStock.ColNo - 1] - orderTakeVo.AfterQuantity[cl.ChannelStock.ColNo - 1]}】"); + // } + + // }); + // } + next(); // continue iteration + } + } + + + } + } + catch (Exception e) + { + RestData(); + logger.Info($"处方取药发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(drawerNo)) + { + PortUtil.PowerOff(); + } + stop(); + } + }); + } + async Task CancelOpera() + { + RestData(); + dialogService.Close(false); + } + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + } + + async Task TakeFinish() + { + + // 保存账册、操作记录 + var b = await selfTakeDao.OrderTakeFinish(data,order); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"自选取药保存数据库失败,数据{JsonConvert.SerializeObject(data)}"); + // 关闭弹窗 + dialogService.Close(false); + } + else + { + // 关闭弹窗 + dialogService.Close(true); + + } + //重置状态 + this.RestData(); + } + +} diff --git a/MasaBlazorApp3/Pages/SignatureDialog.razor b/MasaBlazorApp3/Pages/SignatureDialog.razor new file mode 100644 index 0000000..070fd26 --- /dev/null +++ b/MasaBlazorApp3/Pages/SignatureDialog.razor @@ -0,0 +1,67 @@ +@page "/signature/{user}" +@page "/signature" +@layout EmptyLayout + + @if (user.Sign != null) + { + + } +
+ +
+ + + + + +
+ + +
+
+ +@code { + @inject IJSRuntime JsRuntime; + @inject NotificationService _message; + @inject IUserDao userDao; + private IJSObjectReference module; + @inject DialogService dialogService; + [Parameter] public Pojo.User user { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + // 导入。路径是相对wwwroot写的,其他位置参考顶部链接 + module = await JsRuntime.InvokeAsync("import", "./signatureInit.js"); + await module.InvokeVoidAsync("createSignatrue"); + } + + } + + async Task handleClear() + { + await module.InvokeVoidAsync("clear"); + } + async Task handleUndo() + { + await module.InvokeVoidAsync("undo"); + } + async Task handlePreview() + { + bool flag = await module.InvokeAsync("isEmpty"); + if (flag) + { + } + else + { + string base64 = await module.InvokeAsync("getPNG"); + + await userDao.UpdateSign(user.Id, base64.Split(",")[1]); + + dialogService.Close(true); + + } + } + +} diff --git a/MasaBlazorApp3/Pages/StockBinding.razor b/MasaBlazorApp3/Pages/StockBinding.razor new file mode 100644 index 0000000..d355e97 --- /dev/null +++ b/MasaBlazorApp3/Pages/StockBinding.razor @@ -0,0 +1,293 @@ +@page "/stock/binding" + + +
+
+ @*
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
*@ +
+ + + + +
+
+
+ +@code { + @inject IChannelListDao channelListDao; + @inject IDrugInfoDao drugInfoDao; + @inject DialogService dialogService; + @inject NotificationService _message + RadzenDataList grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + + List drugInfos; + List drugManuNos; + + DrugInfo drugInfo; + + DrugManuNo drugManuNo; + + + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + //drugInfos = await drugInfoDao.GetAllDrug(); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + // var result = await channelListDao.GetAllChannelList(0, "", args.Top, args.Skip); + var result = await channelListDao.GetAllChannelListWithDrug(0, "", args.Top, args.Skip); + + // Update the Data property + _forecasts = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + + drugInfos = result.Other; + } + + async Task reloadGrid() + { + await grid.Reload(); + } + + async Task EditChannel(ChannelStock stock) + { + if(stock.drugManuNo != null) + { + // 说明之前有绑定并且未改变,那么就是在进行解绑 + if(stock.drugManuNo.ManuNo.Equals(stock.ManuNo)) + { + var b = await channelListDao.UnBind(stock.Id); + if(b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"解除绑定成功", Duration = 4000 } + ); + await reloadGrid(); + } + + } + // 否则是进行绑定 + else + { + var b = await channelListDao.Bind(stock); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"绑定成功", Duration = 4000 } + ); + await reloadGrid(); + } + } + } else + { + if (stock.Drug != null) + { + // 说明只设置了药品 + var b = await channelListDao.Bind(stock); + if (b) + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"绑定成功", Duration = 4000 } + ); + await reloadGrid(); + } + } + // 什么都没有选择或者么有改变,只是点击了按钮,此时不操作 + else + { + + } + } + } + + + + + +} diff --git a/MasaBlazorApp3/Pages/StockCheck.razor b/MasaBlazorApp3/Pages/StockCheck.razor new file mode 100644 index 0000000..92a4520 --- /dev/null +++ b/MasaBlazorApp3/Pages/StockCheck.razor @@ -0,0 +1,321 @@ +@page "/stock/check" +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Util +@using Microsoft.Extensions.Options +@using Newtonsoft.Json +@using log4net + + + +
+
+ @* *@ +
+ @foreach (int i in DrawerNos) + { + if (setting.Value.returnDrawer != null && setting.Value.returnDrawer.Contains(i)) + { + + } + else + { + + } + } +
+ @*
*@ +
+
+ + + + @if (status < 3) + { + + } + @if (status == 3) + { + + } + @if (status > 0 && status <= 3) + { + + } + + + + + + + + + + + + @if (channel.Quantity == 0 && !String.IsNullOrEmpty(channel.DrugId)) + { + + + + + @((context as DrugManuNo)?.ManuNo) + @((context as DrugManuNo)?.EffDate) + + + + + } + else + { + + @channel.drugManuNo?.ManuNo + @channel.drugManuNo?.EffDate + } + + + + + + + + @if (cs.BoardType.ToString().Contains("2") || cs.BoardType.ToString().Contains("3")) + { + @cs.CheckQuantity + } + else + { + + + + } + + + + + +
+@code { + @inject IChannelListDao channelListDao; + @inject NavigationManager na; + @inject PortUtil PortUtil; + @inject NotificationService _message + @inject IOptions setting; + int status = 0; + int drawerNo = 1; + RadzenDataGrid grid; + private List? channels; + bool isLoading; + int count; + int[] DrawerNos = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + int[] BeforeQuantity = new int[9]; + int[] AfterQuantity = new int[9]; + private readonly ILog logger = LogManager.GetLogger(typeof(DrawerAdd)); + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await channelListDao.GetChannelStockByDrawerNoWithDrawers(drawerNo); + // var result = await channelListDao.GetChannelStockByDrawerNo(drawerNo); + // Update the Data property + DrawerNos = result.DrawerArray; + // for (int i = 0; i < result.ChannelStocks.Count; i++) + // { + // result.ChannelStocks[i].CheckQuantity = result.ChannelStocks[i].Quantity; + // } + result.ChannelStocks.ForEach(cs => cs.CheckQuantity = cs.Quantity); + channels = result.ChannelStocks; + // Update the count + count = result.ChannelStocks.Count; + + + isLoading = false; + } + async Task OpenDrawer() + { + this.status = 1; + PortUtil.PowerOn(); + await Task.Delay(200); + // 根据抽屉类型来决定打开前是否需要查询数量 + var promiseUtil = new PromiseUtil(); + await promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + try + { + if (this.status == 0) + { + stop(); + } + // 开启抽屉 + else if (this.status == 1) + { + // 判断是否为单支抽屉 + if (setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + BeforeQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,开抽屉前检测数量【{string.Join(",", BeforeQuantity)}】"); + } + var b = await PortUtil.OpenDrawerStatus(this.drawerNo); + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"{drawerNo}号抽屉已经打开,请,盘点"); + this.status = 2; + next(); + } + else + { + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"抽屉【{drawerNo}】打开失败,请检测硬件", Duration = 4000 } + ); + logger.Info($"抽屉打开失败"); + RestData(); + stop(); + } + + } + // 检测状态 + else if (this.status == 2) + { + // 查询抽屉是否为关闭状态 + var b = await PortUtil.CheckDrawerStatus2(drawerNo); + // 关闭则改变状态并终止循环 + if (b) + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + PortUtil.SpeakAsync($"盘点完成,请,核对,或,录入,正确的,盘点数量"); + this.status = 3; + stop(); + } + else + { + if (setting.Value.single.Contains(this.drawerNo)) + { + byte[] quantity = await PortUtil.CheckQuantityByDrawer(this.drawerNo); + AfterQuantity = quantity.Select(it => Convert.ToInt32(it)).ToArray().Skip(3).Take(9).ToArray(); + logger.Info($"单支抽屉,抽屉未关检测数量【{string.Join(",", AfterQuantity)}】"); + + channels.ForEach(cl => + { + cl.CheckQuantity = this.AfterQuantity[cl.ColNo - 1];// - this.BeforeQuantity[cl.ColNo - 1]; + }); + await InvokeAsync(StateHasChanged); + } + next(); // continue iteration + } + + } + } + catch (Exception e) + { + logger.Info($"抽屉盘点发生错误,{e.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"发生错误,{e.Message}", Duration = 4000 } + ); + if (setting.Value.single.Contains(this.drawerNo)) + { + PortUtil.PowerOff(); + } + RestData(); + stop(); + } + }); + PortUtil.PowerOff(); + } + + void RestData() + { + PortUtil.PowerOff(); + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + this.status = 0; + this.BeforeQuantity = new int[9]; + this.AfterQuantity = new int[9]; + } + async Task CheckFinish() + { + if (channels.Any(cl => cl.CheckQuantity != cl.Quantity && cl.DrugId != null && cl.drugManuNo != null)) + { + // 保存账册、操作记录 + var b = await channelListDao.DrawerCheckFinish(channels.Where(cl => cl.CheckQuantity != cl.Quantity).ToList()); + if (!b) + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"数据保存失败", Duration = 4000 }); + logger.Error($"盘点保存数据库失败,数据{JsonConvert.SerializeObject(channels)}"); + } + else + { + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"盘点完成", Duration = 4000 }); + logger.Info($"盘点完成"); + + } + } + + //重置状态 + this.RestData(); + // 重新查询库存 + await grid.Reload(); + } + + void Cancel() + { + RestData(); + } + + void SelectDrawer(int drawerNo) + { + this.drawerNo = drawerNo; + grid.Reload(); + } + + void OnCellClick(DataGridCellMouseEventArgs args) + { + grid.EditRow(args.Data); + } + private IDisposable? registration; + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + registration = na.RegisterLocationChangingHandler(OnLocationChanging); + } + } + + private ValueTask OnLocationChanging(LocationChangingContext context) + { + // 操作中不可跳转页面 + if (status > 0) + { + context.PreventNavigation(); //阻止导航 + } + return ValueTask.CompletedTask; + } + //在生命周期函数Dispose中,移除订阅的事件,并销毁非托管资源registration=========================================== + public void Dispose() + { + registration?.Dispose(); + } +} diff --git a/MasaBlazorApp3/Pages/StockList.razor b/MasaBlazorApp3/Pages/StockList.razor new file mode 100644 index 0000000..9d07b9e --- /dev/null +++ b/MasaBlazorApp3/Pages/StockList.razor @@ -0,0 +1,285 @@ +@page "/stock/list" +@using MasaBlazorApp3.Report +@using Radzen.Blazor.Rendering + +
+ + @*
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
*@ +
+
+ + + @* + + + + + *@ + + + + + + + + + + +
+ +@code { + @inject IDrugInfoDao drugInfoDao; + @inject DialogService dialogService; + @inject IReportDataDao reportDataDao; + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? _forecasts; + DateTime? start; + DateTime? end; + + string drugName; + RadzenButton button; + + Popup popup2; + IEnumerable drugInfo; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + isLoading = true; + + var result = await drugInfoDao.GetAllDrugAndStock(); + // Update the Data property + _forecasts = result; + + drugInfo = await drugInfoDao.GetAllDrug(); + + isLoading = false; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + await grid.ExpandRows(grid.PagedView.Where(di => di.Stocks.Count > 0)); + } + } + + void RowRender(RowRenderEventArgs args) + { + args.Expandable = args.Data.Stocks.Count > 0; + } + + + // //浼 + // async Task StockExport() + // { + // PageData pageData = await reportDataDao.GetStockExportData(drugName); + // GridReportUtil.PrintReport("stock_template.grf", pageData); + // } + //ר˲ᵼ + async Task AccountBookExport() + { + // string drugId = drugName != null ? drugName.Split('/').Last().Trim():""; + // GridReportUtil gridReportUtil = new GridReportUtil(); + PageData pageData = await reportDataDao.GetAccountExportData(start, end, drugName); + GridReportUtil.PrintReport("account_book_temp.grf", pageData); + } + + // + async Task reloadGrid() + { + start = DateTime.MinValue; + end = DateTime.MinValue; + drugName = string.Empty; + await grid.Reload(); + } + +} diff --git a/MasaBlazorApp3/Pages/TEST.razor b/MasaBlazorApp3/Pages/TEST.razor new file mode 100644 index 0000000..a283c7b --- /dev/null +++ b/MasaBlazorApp3/Pages/TEST.razor @@ -0,0 +1,87 @@ +@page "/TEST" +@layout EmptyLayout + + + + + + + @* TextProperty="@(PropertyAccess.GetDynamicPropertyExpression("LastName", typeof(string)))"> *@ + + @string.Join(", ", columns.Where(c => c.Value == typeof(string)).Take(grid.MaxSelectedLabels).Select(c => context[c.Key])) + + + @foreach (var column in columns) + { + + @* Property="@PropertyAccess.GetDynamicPropertyExpression(column.Key, column.Value)"> *@ + + + } + + + + + +@code { + RadzenDropDownDataGrid> grid; + IDictionary selectedItem; + + public IEnumerable> data { get; set; } + + public IDictionary columns { get; set; } + + public enum EnumTest + { + EnumValue1, + EnumValue2 + } + + void OnChange(object value) + { + selectedItem = (IDictionary)value; + } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + columns = new Dictionary() + { + { "EmployeeID", typeof(int) }, + { "MyColumn", typeof(EnumTest) }, + { "FirstName", typeof(string) }, + { "LastName", typeof(string) }, + { "HireDate", typeof(DateTime) }, + }; + + foreach (var i in Enumerable.Range(0, 50)) + { + columns.Add($"Column{i}", typeof(string)); + } + + data = Enumerable.Range(0, 100).Select(i => + { + var row = new Dictionary(); + + foreach (var column in columns) + { + row.Add( + column.Key, + column.Value == typeof(EnumTest) + ? (i % 2 == 0 ? EnumTest.EnumValue1 : EnumTest.EnumValue2) + : column.Value == typeof(int) + ? i + : column.Value == typeof(DateTime) + ? DateTime.Now.AddMonths(i) + : $"{column.Key}{i}" + ); + } + + return row; + }); + } +} diff --git a/MasaBlazorApp3/Pages/User.razor b/MasaBlazorApp3/Pages/User.razor new file mode 100644 index 0000000..34f75e3 --- /dev/null +++ b/MasaBlazorApp3/Pages/User.razor @@ -0,0 +1,306 @@ +@page "/manage/user" + +@using log4net; + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +@code { + @inject IUserDao userDao; + @inject IRoleDao roleDao; + @inject DialogService dialogService; + @inject NotificationService _message + RadzenDataGrid grid; + bool isLoading; + int count; + private IEnumerable? userList; + string nickname; + DateTime OrderDate; + private readonly ILog logger = LogManager.GetLogger(typeof(Pages.User)); + + List roles; + + + + + List usersToInsert = new List(); + List usersToUpdate = new List(); + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + roles = await roleDao.GetAllRoles(); + } + + void Reset() + { + usersToInsert.Clear(); + usersToUpdate.Clear(); + } + + async Task Reg2ZWJ(Pojo.User user) + { + await dialogService.OpenAsync( + $"录入指纹", + new Dictionary() { { "userId", user.Id } }, + new DialogOptions() { Width = "55vw", Resizable = true, Draggable = true, ShowClose = false } + ); + } + + async Task Signatrue(Pojo.User user) + { + var flag = await dialogService.OpenAsync( + $"签名-{user.NickName}", + new Dictionary() { { "user", user } }, + new DialogOptions() { Width = "55vw", Resizable = true, Draggable = true, ShowClose = true } + ); + if(flag != null && flag) + { + await reloadGrid(); + } + } + + + void Reset(Pojo.User user) + { + usersToInsert.Remove(user); + usersToUpdate.Remove(user); + } + + void OnCurrentDateChanged(DateTime args) + { + OrderDate = new DateTime(args.Year, args.Month, args.Day); + } + + async Task LoadData(LoadDataArgs args) + { + isLoading = true; + + var result = await userDao.GetAllByNickname(nickname, args.Top, args.Skip); + // Update the Data property + userList = result.Desserts; + // Update the count + count = result.TotalDesserts; + + isLoading = false; + } + + async Task reloadGrid() + { + nickname = ""; + await grid.Reload(); + } + + async Task EditRow(Pojo.User user) + { + + Reset(); + + usersToUpdate.Add(user); + await grid.EditRow(user); + } + + void OnUpdateRow(Pojo.User user) + { + Reset(user); + + // 数据库更新 + userDao.UpdateUser(user); + if(user.role.Id != user.RoleId) + { + grid.Reload(); + } + } + + async Task SaveRow(Pojo.User user) + { + await grid.UpdateRow(user); + } + + void CancelEdit(Pojo.User user) + { + Reset(user); + + grid.CancelEditRow(user); + grid.Reload(); + } + + async Task DeleteRow(Pojo.User user) + { + Reset(user); + + if (userList.Contains(user)) + { + //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"删除确认", + new Dictionary() { { "confirmInfo", "确认要删除用户:"+user.Username+"吗?" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b) + { + // 数据库删除 + userDao.DeleteeUser(user.Id); + } + await grid.Reload(); + } + else + { + grid.CancelEditRow(user); + await grid.Reload(); + } + } + //重置密码 + async Task ResetPasswordRow(Pojo.User user) + { + Reset(user); + + if (userList.Contains(user)) + { + //弹出确认提示框 + var b = await dialogService.OpenAsync( + $"密码重置确认", + new Dictionary() { { "confirmInfo", "确认要重置用户:" + user.Username+" 的密码吗?" } }, + new DialogOptions() { Width = "45vw", Resizable = true, Draggable = true, ShowClose = false }); + if (b) + { + // 数据库重置密码 + userDao.ResetPassword(user.Id); + //提示密码已重置,下次登录请使用重置后的密码 + _message.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "提示", Detail = $"密码已重置,下次登录请使用重置后的密码", Duration = 4000 }); + } + await grid.Reload(); + } + else + { + grid.CancelEditRow(user); + await grid.Reload(); + } + } + + async Task InsertRow() + { + + Reset(); + var user = new Pojo.User() + { + RoleId = roles[0].Id, + }; + usersToInsert.Add(user); + await grid.InsertRow(user); + } + + void OnCreateRow(Pojo.User user) + { + // 数据库添加用户 + userDao.InsertUser(user); + usersToInsert.Remove(user); + grid.Reload(); + } + + + + + + +} diff --git a/MasaBlazorApp3/Pojo/AccountBook.cs b/MasaBlazorApp3/Pojo/AccountBook.cs new file mode 100644 index 0000000..525b0a5 --- /dev/null +++ b/MasaBlazorApp3/Pojo/AccountBook.cs @@ -0,0 +1,113 @@ +using LinqToDB.Mapping; +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("account_book")] + public class AccountBook + { + /// + /// 主键 + /// + [Column("id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 设备id + /// + [Column("machine_id")] + public string MachineId { get; set; } + /// + /// 药品id + /// + [Column("drug_id")] + public string DrugId { get; set; } + + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo Drug { get; set; } + /// + /// 数量 + /// + [Column("add_quantity")] + public int AddQuantity { get; set; } + [Column("out_quantity")] + public int OutQuantity { get; set; } + + /// + /// 批号 + /// + [Column("manu_no")] + public string ManuNo { get; set; } + /// + /// 操作人id + /// + [Column("operator")] + public int? Operator { get; set; } + + + [Association(ThisKey = nameof(Operator), OtherKey = nameof(User.Id))] + public User OperatorUser { get; set; } + /// + /// 审核人id + /// + [Column("reviewer")] + public int? Reviewer { get; set; } + + + [Association(ThisKey = nameof(Reviewer), OtherKey = nameof(User.Id))] + public User ReviewerUser { get; set; } + /// + /// 操作时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [Column("create_time")] + public DateTime OperationTime { get; set; } + /// + /// 效期 + /// + [Column("eff_date")] + public DateTime? EffDate { get; set; } + /// + /// 出库入库类型(1领入2发出3盘点4日结5日总结6转结) + /// + [Column("type")] + public int Type { get; set; } + /// + /// 出入库调拨单id + /// + [Column("invoice_id")] + public string InvoiceId { get; set; } + /// + /// 列号 + /// + [Column("yesterday_quantity")] + public int YesterdayQuantity { get; set; } + /// + /// 抽屉号 + /// + [Column("manu_stock")] + public int ManuStock { get; set; } + [Column("total_stock")] + public int TotalStock { get; set; } + + /// + /// 取药科室 + /// + [Column("department")] + public string department { get; set; } + /// + /// 退药量 + /// 默认值: 0 + /// + [Column("create_date")] + public string CreateDate { get; set; } + + + } +} diff --git a/MasaBlazorApp3/Pojo/AccountBookG2.cs b/MasaBlazorApp3/Pojo/AccountBookG2.cs new file mode 100644 index 0000000..71059cb --- /dev/null +++ b/MasaBlazorApp3/Pojo/AccountBookG2.cs @@ -0,0 +1,153 @@ +using LinqToDB.Mapping; +namespace MasaBlazorApp3.Pojo +{ + [Table("account_book_g2")] + public class AccountBookG2 + { + /// + /// 主键 + /// + [Column("id", IsPrimaryKey = true)] + public int Id { get; set; } + + /// + /// 药品id + /// + [Column("drug_id")] + public string DrugId { get; set; } + + /// + /// 1领入2发出3日结4总结5转结 + /// + [Column("type")] + public int Type { get; set; } + + /// + /// 科室 + /// + [Column("department")] + public string Department { get; set; } + + /// + /// 设备内记录凭证 + /// + [Column("invoice_no")] + public string InvoiceNo { get; set; } + + /// + /// 处方号或凭证号 + /// + [Column("order_no")] + public string OrderNo { get; set; } + + /// + /// 批次 + /// + [Column("manu_no")] + public string ManuNo { get; set; } + + /// + /// 效期 + /// + [Column("eff_date")] + public string EffDate { get; set; } + + /// + /// 上日结存 + /// + [Column("yesterday_quantity")] + public int YQuantity { get; set; } + + /// + /// 收入 + /// + [Column("add_quantity")] + public int AddQuantity { get; set; } + + /// + /// 发出 + /// + [Column("out_quantity")] + public int OutQuantity { get; set; } + + /// + /// 批次结存 + /// + [Column("manu_stock")] + public int ManuStock { get; set; } + + /// + /// 总结存 + /// + [Column("total_stock")] + public int TotalStock { get; set; } + + + /// + /// 发药领药人id + /// + [Column("user_id1")] + public int? UserId1 { get; set; } + + /// + /// 复核人id + /// + [Column("user_id2")] + public int? UserId2 { get; set; } + + /// + /// 设备id + /// + [Column("machine_id")] + public string MachineId { get; set; } + + /// + /// 日期 + /// + [Column("create_date")] + public string CreateDate { get; set; } + + /// + /// 插入更新时间(当前时间戳) + /// + [Column("create_time")] + public DateTime CreateTime { get; set; } + + /// + /// 药品名称 + /// + [Column(IsColumn = false)] + public string DrugName { get; set; } + + /// + /// 规格 + /// + [Column(IsColumn = false)] + public string DrugSpec { get; set; } + + /// + /// 厂家 + /// + [Column(IsColumn = false)] + public string Manufactory { get; set; } + + /// + /// 发药人 + /// + [Column(IsColumn = false)] + public string OperatorName { get; set; } + + /// + /// 复核人 + /// + [Column(IsColumn = false)] + public string ReviewerName { get; set; } + + /// + /// 手术间 + /// + [Column("shoushuJian")] + public string ShoushuJian { get; set; } + } + +} diff --git a/MasaBlazorApp3/Pojo/Anaesthetist.cs b/MasaBlazorApp3/Pojo/Anaesthetist.cs new file mode 100644 index 0000000..a13fe57 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Anaesthetist.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + public class Anaesthetist + { + public int Id { get; set; } + public string Name { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/BoxModel.cs b/MasaBlazorApp3/Pojo/BoxModel.cs new file mode 100644 index 0000000..9802ed9 --- /dev/null +++ b/MasaBlazorApp3/Pojo/BoxModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + public class BoxModel + { + //库位号 + public int BoxNo { get; set; } + //药箱号 + public int BoxName { get; set; } + public string 药箱号 { + get => BoxName + "-" + BoxNo; + } + } +} diff --git a/MasaBlazorApp3/Pojo/ChannelList.cs b/MasaBlazorApp3/Pojo/ChannelList.cs new file mode 100644 index 0000000..fb172ab --- /dev/null +++ b/MasaBlazorApp3/Pojo/ChannelList.cs @@ -0,0 +1,62 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("channel_list")] + public class ChannelList + { + + [PrimaryKey] + [Column("chnguid")] + public string Id { get; set; } + + + [Column("machine_id")] + public string MachineId { get; set; } + + [Column("row_no")] + public int DrawerNo { get; set; } + + [Column("col_no")] + public int ColNo { get; set; } + + [Column("drug_id")] + public string DrugId { get; set; } + + [Column("chn_type")] + public int DrawerType { get; set; } + + [Column("col_no1")] + public int IsBox { get; set; } + + + [Column("col_no2")] + public int IsWeight { get; set; } + + [Association(ThisKey = nameof(Id), OtherKey = nameof(ChannelStock.ListId))] + public List ChannelStocks { get; set; } = new(); + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo Drug { get; set; } = new(); + + //关联药品中的套餐信息表 + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(Plan.Id))] + public Plan PlanInfo { get; set; } = new(); + //手术室药盒中的库存总数 + [Column("stock_quantity")] + public int TotalQuantity { get; set; } + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(PlanDetails.PlanId))] + public List _PlanDetails { get; set; } = new(); + //手术室药盒中的库存总数 + [Column(IsColumn = false)] + public bool IsChecked{get;set;} = false; + //手术室药盒中的库存总数 + [Column(IsColumn = false)] + public bool BoxDisabled {get;set;} = false; + } +} diff --git a/MasaBlazorApp3/Pojo/ChannelStock.cs b/MasaBlazorApp3/Pojo/ChannelStock.cs new file mode 100644 index 0000000..7418a63 --- /dev/null +++ b/MasaBlazorApp3/Pojo/ChannelStock.cs @@ -0,0 +1,125 @@ +using LinqToDB.Mapping; +using Mysqlx.Crud; + +namespace MasaBlazorApp3.Pojo +{ + [Table("channel_stock")] + public class ChannelStock + { + [PrimaryKey] + [Column("chsguid")] + public string Id { get; set; } + + [Column("chnguid")] + public string ListId { get; set; } + + [Column("machine_id")] + public string MachineId { get; set; } + + [Column("row_no")] + public int DrawerNo { get; set; } + + [Column("col_no")] + public int ColNo { get; set; } + + [Column("drug_id")] + public string DrugId { get; set; } + + [Column("quantity")] + public int Quantity { get; set; } + + [Column(IsColumn =false)] + public int TotalQuantity { get; set; } + + //药盒DrawerType为非1时表示不在库 + [Column("drawer_type")] + public int DrawerType { get; set; } + + /// + /// 1物理隔板;2单支计数;3管控药盒;4储物箱;5智能显示;6称重计数;63称重计数药盒;653称重计数药盒智能显示; + /// + [Column("board_type")] + public int BoardType { get; set; } + + [Column("manu_no")] + public string ManuNo { get; set; } + + [Column("eff_date")] + public string EffDate { get; set; } + + [LinqToDB.Mapping.Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo? Drug { get; set; } + + + [Column(IsColumn = false)] + public int TakeQuantity { get; set; } = 0; + [Column(IsColumn = false)] + public int AddQuantity { get; set; } = 0; + + [Column(IsColumn = false)] + public int ReturnQuantity { get; set; } = 0; + + [Column("dmnguid")] + public string Dmnguid { get; set; } + + [LinqToDB.Mapping.Association(ThisKey = nameof(Dmnguid), OtherKey = nameof(DrugManuNo.Id))] + public DrugManuNo? drugManuNo { get; set; } + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugManuNo.DrugId))] + public List drugManuNoList { get; set; }=new List(); + + [Column(IsColumn = false)] + public string Location + { get => DrawerNo + "-" + ColNo; } + + [Column(IsColumn = false)] + public int CanReturnQuantity { get; set; } + [Column(IsColumn = false)] + public int CheckQuantity + { + get; + set; + } + [Column("Pos_No")] + public int BiaoDingStatus { get; set; } + + //手术室药盒中的药品基数 + [Column("Check_Quantity")] + public int BaseQuantity { get; set; } + //手术室药盒中某药品全部批次的需要加药数 + [Column("col_no2")] + public int NeedQuantity { get; set; } + //手术室药盒中某药品全部批次的已取药待入库数 + [Column("col_no1")] + public int AddToQuantity { get; set; } + //手术室药盒中药品补药状态(1需补药2已补药待入库0满库状态) + [Column("state")] + public int BoxState { get; set; } + [Column("fill_time")] + public DateTime FillTime { get; set; } + //药盒中药品对应的处方信息 + [Column(IsColumn =false)] + public List OrderList { get; set; } + //药盒中药品对应的选中的处方信息 + [Column(IsColumn =false)] + public IList SelectedOrderList { get; set; } + //还空瓶库位 + [Column(IsColumn = false)] + public ChannelStock EmptyStock { get; set; } + //还空瓶数 + [Column(IsColumn = false)] + public int EmptyQuantity { get; set; } = 0; + //用药数 + [Column(IsColumn =false)] + public int UseQuantity { get; set; } + //处方数 + [Column(IsColumn =false)] + public int OrderQuantity { get; set; } + //药盒中未绑套餐的药所在抽屉库位 + [Column(IsColumn =false)] + public List DrawerChanneStockList { get; set; } + //药盒中未绑套餐的药所在抽屉库位 + [Column(IsColumn = false)] + public ChannelStock ReturnDrawerChanneStock { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Config/DrawerConfig.cs b/MasaBlazorApp3/Pojo/Config/DrawerConfig.cs new file mode 100644 index 0000000..2e9e27d --- /dev/null +++ b/MasaBlazorApp3/Pojo/Config/DrawerConfig.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Config +{ + public class DrawerConfig + { + public int[] single { get; set; } + public int[] weigh { get; set; } + public int[] box { get; set; } + public int[] label { get; set; } + public int[] returnDrawer { get; set; } + + } +} diff --git a/MasaBlazorApp3/Pojo/Config/FingerPojo.cs b/MasaBlazorApp3/Pojo/Config/FingerPojo.cs new file mode 100644 index 0000000..5aad883 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Config/FingerPojo.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Config +{ + public class FingerPojo + { + public string ip { get; set; } + public int port { get; set; } + public int type { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Config/PortConfig.cs b/MasaBlazorApp3/Pojo/Config/PortConfig.cs new file mode 100644 index 0000000..f691110 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Config/PortConfig.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Config +{ + public class PortConfig + { + public string drawerPortPath { get; set; } + + public int drawerProtocol { get; set; } + + public string scanCodePortPath { get; set; } + + public string canBusPortPath { get; set; } + + public bool canBusExsit { get; set; } + //抽屉总数量:8个抽屉与16个抽屉对应发单支指令不同,开抽屉指令也不同 + public int totalDrawerCount { get; set; } + + public bool canBusTwoExsit { get; set; } + public string canBusPortPathTwo { get; set; } + public int doorAddr { get; set; } + public int storageBoxAddr { get; set; } + //存在冰箱串口 + public bool fridgePortExist { get; set; } + //冰箱串口号 + public string fridgePortPath { get; set; } + //储物箱串口 + public int StorageCan { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Config/SettingConfig.cs b/MasaBlazorApp3/Pojo/Config/SettingConfig.cs new file mode 100644 index 0000000..a75d231 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Config/SettingConfig.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Config +{ + public class SettingConfig + { + public string machineId { get; set; } + public string storage { get; set; } + //调拨入库时的in_Pharmacy_Id字段值与storage不一致不确定是传错了还是就两个值先加上这个配置 + public string inPharmacyId { get; set; } + public int loginMode { get; set; } + public bool opFirst { get; set; } + //自动退出登录时间,单位秒(0不自动退出) + public int autoOutLog { get; set; } + //手术室药盒的设备id + public string boxMachineId { get; set; } + //手术室名称 + public string roomName { get; set; } + //麻醉医师姓名 + public string anaesthetist_name { get; set; } + public string boxColor { get; set; } + + } +} diff --git a/MasaBlazorApp3/Pojo/Config/fridgeConfig.cs b/MasaBlazorApp3/Pojo/Config/fridgeConfig.cs new file mode 100644 index 0000000..60cc004 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Config/fridgeConfig.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Config +{ + //冰箱配置文件 + public class fridgeConfig + { + public string temperatureRange { get; set; } + public int fridgeState { get; set; } + public int alertState { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/DrugBase.cs b/MasaBlazorApp3/Pojo/DrugBase.cs new file mode 100644 index 0000000..6b8b6b5 --- /dev/null +++ b/MasaBlazorApp3/Pojo/DrugBase.cs @@ -0,0 +1,26 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + /// + /// 药品基数 + /// + [Table("drug_base")] + public class DrugBase + { + [PrimaryKey] + [Column("drugid")] + public string DrugId { get; set; } + + [Column("machine_id")] + public string MachineId { get; set; } + + [Column("baseQuantity")] + public int BaseQuantity { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/DrugInfo.cs b/MasaBlazorApp3/Pojo/DrugInfo.cs new file mode 100644 index 0000000..dea7094 --- /dev/null +++ b/MasaBlazorApp3/Pojo/DrugInfo.cs @@ -0,0 +1,89 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace MasaBlazorApp3.Pojo +{ + [Table("drug_info")] + public class DrugInfo + { + [PrimaryKey] + [Column("drug_id")] + public string DrugId { get; set; } + + [Column("drug_name")] + public string DrugName { get; set;} + + [Column("drug_type")] + public string DrugType { get; set;} + + [Column("drug_spec")] + public string DrugSpec { get; set;} + + + [Column("manufactory")] + public string Manufactory { get; set; } + + [Column("pack_unit")] + public string PackUnit { get; set; } + [Column("py_code")] + public string PyCode { get; set; } + [Column("pack_h")] + public string PackH { get; set; } + //用于标识“手术室患者麻醉药品使用登记本”报表中是否导出该药品 1导出0不导 + //[Column("pack_h")] + //public int ReportType { get; set; } + [Column(IsColumn =false)] + public string DrugNameSpecManufactory + { + get => DrugName + " / " + DrugSpec+ " / " + Manufactory+" / " + PyCode+" / " + DrugId; + } + + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(ChannelStock.DrugId))] + public List Stocks { get; set;} = new List(); + + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugManuNo.DrugId))] + public List Manus { get; set; } = new List(); + + [Column(IsColumn = false)] + public int StockQuantity + { + get { return Stocks.Aggregate(0, (current, next) => current + next.Quantity); } + } + //药盒基数 + [Column(IsColumn = false)] + public int BoxBaseQuantity + { + get { return Stocks.Aggregate(0, (current, next) => current+next.BaseQuantity);} + } + + public override bool Equals(object o) + { + var other = o as DrugInfo; + + return other?.DrugId == DrugId; + } + + public override string ToString() + { + return $"名称: {DrugName},规格:{DrugSpec}"; + } + + [Column(IsColumn = false)] + public string DrugNameSpec + { + get => DrugName + " ; " + DrugSpec + ";"+ Manufactory; + } + + [Column(IsColumn =false)] + public string set_manu_no { get; set; } + [Column(IsColumn =false)] + public string set_eff_Date { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/DrugManuNo.cs b/MasaBlazorApp3/Pojo/DrugManuNo.cs new file mode 100644 index 0000000..7301a0e --- /dev/null +++ b/MasaBlazorApp3/Pojo/DrugManuNo.cs @@ -0,0 +1,42 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("drug_manu_no")] + public class DrugManuNo + { + [Column("dmnguid", IsPrimaryKey = true)] + public string Id { get; set; } + + [Column("drug_id")] + public string DrugId { get; set; } + + + [Column("manu_no")] + public string ManuNo { get; set; } + + + + [Column("manu_date")] + public string ManuDate { get; set; } + + + [Column("eff_date")] + public DateTime? EffDate { get; set; } + + + public override bool Equals(object o) + { + var other = o as DrugManuNo; + + return other?.DrugId == DrugId && other?.ManuNo == ManuNo; + } + [Column(IsColumn =false)] + public int Quantity { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/HkcChangeShifts.cs b/MasaBlazorApp3/Pojo/HkcChangeShifts.cs new file mode 100644 index 0000000..f49a425 --- /dev/null +++ b/MasaBlazorApp3/Pojo/HkcChangeShifts.cs @@ -0,0 +1,45 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + //交接班表 + [Table("hkc_changeshifts")] + public class HkcChangeShifts + { + [Column("Id")] + public int Id { get; set; } + //操作时间 + [Column("optDate")] + public DateTime optDate { get; set; } + //交班操作人 + [Column("FromOperator")] + public string FromOperator { get; set; } + //交班审核人 + [Column("FromRviewer")] + public string FromRviewer { get; set; } + //接班操作人 + [Column("ToOperator")] + public string ToOperator { get; set; } + //接班审核人 + [Column("ToReviewer")] + public string ToReviewer { get; set; } + //接班时间 + [Column("ToDate")] + public DateTime ToDate { get; set; } + //当班状态(0当前值班,1已交班) + [Column("State")] + public string State { get; set; } + //操作状态(0新增,1修改) + [Column("optState")] + public string optState { get; set; } + [Column("machine_id")] + public string MachineId { get; set; } + [Column("Remarks")] + public string Remarks { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/HkcChangeShiftsDrugDetail.cs b/MasaBlazorApp3/Pojo/HkcChangeShiftsDrugDetail.cs new file mode 100644 index 0000000..f6e58e9 --- /dev/null +++ b/MasaBlazorApp3/Pojo/HkcChangeShiftsDrugDetail.cs @@ -0,0 +1,23 @@ +using LinqToDB.Mapping; + +namespace MasaBlazorApp3.Pojo +{ + [Table("hkc_changeshifts_drug")] + public class HkcChangeShiftsDetail + { + [Column("Id")] + public int Id { get; set; } + //交接班ID + [Column("changeshifts_id")] + public int ChangeshiftsId { get; set; } + //药品ID + [Column("drug_id")] + public string DrugId { get; set; } + //实物数 + [Column("RealNumber")] + public int RealNumber { get; set; } + //处方数 + [Column("orderNumber")] + public int OrderNumber { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/InOutInvoice.cs b/MasaBlazorApp3/Pojo/InOutInvoice.cs new file mode 100644 index 0000000..08f731d --- /dev/null +++ b/MasaBlazorApp3/Pojo/InOutInvoice.cs @@ -0,0 +1,146 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("in_out_invoice")] + public class InOutInvoice + { + /// + /// 主键(序号) + /// + [Column("id", IsPrimaryKey = true, IsIdentity =true)] + public int Id { get; set; } + + [Column("in_pharmacy_id")] + public string InPharmacyId { get; set; } + + [Column("out_pharmacy_id")] + public string OutPharmacyId { get; set; } + + /// + /// 库存管理单位(入库单位代码) + /// + [Column("storage")] + public string storage { get; set; } + + /// + /// 单据号 + /// + [Column("invoice_no")] + public string InvoiceNo { get; set; } + + [Column("invoice_date")] + public string InvoiceDate { get; set; } + + /// + /// 药品id + /// + [Column("drug_id")] + public string DrugId { get; set; } + + + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo Drug { get; set; } = new(); + + /// + /// 药品规格 + /// + [Column("drug_spec")] + public string DrugSpec { get; set; } + + /// + /// 计算单位 + /// + [Column("units")] + public string Units { get; set; } + + /// + /// 厂商标识 + /// + [Column("firm_id")] + public string FirmId { get; set; } + + /// + /// 包装规格(反映药品含量及包装信息,如0.25g*30) + /// + [Column("package_spec")] + public string PackageSpec { get; set; } + + /// + /// 数量(以包装单位所计的数量) + /// + [Column("quantity")] + public int quantity { get; set; } + + /// + /// 计量单位,可使用任一级管理上方便的包装 + /// + [Column("package_units")] + public string PackageUnits { get; set; } + + /// + /// 药品批次 + /// + [Column("drug_manu_no")] + public string DrugManuNo { get; set; } + + /// + /// 创建时间(入库日期) + /// + [Column("create_time")] + public DateTime CreateTime { get; set; } + + /// + /// 2调拨出库1.调拨入库 0.调拨 + /// + [Column("type")] + public int Type { get; set; } + + /// + /// 类型描述 + /// + [Column("type_describe")] + public string TypeDescribe { get; set; } + + /// + /// 供货方 + /// + [Column("supplier")] + public string Supplier { get; set; } + + /// + /// 操作人 + /// + [Column("operator")] + public string Operator { get; set; } + + /// + /// 存放库房 + /// + [Column("sub_storage")] + public string SubStorage { get; set; } + + /// + /// 备注 + /// + [Column("memos")] + public string Memos { get; set; } + + [Column("status")] + public int Status { get; set; } + + [Column("drug_eff_date")] + public string EffDate { get; set; } + + + [Column("cancel_flag")] + public int CancelFlag { get; set; } + + } +} diff --git a/MasaBlazorApp3/Pojo/MachineRecord.cs b/MasaBlazorApp3/Pojo/MachineRecord.cs new file mode 100644 index 0000000..6360852 --- /dev/null +++ b/MasaBlazorApp3/Pojo/MachineRecord.cs @@ -0,0 +1,170 @@ +using LinqToDB.Mapping; +using MasaBlazorApp3.Pojo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("dm_machine_record")] + public class MachineRecord + { + /// + /// 主键 + /// + [Column("id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 设备id + /// + [Column("machine_id")] + public string MachineId { get; set; } + /// + /// 药品id + /// + [Column("drug_id")] + public string DrugId { get; set; } + + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo Drug { get; set; } + /// + /// 数量 + /// + [Column("quantity")] + public int Quantity { get; set; } + + /// + /// 批号 + /// + [Column("manu_no")] + public string ManuNo { get; set; } + /// + /// 操作人id + /// + [Column("operator")] + public int? Operator { get; set; } + + + [Association(ThisKey = nameof(Operator), OtherKey = nameof(User.Id))] + public User OperatorUser { get; set; } + /// + /// 审核人id + /// + [Column("reviewer")] + public int? Reviewer { get; set; } + + + [Association(ThisKey = nameof(Reviewer), OtherKey = nameof(User.Id))] + public User ReviewerUser { get; set; } + /// + /// 操作时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [Column("operation_time")] + public DateTime OperationTime { get; set; } + /// + /// 效期 + /// + [Column("eff_date")] + public DateTime? EffDate { get; set; } + /// + /// 出库入库类型(1入库2出库4盘点31还药32还空瓶,21药盒移出移入,69药盒药品替换,) + /// 50添加套餐;51删除套餐;52向套餐中添加药品;53修改套餐中的药品;54删除套餐中的药品;55药盒套餐绑定;56药盒套餐解绑, + /// + [Column("type")] + public int Type { get; set; } + /// + /// 出入库调拨单id + /// + [Column("invoice_id")] + public string InvoiceId { get; set; } + /// + /// 列号 + /// + [Column("col_no")] + public int ColNo { get; set; } + /// + /// 抽屉号 + /// + [Column("drawer_no")] + public int DrawerNo { get; set; } + /// + /// 取药科室 + /// + [Column("department_id")] + public string DepartmentId { get; set; } + /// + /// 是否已经退药(0:没有1:还了部分2:完成) + /// 默认值: 0 + /// + [Column("status")] + public int Status { get; set; } + /// + /// 退药量 + /// 默认值: 0 + /// + [Column("return_quantity1")] + public int ReturnQuantity1 { get; set; } + /// + /// 退空瓶量 + /// 默认值: 0 + /// + [Column("return_quantity2")] + public int ReturnQuantity2 { get; set; } + + + [Column(IsColumn = false)] + public int CurrentReturnQuantity { get; set; } + /// + /// 取药记录id + /// + [Column("get_id")] + public int? GetId { get; set; } + /// + /// 是否已经销毁 + /// 默认值: 0 + /// + [Column("is_destroy")] + public int? IsDestroy { get; set; } + + [Column(IsColumn = false)] + public int CanReturnQuantity + { + get => Quantity - ReturnQuantity1 - ReturnQuantity2; + + } + //是否选中 + [Column(IsColumn = false)] + public bool IsSelected { get; set; } + + [Column(IsColumn =false)] + public string Location + { + get => DrawerNo + "-" + ColNo; + } + public static MachineRecord Build(MachineRecord machineRecord,DrugInfo drug,User user) + { + if(machineRecord!=null) + { + machineRecord.Drug = drug; + machineRecord.OperatorUser = user; + + } + return machineRecord; + } + /// + /// 药盒号 + /// + [Column("Box_Drawer")] + public int? BoxDrawer { get; set; } + /// + /// 药盒号 + /// + [Column("Box_ColNo")] + public int? BoxColNo { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/OrderDetail.cs b/MasaBlazorApp3/Pojo/OrderDetail.cs new file mode 100644 index 0000000..1bfdf5f --- /dev/null +++ b/MasaBlazorApp3/Pojo/OrderDetail.cs @@ -0,0 +1,150 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +namespace MasaBlazorApp3.Pojo +{ + /// + /// + /// + [Table("order_detail")] + public class OrderDetail + { + /// + /// + /// + /// + [PrimaryKey] + [Column("id")] + public int Id { get; set; } + /// + /// + /// 默认值: NULL + /// + //[SugarColumn(ColumnName = "order_id")] + //public int? OrderId { get; set; } + /// + /// + /// + [Column("patient_id")] + public string PatientId { get; set; } + /// + /// + /// + [Column("order_id")] + public string OrderId { get; set; } + /// + /// + /// + [Column("order_no")] + public string OrderNo { get; set; } + /// + /// + /// + [Column("charge_date")] + public DateTime ChargeDate { get; set; } + /// + /// + /// 默认值: NULL + /// + //[SugarColumn(ColumnName = "serial_no")] + //public int? SerialNo { get; set; } + /// + /// + /// + [Column("drug_id")] + public string DrugId { get; set; } + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo Drug { get; set; } = new(); + + /// + /// + /// + [Column("quantity")] + public int Quantity { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("order_unit")] + public string OrderUnit { get; set; } + /// + /// + /// 默认值: 1 + /// + [Column("unit_convercoef")] + public int? UnitConvercoef { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("set_manu_no")] + public string SetManuNo { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("set_eff_date")] + public string SetEffDate { get; set; } + /// + /// + /// 默认值: NULL + /// + //[SugarColumn(ColumnName = "price")] + //public string Price { get; set; } + /// + /// + /// 默认值: NULL + /// + //[SugarColumn(ColumnName = "total_price")] + //public string TotalPrice { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("use_discrip")] + public string UseDiscrip { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("use_frequ")] + public string UseFrequ { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("use_once")] + public string UseOnce { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("use_by")] + public string UseBy { get; set; } + /// + /// + /// 默认值: '0' + /// + [Column("use_self")] + public string UseSelf { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("use_dosage")] + public string UseDosage { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column(IsColumn = false)] + public int? TotalQuantity { get; set; } = null; + + [LinqToDB.Mapping.Association(ThisKey = nameof(SetManuNo), OtherKey = nameof(DrugManuNo.ManuNo))] + public DrugManuNo? drugManuNo { get; set; } + [Column(IsColumn =false)] + public string DrugName { get; set; } + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pojo/OrderFinish.cs b/MasaBlazorApp3/Pojo/OrderFinish.cs new file mode 100644 index 0000000..de8fb09 --- /dev/null +++ b/MasaBlazorApp3/Pojo/OrderFinish.cs @@ -0,0 +1,33 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("hkc_order_finish")] + public class OrderFinish + { + [PrimaryKey] + [Column("id")] + public int Id { get; set; } + + [Column("pharmacy")] + public string Pharmacy { get; set; } + + [Column("patient_id")] + public string PatientId { get; set; } + + [Column("order_no")] + public string OrderNo { get; set; } + + [Column("state")] + public int State { get; set; } + + [Column("operator")] + public string Operator { get; set; } + + } +} diff --git a/MasaBlazorApp3/Pojo/OrderInfo.cs b/MasaBlazorApp3/Pojo/OrderInfo.cs new file mode 100644 index 0000000..fa28876 --- /dev/null +++ b/MasaBlazorApp3/Pojo/OrderInfo.cs @@ -0,0 +1,189 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +namespace MasaBlazorApp3.Pojo +{ + /// + /// + /// + [Table("order_info")] + public class OrderInfo + { + /// + /// + /// + /// + [PrimaryKey, Identity] + [Column("order_id")] + public int OrderId { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("pharmacy")] + public string Pharmacy { get; set; } + /// + /// + /// + [Column("order_no")] + public string OrderNo { get; set; } + /// + /// + /// + [Column("patient_id")] + public string PatientId { get; set; } + /// + /// + /// + [Column("p_name")] + public string PatientName { get; set; } + + /// + /// + /// 默认值: NULL + /// + [Column("sex")] + public string Sex { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("age")] + public string Age { get; set; } + + /// + /// + /// 默认值: NULL + /// + [Column("id_number")] + public string IdNumber { get; set; } + + + /// + /// + /// 默认值: NULL + /// + [Column("invoice_no")] + public string InvoiceNo { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("patient_no")] + public string PatientNo { get; set; } + + /// + /// + /// 默认值: NULL + /// + [Column("doctor_name")] + public string DoctorName { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("order_date")] + public DateTime OrderDate { get; set; } + /// + /// + /// + [Column("charge_date")] + public DateTime ChargeDate { get; set; } = DateTime.Now; + /// + /// + /// 默认值: NULL + /// + [Column("recv_date")] + public DateTime RecvDate { get; set; } + + + /// + /// + /// 默认值: NULL + /// + [Column("dept_name")] + public string DeptName { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("disease")] + public string Disease { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("order_type")] + public string OrderType { get; set; } + /// + /// + /// 默认值: NULL + /// + [Column("charge_type")] + public string ChargeType { get; set; } + /// + /// + /// + [Column("dm_status")] + public int Status { get; set; } + /// + /// + /// 默认值: 0 + /// + [Column("his_disp_flag")] + public int? HisDispFlag { get; set; } + + /// + /// + /// 默认值: 0 + /// + [Column("cancel_flag")] + public int? CancelFlag { get; set; } + + /// + /// + /// 默认值: 0 + /// + [Column("win_no")] + public int WinNo { get; set; } = 0; + /// + /// + /// 默认值: 0 + /// + [Column("state")] + public int state { get; set; } = 0; + + //[Association(ThisKey = nameof(OrderNo), OtherKey = nameof(OrderDetail.OrderNo))] + //public List DetailList { get; set; } = new(); + + + [Association(ThisKey = nameof(OrderNo), OtherKey = nameof(OrderDetail.OrderNo))] + public OrderDetail DetailInfo { get; set; } = new(); + + /// + /// 是否选中 + /// + [Column(IsColumn = false)] + public bool ItemIsChecked { get; set; } = true; + /// + /// 是否全先中 + /// + [Column(IsColumn = false)] + public bool AllItemIsChecked { get; set; } = true; + + /// + /// 麻醉师 + /// + [Column("anaesthetist_name")] + public string anaesthetistName { get; set; } + /// + /// 手术室 + /// + [Column("op_room_name")] + public string RoomName { get; set; } + //药盒中药品对应的选中的处方信息 + [Column(IsColumn = false)] + public IList SelectedOrderList { get; set; } + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Pojo/Plan.cs b/MasaBlazorApp3/Pojo/Plan.cs new file mode 100644 index 0000000..e6d4bc1 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Plan.cs @@ -0,0 +1,40 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("Plan")] + public class Plan + { + //主键 + [Column("Id")] + public int Id { get; set; } + //套餐名 + [Column("Name")] + public string Name { get; set; } + //套餐描述 + [Column("Description")] + public string Description { get; set; } + [Association(ThisKey = nameof(Id), OtherKey = nameof(PlanDetails.PlanId))] + public List _PlanDetails { get; set; } = new(); + //添加时间 + [Column("AddTime")] + public DateTime AddTime { get; set; } + //可用状态:0不可用1可用 + [Column("usestate")] + public int UseState { get; set; } + //操作人 + [Column("operatorUser")] + public int OperatorUser { get; set; } + //审核人 + [Column("reviewerUser")] + public int ReviewerUser { get; set; } + + [Column("machine_id")] + public string MachineId { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/PlanDetails.cs b/MasaBlazorApp3/Pojo/PlanDetails.cs new file mode 100644 index 0000000..7e181c9 --- /dev/null +++ b/MasaBlazorApp3/Pojo/PlanDetails.cs @@ -0,0 +1,45 @@ +using LinqToDB.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + [Table("Plan_Details")] + public class PlanDetails + { + //主键 + [Column("Id")] + public int Id { get; set; } + //套餐外键 + [Column("Plan_Id")] + public int PlanId { get; set; } + //药品基数 + [Column("Base_Quantity")] + public int BaseQuantity { get; set; } + //药品ID + [Column("Drug_Id")] + public string DrugId { get; set; } + + [Association(ThisKey = nameof(DrugId), OtherKey = nameof(DrugInfo.DrugId))] + public DrugInfo _DrugInfo { get; set; } = new(); + //添加时间 + [Column("AddTime")] + public DateTime AddTime { get; set; } + //可用状态:0不可用1可用 + [Column("usestate")] + public int UseState { get; set; } + //操作人 + [Column("operatorUser")] + public string OperatorUser { get; set; } + //审核人 + [Column("reviewerUser")] + public string ReviewerUser { get; set; } + public List channelStocks { get; set; } = new List(); + + public DrugManuNo _ManuNo { get; set; } + + } +} diff --git a/MasaBlazorApp3/Pojo/Premission.cs b/MasaBlazorApp3/Pojo/Premission.cs new file mode 100644 index 0000000..d82c225 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Premission.cs @@ -0,0 +1,323 @@ +using Mysqlx.Crud; + +namespace MasaBlazorApp3.Pojo +{ + [Serializable] + public class Premission + { + + public Premission Parent { get; set; } = null; + + public void AddChild(Premission item) + { + item.Parent = this; + this.Items = this.Items.Concat(new Premission[] { item }); + } + + public int Id { get; set; } + public string PremissionName { get; set; } + /// + /// 菜单路径 + /// + public string PremissionPath { get; set; } + + + public IEnumerable Items { get; set; } = Enumerable.Empty(); + + public List getAdminPremission() + { + var list = new List(); + Premission q = new Premission + { + Id = 1, + PremissionName = "出库", + PremissionPath = "take" + }; + + //q.AddChild(new Premission() + //{ + // Id = 11, + // PremissionName = "处方取药", + // PremissionPath = "/take/order" + //}); + //q.AddChild(new Premission() + //{ + // Id = 12, + // PremissionName = "调拨取药", + // PremissionPath = "/take/invoice" + //}); + q.AddChild(new Premission() + { + Id = 13, + PremissionName = "抽屉取药", + PremissionPath = "/take/drawer" + }); + //q.AddChild(new Premission() + //{ + // Id = 14, + // PremissionName = "自选取药", + // PremissionPath = "/take/self" + //}); + q.AddChild(new Premission() + { + Id = 15, + PremissionName = "取药记录", + PremissionPath = "/take/record/2" + }); + + Premission j = new Premission + { + Id = 2, + PremissionName = "入库", + PremissionPath = "add" + }; + j.AddChild(new Premission() + { + Id = 21, + PremissionName = "调拨入库", + PremissionPath = "/add/invoice" + }); + //j.AddChild(new Premission() + //{ + // Id = 22, + // PremissionName = "请领入库", + // PremissionPath = "/add/apply" + //}); + j.AddChild(new Premission() + { + Id = 23, + PremissionName = "抽屉入库", + PremissionPath = "/add/drawer" + }); + j.AddChild(new Premission() + { + Id = 24, + PremissionName = "入库记录", + PremissionPath = "/add/record/1" + }); + Premission h = new Premission + { + Id = 3, + PremissionName = "归还", + PremissionPath = "return" + }; + + //h.AddChild(new Premission() + //{ + // Id = 31, + // PremissionName = "归还药品(处方)", + // PremissionPath = "/return/order" + //}); + //h.AddChild(new Premission() + //{ + // Id = 32, + // PremissionName = "归还药品(记录)", + // PremissionPath = "/return/byRecord" + //}); + //h.AddChild(new Premission() + //{ + // Id = 33, + // PremissionName = "归还空瓶", + // PremissionPath = "/return/empty" + //}); + h.AddChild(new Premission() + { + Id = 34, + PremissionName = "归还记录(药品)", + PremissionPath = "/return/record1/31" + }); + h.AddChild(new Premission() + { + Id = 35, + PremissionName = "归还记录(空瓶)", + PremissionPath = "/return/record2/32" + }); + + Premission k = new Premission + { + Id = 4, + PremissionName = "库存管理", + PremissionPath = "stock" + }; + k.AddChild(new Premission() + { + Id = 41, + PremissionName = "库存列表", + PremissionPath = "/stock/list" + }); + k.AddChild(new Premission() + { + Id = 42, + PremissionName = "库位绑定", + PremissionPath = "/stock/binding" + }); + k.AddChild(new Premission() + { + Id = 43, + PremissionName = "库存盘点", + //PremissionName = "盘点交接", + PremissionPath = "/stock/check" + }); + k.AddChild(new Premission() + { + Id = 44, + PremissionName = "盘点记录", + //PremissionPath = "/stock/checkRecord" + PremissionPath = "/stock/record/4" + }); + k.AddChild(new Premission() + { + Id = 45, + PremissionName = "药品信息", + PremissionPath = "/stock/drug" + }); + //k.AddChild(new Premission() + //{ + // Id = 46, + // PremissionName = "药品标定", + // PremissionPath = "/stock/biaoDing" + //}); + k.AddChild(new Premission() + { + Id = 47, + PremissionName = "交接班列表", + PremissionPath = "/stock/Change" + }); + Premission x = new Premission + { + Id = 5, + PremissionName = "系统管理", + PremissionPath = "manage" + }; + x.AddChild(new Premission() + { + Id = 51, + PremissionName = "用户管理", + PremissionPath = "/manage/user" + }); + x.AddChild(new Premission() + { + Id = 52, + PremissionName = "权限管理", + PremissionPath = "/manage/role" + }); + Premission set = new Premission() + { + Id = 53, + PremissionName = "系统设置", + PremissionPath = "/manage/setting" + //PremissionPath = "/Box/Plan" + }; + set.AddChild(new Premission() + { + Id = 531, + PremissionName = "登录设置", + PremissionPath = "/manage/setting/login" + + }); + set.AddChild(new Premission() + { + Id = 532, + PremissionName = "冰箱设置", + PremissionPath = "/manage/setting/Fridge" + + }); + //x.AddChild(new Premission() + //{ + // Id = 54, + // PremissionName = "套餐管理", + // PremissionPath = "/Box/Plan" + //}); + //x.AddChild(new Premission() + //{ + // Id = 55, + // PremissionName = "绑定药盒", + // PremissionPath = "/Box/BoxBindings" + //}); + //x.AddChild(new Premission() + //{ + // Id = 56, + // PremissionName = "药盒核对", + // PremissionPath = "/Box/Check" + //}); + //x.AddChild(new Premission() + //{ + // Id = 57, + // PremissionName = "药盒加药", + // PremissionPath = "/Box/BoxAdd" + //}); + //x.AddChild(new Premission() + //{ + // Id = 58, + // PremissionName = "药盒入库", + // PremissionPath = "/Box/BoxAddBox" + //}); + //x.AddChild(new Premission() + //{ + // Id = 59, + // PremissionName = "药盒库存", + // PremissionPath = "/Box/BoxStock" + //}); + + + Premission b = new Premission + { + Id = 6, + PremissionName = "药盒管理", + PremissionPath = "Box" + }; + //b.AddChild(new Premission() + //{ + // Id = 61, + // PremissionName = "套餐管理", + // PremissionPath = "/Box/Plan" + //}); + //b.AddChild(new Premission() + //{ + // Id = 62, + // PremissionName = "绑定药盒", + // PremissionPath = "/Box/BoxBindings" + //}); + //b.AddChild(new Premission() + //{ + // Id = 63, + // PremissionName = "药盒核对", + // //PremissionName = "盘点交接", + // PremissionPath = "/Box/Check" + //}); + b.AddChild(new Premission() + { + Id = 66, + PremissionName = "药盒加药", + //PremissionPath = "/stock/checkRecord" + PremissionPath = "/Box/BoxAdd" + }); + //b.AddChild(new Premission() + //{ + // Id = 65, + // PremissionName = "药盒入库", + // PremissionPath = "/Box/BoxAddBox" + //}); + b.AddChild(new Premission() + { + Id = 66, + PremissionName = "药盒库存", + PremissionPath = "/Box/BoxStock" + }); + list.Add(q); + list.Add(j); + list.Add(h); + list.Add(k); + list.Add(b); + x.AddChild(set); + list.Add(x); + + return list; + } + + public bool HasChild() + { + return this.Items.Count() > 0; + } + } +} diff --git a/MasaBlazorApp3/Pojo/ReportDateInfo.cs b/MasaBlazorApp3/Pojo/ReportDateInfo.cs new file mode 100644 index 0000000..058a5d4 --- /dev/null +++ b/MasaBlazorApp3/Pojo/ReportDateInfo.cs @@ -0,0 +1,160 @@ +using MySqlX.XDevAPI.Relational; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + public class ReportAccountDateInfo + { + //日期 + public string OperationTime { get; set; } = string.Empty; + //操作类型 + //public string Type { get; set; } = string.Empty; + //批号 + public string ManuNo { get; set; } = string.Empty; + //效期 + public string EffDate { get; set; } = string.Empty; + //上次批次结存 + //public string BeforeManuQuan { get; set; } = string.Empty; + //入库数量 + public int InQuantity { get; set; } = 0; + // 出库数量 + public int OutQuantity { get; set; } = 0; + //批号结存 + public int ManuQuantity { get; set; } = 0; + + //总结存 + public int StockQuantity { get; set; } = 0; + + //收/发药人 + public string operatorName { get; set; } = string.Empty; + + //复核人 + public string ReviewerName { get; set; } = string.Empty; + public string DrugId { get; set; } = string.Empty; + //药品名称 + public string DrugName { get; set; } = string.Empty; + //药品规格 + public string DrugSpec { get; set; } = string.Empty; + //单位 + public string BigUnit { get; set; } = string.Empty; + //剂型 + public string Dosage { get; set; } = string.Empty; + //生产厂家 + public string Manufactory { get; set; } = string.Empty; + //凭证号 + public string InvoiceId { get; set; } = string.Empty; + //////供应单位 + //public string SupplierDept { get;set; } = string.Empty; + //////领用部门 + //public string ReceiveDept { get; set; } = string.Empty; + /// + ///供应单位(领用部门) + /// + public string department { get; set; } = string.Empty; + //备注 + public string Remarks { get; set; } = string.Empty; + } + + public class ReportStockDateInfo + { + public string DrugId { get; set; } + + public string DrugName { get; set; } + + public string DrugType { get; set; } + + public string DrugSpec { get; set; } + + + public string Manufactory { get; set; } + + + public string PyCode { get; set; } + //基数 + public int BaseQuantity { get; set; } + + //批次 + public string ManuNo { get; set; } + + //效期 + public string EffDate { get; set; } + //库位 + public string location { get; set; } + + //数量 + public int Quantity { get; set; } + } + //手术室患者麻醉药品使用登记本 + public class ReportUsageParentDateInfo + { + //药品ID + public string drugId1 { get; set; } + //药品名称 + public string drugName1 { get; set; } + //批次 + public string manuNo1 { get; set; } + //数量 + public int quantity1 { get; set; } + //日期 + public DateTime portDate { get; set; } + } + //手术室患者麻醉药品使用登记本 + public class ReportUsageDateInfo + { + //日期 + public DateTime portdate { get; set; } + //手术间 + public int ShouShuJian { get; set; } + //主麻 + public string doctor1 { get; set; } + //副麻 + public string doctor2 { get; set; } + //ID号 + public string patientId { get; set; } + //患者姓名 + public string PName { get; set; } + public string Diagnose { get; set; } + //药品ID + public string DrugId { get; set; } + //药品名称 + public string DrugName { get; set; } + //批次 + public string ManuNo { get; set; } + //使用量 + public string UsageDosage { get; set; } + //残液量 + public string CanYeLiang { get; set; } + //残液处置方式 + public string CanYeChuZhi { get; set; } + //使用人姓名 + public string UseUserName { get; set; } + //核对人姓名 + public string CheckUserName { get; set; } + //数量 + public int quantity { get; set; } + } + //请领报表信息 + public class ReportApplyInfo + { + //手术间 + public int BoxNum { get; set; } + //请领时间 + public DateTime ApplyDate { get; set; } + //麻醉医生 一线 + public string UserFirst { get; set; } + //麻醉医生 二线 + public string UserSecond { get; set; } + //药品ID + public string DrugId { get; set; } + //医生签名 + public string Doctor { get; set; } + //管理者签名 + public string Manager { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/ReturnChannelStock.cs b/MasaBlazorApp3/Pojo/ReturnChannelStock.cs new file mode 100644 index 0000000..446798d --- /dev/null +++ b/MasaBlazorApp3/Pojo/ReturnChannelStock.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo +{ + public class ReturnChannelStock + { + + } +} diff --git a/MasaBlazorApp3/Pojo/Role.cs b/MasaBlazorApp3/Pojo/Role.cs new file mode 100644 index 0000000..222e222 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Role.cs @@ -0,0 +1,50 @@ +using LinqToDB.Mapping; + +namespace MasaBlazorApp3.Pojo +{ + [Table("role")] + public class Role + { + + [PrimaryKey, Identity] + [Column("id")] + public int Id { get; set; } + [Column("role_name")] + public string RoleName { get; set; } + //[Column("role_des")] + //public string Description { get; set; } + [Column("machine_id")] + public string MachineId { get; set; } + + [Column("permissions")] + public string permissions { get; set; } + + [Column(IsColumn = false)] + public List permissionList { + get + { + + return null; + } + } + + [Column(IsColumn = false)] + public IEnumerable permissionIds + { + get + { + return !String.IsNullOrEmpty(permissions) ? permissions.Split(",").Select(s => Convert.ToInt32(s)): Enumerable.Empty(); + } + set + { + if (value == null) + { + permissions = ""; + } else + { + permissions = string.Join(",", value); + } + } + } + } +} diff --git a/MasaBlazorApp3/Pojo/SettingManu.cs b/MasaBlazorApp3/Pojo/SettingManu.cs new file mode 100644 index 0000000..9d82125 --- /dev/null +++ b/MasaBlazorApp3/Pojo/SettingManu.cs @@ -0,0 +1,24 @@ +using LinqToDB.Mapping; + +namespace MasaBlazorApp3.Pojo +{ + //系统设置中的菜单 + [Table("SettingManu")] + public class SettingManu + { + [PrimaryKey, Identity] + [Column("id")] + public int Id { get; set; } + [Column("Manu_Name")] + public string Name { get; set; } + [Column("Manu_Icon")] + public string Icon { get; set; } + [Column("Path")] + public string Path { get; set; } + //使用状态1在用;0不在用 + [Column("UseStatus")] + public int UseStatus { get; set; } + [Column(IsColumn = false)] + public List Children { get; set; } = new(); + } +} diff --git a/MasaBlazorApp3/Pojo/User.cs b/MasaBlazorApp3/Pojo/User.cs new file mode 100644 index 0000000..3ca4e2b --- /dev/null +++ b/MasaBlazorApp3/Pojo/User.cs @@ -0,0 +1,42 @@ + + +using LinqToDB.Mapping; + +namespace MasaBlazorApp3.Pojo +{ + [Table("user_list")] + public class User + { + [Column("id")] + [PrimaryKey, Identity] + public int Id { get; set; } + [Column("user_id")] + public string Username { get; set; } + + [Column("pass_word")] + public string Password { get; set; } + + + [Column("user_name")] + public string NickName { get; set; } + + + [Column("machine_id")] + public string MachineId { get; set; } + + + [Column("sign")] + public byte[] Sign { get; set; } + + + [Column("machine_role_id")] + public int RoleId { get; set; } + + + [Association(ThisKey = nameof(RoleId), OtherKey = nameof(Role.Id))] + public Role role { get; set; } + + [Column(IsColumn =false)] + public string OldPassword { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Vo/BoxTakeVo.cs b/MasaBlazorApp3/Pojo/Vo/BoxTakeVo.cs new file mode 100644 index 0000000..48570d8 --- /dev/null +++ b/MasaBlazorApp3/Pojo/Vo/BoxTakeVo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Vo +{ + public class BoxTakeVo + { + public DrugInfo Drug { get; set; } + + public ChannelStock BoxDetail { get; set; } + + public ChannelStock ChannelStock { get; set; } + + public int StockQuantity { get; set; } + + public int Quantity { get; set; } + + public int GetQuantity { get; set; } = 0; + + public int Status { get; set; } = 0; + + public int[] BeforeQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int[] AfterQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int AddQuantity { get; set; } = 0; + + } +} diff --git a/MasaBlazorApp3/Pojo/Vo/InvoiceVo.cs b/MasaBlazorApp3/Pojo/Vo/InvoiceVo.cs new file mode 100644 index 0000000..b46667b --- /dev/null +++ b/MasaBlazorApp3/Pojo/Vo/InvoiceVo.cs @@ -0,0 +1,34 @@ +using Radzen.Blazor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Vo +{ + public class InvoiceVo + { + public DrugInfo Drug { get; set; } + + public InOutInvoice Invoice { get; set; } + + public List ChannelStocks { get; set; } + + public int StockQuantity { get; set; } + + public int Quantity { get; set; } + + public int GetQuantity { get; set; } = 0; + + public int Status { get; set; } = 0; + + public int[] BeforeQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int[] AfterQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int AddQuantity { get; set; } = 0; + + public RadzenDataGrid Grid { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Vo/OperationVo.cs b/MasaBlazorApp3/Pojo/Vo/OperationVo.cs new file mode 100644 index 0000000..4b4dcce --- /dev/null +++ b/MasaBlazorApp3/Pojo/Vo/OperationVo.cs @@ -0,0 +1,37 @@ +using Radzen.Blazor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Vo +{ + public class OperationVo + { + public DrugInfo Drug { get; set; } + + public T data { get; set; } + + public List ChannelStocks { get; set; } + + public int StockQuantity { get; set; } + + public int Quantity { get; set; } + + public int GetQuantity { get; set; } = 0; + + public int Status { get; set; } = 0; + + public int[] BeforeQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int[] AfterQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int AddQuantity { get; set; } = 0; + + + public int ReturnQuantity { get; set; } = 0; + + public RadzenDataGrid Grid { get; set; } + } +} diff --git a/MasaBlazorApp3/Pojo/Vo/OrderTakeVo.cs b/MasaBlazorApp3/Pojo/Vo/OrderTakeVo.cs new file mode 100644 index 0000000..570f9fa --- /dev/null +++ b/MasaBlazorApp3/Pojo/Vo/OrderTakeVo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Pojo.Vo +{ + public class OrderTakeVo + { + public DrugInfo Drug { get; set; } + + public OrderDetail OrderDetail { get; set; } + + public ChannelStock ChannelStock { get; set; } + + public int StockQuantity { get; set; } + + public int Quantity { get; set;} + + public int GetQuantity { get; set; } = 0; + + public int Status { get; set; } = 0; + + public int[] BeforeQuantity { get; set; } = new int[] { 0,0,0,0,0,0,0,0,0 }; + + public int[] AfterQuantity { get; set; } = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + public int AddQuantity { get; set; } = 0; + + } +} diff --git a/MasaBlazorApp3/Port/PortUtil.cs b/MasaBlazorApp3/Port/PortUtil.cs new file mode 100644 index 0000000..08ef4f6 --- /dev/null +++ b/MasaBlazorApp3/Port/PortUtil.cs @@ -0,0 +1,1564 @@ +using log4net; +using log4net.Repository.Hierarchy; +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Configuration; +using System.IO.Ports; +using System.Linq; +using System.Reflection.Metadata; +using System.Speech.Synthesis; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; +using System.Timers; +using System.Windows; +using System.Windows.Markup; +using System.Reflection; +using MasaBlazorApp3.Pojo.Config; +using Microsoft.Extensions.Options; +using LinqToDB.Common; +using MasaBlazorApp3.Util; +using Microsoft.Extensions.Logging; + +namespace MasaBlazorApp3.Port +{ + public class PortUtil + { + private readonly ILog logger = LogManager.GetLogger(typeof(PortUtil)); + // 抽屉串口 + public SerialPort drawerSerial; + // can总线串口 + public SerialPort canBusSerial; + // can总线串口 + public SerialPort canBusSerialTwo; + + // 条码枪串口 + public SerialPort scanCodeSerial; + + //冰箱串口 + public SerialPort fridgeSerial; + + + public bool Operate { get; set; } + public DateTime dateTime { get; set; } = DateTime.Now; + //鼠标点击时间 + public DateTime mouseClickTime { get; set; } + + // 当前操作的抽屉号 + public int DrawerNo { get; set; } + // 当前操作的库位号列表 + public int[] ColNos { get; set; } = new int[] { }; + // 当前操作查数的库位号列表 + public List ColNoLst { get; set; } = new List(); + // 当前操作开药盒的库位号 + public int OpenBoxColNo { get; set; } = 0; + + private readonly PortConfig _portConfig; + + public PortUtil(IOptions setting) + { + _portConfig = setting.Value; + try + { + string DrawerPortPath = _portConfig.drawerPortPath; + logger.Info($"打开抽屉串口【{DrawerPortPath}】"); + drawerSerial = new SerialPort(DrawerPortPath, 9600, Parity.None, 8); + //drawerSerial.Open(); + //logger.Info($"抽屉串口打开结果【{drawerSerial.IsOpen}】"); + } + catch (Exception e) + { + logger.Error("抽屉串口打开错误" + e.Message); + } + + try + { + string ScanCodePortPath = _portConfig.scanCodePortPath; + logger.Info($"打开条码枪串口【{ScanCodePortPath}】"); + scanCodeSerial = new SerialPort(ScanCodePortPath, 9600, Parity.None, 8); + scanCodeSerial.DataReceived += (object sender, System.IO.Ports.SerialDataReceivedEventArgs e) => + { + string code = scanCodeSerial.ReadExisting(); + + }; + //scanCodeSerial.Open(); + //logger.Info($"条码枪串口打开结果【{scanCodeSerial.IsOpen}】"); + } + catch (Exception e) + { + logger.Error("条码枪串口打开错误" + e.Message); + } + if (_portConfig.canBusExsit) + { + try + { + string CanBusPortPath = _portConfig.canBusPortPath; + logger.Info($"打开can总线串口【{CanBusPortPath}】"); + canBusSerial = new SerialPort(CanBusPortPath, 57600, Parity.None, 8); + //canBusSerial.Open(); + //logger.Info($"can总线串口打开结果【{canBusSerial.IsOpen}】"); + } + catch (Exception e) + { + logger.Error("can总线串口打开错误" + e.Message); + } + + } + //打开第二个can总线串口 + if (_portConfig.canBusTwoExsit) + { + try + { + string CanBusPortPath = _portConfig.canBusPortPathTwo; + logger.Info($"打开第二个can总线串口【{CanBusPortPath}】"); + canBusSerialTwo = new SerialPort(CanBusPortPath, 57600, Parity.None, 8); + } + catch (Exception e) + { + logger.Error("第二个can总线串口打开错误" + e.Message); + } + + } + if (_portConfig.fridgePortExist) + { + try + { + string FridgePortPath = _portConfig.fridgePortPath; + logger.Info($"打开冰箱串口【{FridgePortPath}】"); + fridgeSerial = new SerialPort(FridgePortPath, 9600, Parity.None, 8); + //fridgeSerial.Open(); + //logger.Info($"冰箱串口打开结果【{fridgeSerial.IsOpen}】"); + } + catch (Exception e) + { + logger.Error("冰箱串口打开错误" + e.Message); + } + } + } + + + private byte[] GetBufferByPort(SerialPort serialPort, int length, int timeout) + { + int _length = 0; + DateTime start = DateTime.Now; + DateTime end = DateTime.Now; + while (_length != length && end.Subtract(start).TotalMilliseconds < timeout) + { + _length = serialPort.BytesToRead; + end = DateTime.Now; + //logger.Error($"_length:{_length};length:{length}"); + } + if (_length != length) + { + throw new TimeoutException($"串口【{serialPort.PortName}】交互超时"); + } + byte[] buffer = new byte[length]; + serialPort.Read(buffer, 0, length); + return buffer; + } + private Task GetBufferByPort(SerialPort serialPort, int length) + { + + return Task.Run(() => GetBufferByPort(serialPort, length, 3000)); + } + + + public static SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer(); + public void SpeakAsync(string textinfo) + { + speechSynthesizer.SpeakAsync(textinfo); + } + + + + #region 抽屉串口操作 + // 打开抽屉 + public async Task OpenDrawer(int DrawerNo) + { + drawerSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x41, (byte)DrawerNo, 0xee }; + if (_portConfig.drawerProtocol == 485) + { + if (_portConfig.totalDrawerCount > 8) + { + if (DrawerNo % 2 == 0) + { + buffer = new byte[] { 0xaa, 0x21, (byte)(DrawerNo / 2), 0xee }; + } + else + { + buffer = new byte[] { 0xaa, 0x11, (byte)(DrawerNo / 2 + DrawerNo % 2), 0xee }; + } + } + else + { + buffer = new byte[] { 0xaa, 0x11, (byte)DrawerNo, 0xee }; + } + + } + logger.Info($"打开抽屉,串口数据:{Convert.ToHexString(buffer)}"); + drawerSerial.Write(buffer, 0, 4); + + return await GetBufferByPort(drawerSerial, 11); + } + + public async Task OpenDrawerStatus(int DrawerNo) + { + byte[] buffer = await OpenDrawer(DrawerNo); + int[] r = buffer.Select(it => Convert.ToInt32(it)).ToArray(); + //int index = DrawerNo > 8 ? DrawerNo - 7 : DrawerNo + 1; + //int index = DrawerNo % 2 > 0 ? ((DrawerNo + 1) / 2) + 1 : (DrawerNo / 2) + 1; + int index = 1; + if (_portConfig.totalDrawerCount > 8) + { + index = DrawerNo % 2 > 0 ? ((DrawerNo + 1) / 2) + 1 : (DrawerNo / 2) + 1; + } + else + { + index = DrawerNo > 8 ? DrawerNo - 7 : DrawerNo + 1; + } + return r[index] == 0; + + } + + + // 查询抽屉状态 + public async Task CheckDrawerStatus(int DrawerNo) + { + drawerSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x42, 0xee }; + if (_portConfig.drawerProtocol == 485) + { + if (_portConfig.totalDrawerCount > 8) + { + //if (DrawerNo > 8) + //{ + if (DrawerNo % 2 == 0) + { + buffer = new byte[] { 0xaa, 0x22, 0xee }; + } + else + { + buffer = new byte[] { 0xaa, 0x12, 0xee }; + } + //} + //else + //{ + // buffer = new byte[] { 0xaa, 0x12, 0xee }; + //} + } + else + { + buffer = new byte[] { 0xaa, 0x12, 0xee }; + } + } + + logger.Info($"查询抽屉状态,串口数据:{Convert.ToHexString(buffer)}"); + drawerSerial.Write(buffer, 0, 3); + + return await GetBufferByPort(drawerSerial, 11); + } + + public async Task CheckDrawerStatus2(int DrawerNo) + { + byte[] buffer = await CheckDrawerStatus(DrawerNo); + logger.Info($"查询抽屉状态,返回:{Convert.ToHexString(buffer)}"); + int[] r = buffer.Select(it => Convert.ToInt32(it)).ToArray(); + //int index = DrawerNo > 8 ? DrawerNo - 7 : DrawerNo + 1; + int index = 1; + if (_portConfig.totalDrawerCount > 8) + { + index = DrawerNo % 2 > 0 ? ((DrawerNo + 1) / 2) + 1 : (DrawerNo / 2) + 1; + } + else + { + index = DrawerNo > 8 ? DrawerNo - 7 : DrawerNo + 1; + } + return r[index] != 0; + + } + #endregion + + #region can总线串口操作 + #region 耗材板操作 + // 后门状态 + public async Task BackDoorState() + { + + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.doorAddr), 0x02, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + + } + // 打开电控门储物箱(有灯使能) + public async Task OpenStorage() + { + if (_portConfig.StorageCan == 2) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.doorAddr), 0x01, (byte)_portConfig.storageBoxAddr, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + return await GetBufferByPort(canBusSerial, 8); + } + else + { + canBusSerialTwo.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.doorAddr), 0x01, (byte)_portConfig.storageBoxAddr, 0x00, 0x00, 0x00, 0xee }; + canBusSerialTwo.Write(buffer, 0, 8); + return await GetBufferByPort(canBusSerialTwo, 8); + } + + + } + // 关闭电控门储物箱(有灯失能) + public void CloseStorage() + { + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.doorAddr), 0x04, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 打开普通储物箱(无灯) + public void OpenStorageBox() + { + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.storageBoxAddr), 0x03, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 关闭普通储物箱(无灯) + public void CloseStorageBox() + { + byte[] buffer = new byte[] { 0xaa, (byte)(_portConfig.storageBoxAddr), 0x04, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + + private int[] CheckStorageStatus(int[] data) + { + int a = data[0]; + int b = data[1]; + int[] intA = Decimal2Chunks(a); + int[] intB = Decimal2Chunks(b); + int[] r = new int[intA.Length + intB.Length]; + Array.Copy(intA, 0, r, 0, intA.Length); + Array.Copy(intB, 0, r, intA.Length, intB.Length); + return r; + } + private int[] Decimal2Chunks(int d) + { + string s = Convert.ToString(d, 2); + List t = s.Split().Select(it => Convert.ToInt32(it)).Reverse().ToList(); + while (t.Count < 8) + { + t.Add(0); + } + return t.ToArray(); + } + + #endregion + + #region 单支操作 + // 以抽屉为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByDrawer(int DrawerNo) + { + SerialPort serialCanPort = canBusSerial; + int channel = DrawerNo; + if (_portConfig.totalDrawerCount > 8) + { + if (DrawerNo % 2 == 0) + { + channel = DrawerNo / 2; + } + else + { + serialCanPort = canBusSerialTwo; + channel = (DrawerNo + 1) / 2; + } + } + + + serialCanPort.DiscardInBuffer(); + + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + channel), 0x01, 0x00, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"单支板发送库位数量查询【{string.Join(",", buffer)}】,调用串口{serialCanPort.PortName}"); + serialCanPort.Write(buffer, 0, 8); + + return await GetBufferByPort(serialCanPort, 13); + } + // 获取单个单支板药品数量 + public async Task CheckQuantityByCol(int DrawerNo, int colNo) + { + canBusSerial.DiscardInBuffer(); + + var channel = Convert.ToInt32((DrawerNo * 10 + colNo).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x08, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + + } + // 以抽屉为单位有药位置亮灯 + public void HasLightOnByDrawer(int DrawerNo) + { + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x02, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 以抽屉为单位无药位置亮灯 + public void NoLightOnByDrawer(int DrawerNo) + { + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x03, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 以抽屉为单位灭灯 + public void LightOffByDrawer(int DrawerNo) + { + SerialPort serialPort = canBusSerial; + //int channelDrawerNo = DrawerNo; + //if (_portConfig.totalDrawerCount > 8) + //{ + // if (DrawerNo % 2 == 0) + // { + // channelDrawerNo = DrawerNo / 2; + // } + // else + // { + // serialPort = canBusSerialTwo; + // channelDrawerNo = (DrawerNo + 1) / 2; + // } + //} + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x06, 0x00, 0x00, 0x00, 0x00, 0xee }; + serialPort.Write(buffer, 0, 8); + } + // 以单支板为单位有药位置亮灯 + public async Task HasLightOnByCol(int DrawerNo, int[] ColNos) + { + SerialPort serialPort = canBusSerial; + int channelDrawerNo = DrawerNo; + if (_portConfig.totalDrawerCount > 8) + { + if (DrawerNo % 2 == 0) + { + channelDrawerNo = DrawerNo / 2; + } + else + { + serialPort = canBusSerialTwo; + channelDrawerNo = (DrawerNo + 1) / 2; + } + } + for (int i = 0; i < ColNos.Length; i++) + { + + var channel = Convert.ToInt32((channelDrawerNo * 10 + ColNos[i]).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xee }; + serialPort.Write(buffer, 0, 8); + logger.Info($"{serialPort}串口{DrawerNo}号{channelDrawerNo}抽屉{string.Join(',',ColNos)}库位有药位置亮灯发送指令:{Convert.ToHexString(buffer)}"); + await Task.Delay(TimeSpan.FromMilliseconds(20)); + } + + } + // 以单支板为单位无药位置亮灯 + public async Task NoLightOnByCol(int DrawerNo, int[] ColNos) + { + SerialPort serialPort = canBusSerial; + int channelDrawerNo = DrawerNo; + if (_portConfig.totalDrawerCount > 8) + { + if (DrawerNo % 2 == 0) + { + channelDrawerNo = DrawerNo / 2; + } + else + { + serialPort = canBusSerialTwo; + channelDrawerNo = (DrawerNo + 1) / 2; + } + } + for (int i = 0; i < ColNos.Length; i++) + { + var channel = Convert.ToInt32((channelDrawerNo * 10 + ColNos[i]).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(TimeSpan.FromMilliseconds(20)); + } + } + // 广播灭灯 + public void AllLightOff() + { + byte[] buffer = new byte[] { 0xaa, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + canBusSerialTwo.Write(buffer, 0, 8); + } + //单支板通电 + public void PowerOn() + { + if (_portConfig.StorageCan == 2) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x01, 0x05, 0x07, 0x01, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + else + { + canBusSerialTwo.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x01, 0x05, 0x07, 0x01, 0x00, 0x00, 0xee }; + canBusSerialTwo.Write(buffer, 0, 8); + } + } + //单支板断电 + public void PowerOff() + { + if (_portConfig.StorageCan == 2) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x01, 0x05, 0x07, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + else + { + canBusSerialTwo.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, 0x01, 0x05, 0x07, 0x00, 0x00, 0x00, 0xee }; + canBusSerialTwo.Write(buffer, 0, 8); + } + + } + #endregion + + #region 药盒操作 + // 指定药盒指示灯开启使能开锁 + public async Task BoxLockLightOn(int DrawerNo, int[] ColNos) + { + for (int i = 0; i < ColNos.Length; i++) + { + + var channel = Convert.ToInt32((DrawerNo * 10 + ColNos[i]).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x03, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(TimeSpan.FromMilliseconds(20)); + } + } + // 指定药盒指示灯开启失能开锁 + public async Task BoxLockLightOff(int DrawerNo, int[] ColNos) + { + for (int i = 0; i < ColNos.Length; i++) + { + var channel = Convert.ToInt32((DrawerNo * 10 + ColNos[i]).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x04, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(TimeSpan.FromMilliseconds(20)); + } + } + // 指定药盒状态查询 + public async Task BoxLockState(int DrawerNo, int ColNo) + { + canBusSerial.DiscardInBuffer(); + var channel = Convert.ToInt32((DrawerNo * 10 + ColNo).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x02, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + + } + // 以抽屉为单位药盒指示灯开启使能开锁 + public async Task BoxLockLightOnByDrawer(int DrawerNo) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x04, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 以抽屉为单位药盒指示灯开启失能开锁 + public async Task BoxLockLightOffByDrawer(int DrawerNo) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x05, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + + /// + /// 开指定库位的药盒 + /// + /// + /// + public async Task OpenBoxByColNo(int colNo) + { + if (colNo > 0) + { + canBusSerial.DiscardInBuffer(); + int ColNo = colNo; + int[] iNum = new int[] { 4, 2, 1 }; + var colNo2 = ColNo % 3 > 0 ? (ColNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)ColNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 5, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + //byte[] buffer = new byte[] { 0xaa, 0x11, 0x05,0x01, 0x00,0x00,0x00,0xee}; + logger.Info($"开药盒{DrawerNo}-{ColNo}【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] retBuffer = await GetBufferByPort(canBusSerial, 8); + logger.Info($"开药盒返回{ColNo}【{Convert.ToHexString(retBuffer)}】"); + int[] r = retBuffer.Select(it => Convert.ToInt32(it)).ToArray(); + if (r[4] > 0) + { + return true; + } + else + { + return false; + } + } + return false; + } + /// + /// 打开药盒 + /// + /// + /// + public async Task OpenBox() + { + for (int i = 0; i < ColNos.Length; i++) + { + canBusSerial.DiscardInBuffer(); + int ColNo = ColNos[i]; + int[] iNum = new int[] { 4, 2, 1 }; + var colNo2 = ColNo % 3 > 0 ? (ColNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)ColNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 5, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + //byte[] buffer = new byte[] { 0xaa, 0x11, 0x05,0x01, 0x00,0x00,0x00,0xee}; + logger.Info($"{Convert.ToHexString(buffer)}"); + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(800); + } + + } + // 以抽屉为单位药盒指示灯开启使能开锁 + public async Task BoxLockLightOnByDrawer() + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x04, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 以抽屉为单位药盒指示灯开启失能开锁 + public async Task BoxLockLightOffByDrawer() + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xaa, (byte)(0xf0 + DrawerNo), 0x05, 0x00, 0x00, 0x00, 0x00, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + + + + #endregion + + private string trim(string text) + { + //此处使用了转义字符如:\',\",\\,分别表示单引号,双引号,反斜杠 + char[] TrimChar = { ' ', '-', '\'', '\"', '\\', '(', ')', '(', ')', '①', '②' }; + return text.Trim(TrimChar); + } + + #region 2.4寸汉显屏 + // 基础数据写入方法 + public async void WriteChannelInfo(int type, string content, int drawerNo, int colNo) + { + + canBusSerial.DiscardInBuffer(); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + byte[] contentBuf = Encoding.GetEncoding("gb2312").GetBytes(trim(content)); + int channel = (drawerNo * 10 + colNo); + if (contentBuf.Length % 2 != 0) + { + Array.Resize(ref contentBuf, contentBuf.Length + 1); + } + byte[] buffer = new byte[] { 0xaa, (byte)channel, 1, (byte)type, 0, 0, 0, 0xee }; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(20); + buffer[4] = 1; + for (int i = 0; i < contentBuf.Length; i += 2) + { + buffer[5] = contentBuf[i]; + buffer[6] = contentBuf[i + 1]; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(20); + } + buffer[4] = 2; + buffer[5] = 0; + buffer[6] = 0; + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(20); + } + + // 清除显示内容 + public void ClearContent(int drawerNo, int colNo) + { + canBusSerial.DiscardInBuffer(); + int channel = (drawerNo * 10 + colNo); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 4, 0, 0, 0, 0, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 刷新显示内容 + public void ShowContent(int drawerNo, int colNo) + { + canBusSerial.DiscardInBuffer(); + int channel = (drawerNo * 10 + colNo); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 2, 0, 0, 0, 0, 0xee }; + canBusSerial.Write(buffer, 0, 8); + } + // 取药或者加药亮灯 + public void TakeQuantity(int drawerNo, int colNo, int quantity, int stock) + { + canBusSerial.DiscardInBuffer(); + int channel = (drawerNo * 10 + colNo); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 6, 0, 0, 0, 0, 0xee }; + buffer[3] = (byte)(quantity >> 8); + buffer[4] = (byte)(quantity & 0xff); + buffer[5] = (byte)(stock >> 8); + buffer[6] = (byte)(stock & 0xff); + canBusSerial.Write(buffer, 0, 8); + } + // 写入数量 + public void WriteQuantity(int drawerNo, int colNo, int quantity) + { + canBusSerial.DiscardInBuffer(); + int channel = (drawerNo * 10 + colNo); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x21, 0, 0, 0, 0, 0xee }; + buffer[5] = (byte)(quantity >> 8); + buffer[6] = (byte)(quantity & 0xff); + canBusSerial.Write(buffer, 0, 8); + } + + //清屏 + public void ClearContentMethod(int drawerNo, int colNo) + { + decimal deColNo = colNo; + //var channel = drawerNo * 10 + Math.Ceiling(deColNo / 3); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = Convert.ToInt32((iNum[colNo2] + 10).ToString(), 16); + //var index = Convert.ToInt32(((colNo % 3 == 0 ? 3 : colNo % 3)+10).ToString(),16); + int channel = Convert.ToInt32((drawerNo * 10 + Math.Ceiling((decimal)colNo / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x09, (byte)bColNo, 0, 0, 0, 0xee }; + canBusSerial.Write(buffer, 0, 8); + logger.Info($"清屏指令:{Convert.ToHexString(buffer)}"); + } + //刷新内容 + public async Task ShowContentMethod(int drawerNo, int colNo) + { + int channel = Convert.ToInt32((drawerNo * 10 + Math.Ceiling((decimal)colNo / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)channel, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"刷新内容指令:{Convert.ToHexString(buffer)}"); + canBusSerial.Write(buffer, 0, 8); + } + // 基础数据写入方法 + public async Task WriteChannelInfoMethod(int type, string content, int drawerNo, int colNo) + { + try + { + canBusSerial.DiscardInBuffer(); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + if (content.Length > 10) + { + content = content.Substring(0, 10); + } + byte[] contentBuf = Encoding.GetEncoding("gb2312").GetBytes(trim(content)); + int channel = Convert.ToInt32((drawerNo * 10 + Math.Ceiling((decimal)colNo / 3)).ToString(), 16); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2] + 160; + //var index = (colNo % 3 == 0 ? 3 : colNo % 3)+160; + if (contentBuf.Length % 2 != 0) + { + Array.Resize(ref contentBuf, contentBuf.Length + 1); + } + byte[] buffer = new byte[] { 0xaa, (byte)channel, (byte)bColNo, (byte)type, 0, 0, 0, 0xee }; + + + canBusSerial.Write(buffer, 0, 8); + logger.Info($"开始写标签指令:{Convert.ToHexString(buffer)}"); + Thread.Sleep(20); + buffer[4] = 1; + for (int i = 0; i < contentBuf.Length; i += 2) + { + buffer[5] = contentBuf[i]; + buffer[6] = contentBuf[i + 1]; + canBusSerial.Write(buffer, 0, 8); + logger.Info($"写标签指令:{Convert.ToHexString(buffer)}"); + Thread.Sleep(50); + } + buffer[4] = 2; + buffer[5] = 0; + buffer[6] = 0; + canBusSerial.Write(buffer, 0, 8); + logger.Info($"结束写标签指令:{Convert.ToHexString(buffer)}"); + Thread.Sleep(20); + + } + catch (Exception ex) + { + logger.Info($"2.4寸汉显屏异常:ex:{ex.Message}"); + } + } + + public async Task WriteQuantityMethod(int quantity, int drawerNo, int colNo) + { + try + { + logger.Info($"写数量:{drawerNo}-{colNo}:{quantity}"); + canBusSerial.DiscardInBuffer(); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + string strQuantity = quantity.ToString("X"); + if (strQuantity.Length % 2 != 0) + { + strQuantity = "0" + strQuantity; + } + int channel = Convert.ToInt32((drawerNo * 10 + Math.Ceiling((decimal)colNo / 3)).ToString(), 16); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2] + 160; + byte[] buffer = new byte[] { 0xaa, (byte)channel, (byte)bColNo, 0xf2, 01, 0, 0, 0xee }; + if (strQuantity.Length >= 4) + { + buffer[5] = Convert.ToByte(strQuantity.Substring(0, 2), 16); + buffer[6] = Convert.ToByte(strQuantity.Substring(2, 2), 16); + } + else + { + + buffer[6] = Convert.ToByte(strQuantity.Substring(0, 2), 16); + } + canBusSerial.Write(buffer, 0, 8); + logger.Info($"写标签指令:{Convert.ToHexString(buffer)}"); + } + catch (Exception ex) + { + logger.Info($"写标签数量异常:ex:{ex.Message}"); + } + } + + #endregion + + #region 回收箱操作 + // 打开回收箱 + public async Task OpenRecover() + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xAA, 0x9A, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEE }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + } + // 回收箱状态查询 + public async Task CheckRecoverStatus() + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xAA, 0x9A, 0x03, 0x00, 0x00, 0x00, 0x00, 0xEE }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + } + // 回收箱回收数量查询 + public async Task CheckRecoverQuantity(int ColNo) + { + canBusSerial.DiscardInBuffer(); + byte[] buffer = new byte[] { 0xAA, 0x9A, (byte)(ColNo > 3 ? 2 : 1), 0x00, 0x00, 0x00, 0x00, 0xEE }; + canBusSerial.Write(buffer, 0, 8); + + return await GetBufferByPort(canBusSerial, 8); + } + #endregion + + #region 称重操作 + // 以板子为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByAddr(int DrawerNo) + { + + canBusSerial.DiscardInBuffer(); + var channel = Convert.ToInt32((DrawerNo * 10 + 1).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x28, 0x00, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送库位数量查询1【{string.Join(",", buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result1 = await GetBufferByPort(canBusSerial, 8); + + + var channel2 = Convert.ToInt32((DrawerNo * 10 + 2).ToString(), 16); + byte[] buffer2 = new byte[] { 0xaa, (byte)(channel2), 0x28, 0x00, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送库位数量查询2【{string.Join(",", buffer2)}】"); + canBusSerial.Write(buffer2, 0, 8); + byte[] result2 = await GetBufferByPort(canBusSerial, 8); + + byte[] res = new byte[6]; + Array.Copy(result1, 3, res, 0, 3); + Array.Copy(result2, 3, res, 3, 3); + + return res; + + } + + // 以板子为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByAddr2(int DrawerNo, int[] ColNos) + { + + + int[] res = new int[6]; + for (int i = 0; i < ColNos.Length; i++) + { + canBusSerial.DiscardInBuffer(); + var index = ColNos[i] > 3 ? 2 : 1; + var lock1 = ColNos[i] % 3 == 0 ? 3 : ColNos[i] % 3; + var channel = Convert.ToInt32((DrawerNo * 10 + index).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x27, (byte)lock1, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送库位数量查询1【{string.Join(",", buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result = await GetBufferByPort(canBusSerial, 8); + logger.Info($"称重发送库位数量查询1返回结果【{string.Join(",", result)}】"); + byte[] hl = result.Skip(3).Take(2).ToArray(); + int quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + res[ColNos[i] - 1] = quantity; + } + + return res; + + } + + // 指定药盒指示灯开启使能开锁 + public async Task BoxLockLightOn2(int DrawerNo, int[] ColNos) + { + for (int i = 0; i < ColNos.Length; i++) + { + var index = ColNos[i] > 3 ? 2 : 1; + var lock1 = ColNos[i] % 3 == 0 ? 3 : ColNos[i] % 3; + var channel = Convert.ToInt32((DrawerNo * 10 + index).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x03, (byte)lock1, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送药盒使能【{string.Join(",", buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(TimeSpan.FromMilliseconds(500)); + } + } + // 指定药盒指示灯开启失能开锁 + public async Task BoxLockLightOff2(int DrawerNo, int[] ColNos) + { + canBusSerial.DiscardInBuffer(); + for (int i = 0; i < ColNos.Length; i++) + { + var index = ColNos[i] > 3 ? 2 : 1; + var lock1 = ColNos[i] % 3 == 0 ? 3 : ColNos[i] % 3; + var channel = Convert.ToInt32((DrawerNo * 10 + index).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x04, (byte)lock1, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送药盒失能【{string.Join(",", buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + await Task.Delay(TimeSpan.FromMilliseconds(50)); + } + } + + public async Task ClearCount(int DrawerNo, int ColNo) + { + try + { + canBusSerial.DiscardInBuffer(); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = ColNo % 3 > 0 ? (ColNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)ColNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x25, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送清空计数【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + } + catch (Exception ex) + { + logger.Info($"操作发生异常:ex:{ex.Message},方法名:ClearCount;参数:{DrawerNo},{ColNo}"); + } + } + + public async Task SetNumCount(int DrawerNo, int ColNo, int Quantity) + { + try + { + canBusSerial.DiscardInBuffer(); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = ColNo % 3 > 0 ? (ColNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)ColNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x26, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + buffer[4] = (byte)(Quantity & 0xff); + //buffer[4] = (byte)(Quantity >> 8); + //buffer[5] = (byte)(Quantity & 0xff); + + + logger.Info($"标定数量【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + } + catch (Exception ex) + { + logger.Info($"操作发生异常:ex:{ex.Message},方法名:SetNumCount;参数:{DrawerNo},{ColNo},{Quantity}"); + } + } + + // 以板子为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByAddr() + { + + canBusSerial.DiscardInBuffer(); + var channel = Convert.ToInt32((DrawerNo * 10 + 1).ToString(), 16); + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x28, 0x00, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送库位数量查询1【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result1 = await GetBufferByPort(canBusSerial, 8); + + + var channel2 = Convert.ToInt32((DrawerNo * 10 + 2).ToString(), 16); + byte[] buffer2 = new byte[] { 0xaa, (byte)(channel2), 0x28, 0x00, 0x00, 0x00, 0x00, 0xee }; + logger.Info($"称重发送库位数量查询2【{Convert.ToHexString(buffer2)}】"); + canBusSerial.Write(buffer2, 0, 8); + byte[] result2 = await GetBufferByPort(canBusSerial, 8); + + byte[] res = new byte[6]; + Array.Copy(result1, 3, res, 0, 3); + Array.Copy(result2, 3, res, 3, 3); + + return res; + + } + // 以板子为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByAddrForMulti() + { + + + int[] res = new int[9]; + for (int i = 0; i < ColNoLst.Count; i++) + { + Thread.Sleep(200); + canBusSerial.DiscardInBuffer(); + int colNo = ColNoLst[i]; + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)colNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x27, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送库位数量查询{DrawerNo}-{ColNoLst[i]}【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result = await GetBufferByPort(canBusSerial, 8); + logger.Info($"称重发送库位数量查询返回结果【{Convert.ToHexString(result)}】"); + byte[] hl = result.Skip(4).Take(2).ToArray(); + var r = Convert.ToHexString(result).Substring(8, 1); + int quantity = 0; + if (r == "8") + { + hl[0] -= 0x80; + quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为负数{quantity}"); + quantity = 0 - quantity; + } + else + { + quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为正数{quantity}"); + } + + res[ColNoLst[i] - 1] = quantity; + } + + return res; + + } + //获取单个称重药合的药品数量 --查数 + public async Task CheckQuantityForSingle(int colNo) + { + //await Task.Delay(300); + //canBusSerial.DiscardInBuffer(); + //var index = colNo % 3 == 0 ? 3 : colNo % 3; + //var lock1 = colNo <= 3 ? 3 : colNo >= 7 ? 1 : 2; + //var channel = Convert.ToInt32((DrawerNo * 10 + index).ToString(), 16); + + + canBusSerial.DiscardInBuffer(); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)colNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x27, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送库位数量查询{DrawerNo}-{colNo}【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result = await GetBufferByPort(canBusSerial, 8); + byte[] hl = result.Skip(4).Take(2).ToArray(); + var r = Convert.ToHexString(result).Substring(8, 1); + logger.Info($"称重发送库位数量查询返回结果【{Convert.ToHexString(result)}】"); + + if (r == "8") + { + hl[0] -= 0x80; + int quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为负数{quantity}"); + return 0 - quantity; + } + else + { + int quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为正数{quantity}"); + return quantity; + } + + } + //获取单个称重药合的药品数量---标定(标定查数与库位查数区别在于用不用忽略0x80) + public async Task CheckQuantityForBiaoDing(int colNo) + { + canBusSerial.DiscardInBuffer(); + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)colNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x27, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送库位数量查询{DrawerNo}-{colNo}【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result = await GetBufferByPort(canBusSerial, 8); + logger.Info($"称重发送库位数量查询返回结果【{Convert.ToHexString(result)}】"); + byte[] hl = result.Skip(4).Take(2).ToArray(); + int quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + + return quantity; + + } + // 以板子为单位获取抽屉内所有库位的药品数量 + public async Task CheckQuantityByAddr2() + { + + + int[] res = new int[9]; + for (int i = 0; i < ColNos.Length; i++) + { + await Task.Delay(300); + canBusSerial.DiscardInBuffer(); + int colNo = ColNos[i]; + int[] iNum = new int[] { 3, 2, 1 }; + var colNo2 = colNo % 3 > 0 ? (colNo % 3) - 1 : 2; + var bColNo = iNum[colNo2]; + decimal decolNO = (decimal)colNo; + var channel = Convert.ToInt32((DrawerNo * 10 + Math.Ceiling(decolNO / 3)).ToString(), 16); + + byte[] buffer = new byte[] { 0xaa, (byte)(channel), 0x27, (byte)bColNo, 0x00, 0x00, 0x00, 0xee }; + + logger.Info($"称重发送库位数量查询{DrawerNo}-{ColNos[i]}【{Convert.ToHexString(buffer)}】"); + canBusSerial.Write(buffer, 0, 8); + byte[] result = await GetBufferByPort(canBusSerial, 8); + logger.Info($"称重发送库位数量查询返回结果【{Convert.ToHexString(result)}】"); + byte[] hl = result.Skip(4).Take(2).ToArray(); + //int quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + var r = Convert.ToHexString(result).Substring(8, 1); + int quantity = 0; + if (r == "8") + { + hl[0] -= 0x80; + quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为负数{quantity}"); + quantity = 0 - quantity; + } + else + { + quantity = BitConverter.ToInt16(hl.Reverse().ToArray(), 0); + logger.Info($"获取值为正数{quantity}"); + } + + + res[ColNos[i] - 1] = quantity; + } + + return res; + + } + + #endregion 称重操作 + #endregion + + #region 冰箱 + /// + /// 冰箱使能 + /// + /// + public async Task FridegOpen(int iIndex) + { + try + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0xD4, 0x00, 0x01, 0x0C, 0xF2 }; + //byte[] buffer = new byte[] { 0x01, 0x06, 0x10, 0xD4, 0x00, 0x01 }; + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + logger.Info($"冰箱使能【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + await Task.Delay(80); + } + catch (Exception ex) + { + logger.Info($"冰箱使能发生异常:ex:{ex.Message}"); + } + } + /// + /// 冰箱失能 + /// + /// + public async Task FridgeOff(int iIndex) + { + try + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0xD4, 0x00, 0x00, 0xCD, 0x32 }; + //byte[] buffer = new byte[] { 0x01, 0x06, 0x10, 0xD4, 0x00, 0x01 }; + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + logger.Info($"冰箱失能【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + await Task.Delay(80); + } + catch (Exception ex) + { + logger.Info($"冰箱失能发生异常:ex:{ex.Message}"); + } + } + /// + /// 冰箱报警使能 + /// + /// + public async Task FridgeAlarmOn(int iIndex) + { + try + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0xD5, 0x00, 0x01, 0x5D, 0x32 }; + //byte[] buffer = new byte[] { 0x01, 0x06, 0x10, 0xD5, 0x00, 0x01 }; + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + logger.Info($"冰箱报警使能【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + await Task.Delay(80); + } + catch (Exception ex) + { + logger.Info($"冰箱报警使能发生异常:ex:{ex.Message}"); + } + + } + + /// + /// 冰箱报警失能 + /// + /// + public async Task FridgeAlarmOff(int iIndex) + { + try + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0xD5, 0x00, 0x00, 0x9C, 0xF2 }; + //byte[] buffer = new byte[] { 0x01, 0x06, 0x10, 0xD5, 0x00, 0x00 }; + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + logger.Info($"冰箱报警失能【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + await Task.Delay(80); + } + catch (Exception ex) + { + logger.Info($"冰箱报警失能发生异常:ex:{ex.Message}"); + } + } + /// + /// 冰箱温度设定最小 + /// + /// + public async Task FridgeMinSetting(float min, int iIndex) + { + try + { + + int iMix = Convert.ToInt32(min * 10); + fridgeSerial.DiscardInBuffer(); + //byte[] bufferMin = new byte[] { 0x01, 0x06, 0x10, 0xC9, 0x00, 0x15, 0x9C, 0xFB }; + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] bufferMin = new byte[] { bAddress, 0x06, 0x10, 0xC9, 0x00, (byte)(iMix & 0xff) }; + //获取数组CRC校验码 + byte[] byteDate = CRC16MODBUS.CrcModBus(bufferMin); + //Array.Reverse(byteDate); + int dataLength = bufferMin.Length; + Array.Resize(ref bufferMin, dataLength + byteDate.Length); + for (int i = 0; i < byteDate.Length; i++) + { + bufferMin[dataLength + i] = byteDate[i]; + } + logger.Info($"冰箱温度设定Min:【{Convert.ToHexString(bufferMin)}】"); + fridgeSerial.Write(bufferMin, 0, 8); + } + catch (Exception ex) + { + logger.Info($"获取冰箱温度发生异常:ex:{ex.Message}"); + } + } + /// + /// 冰箱温度设定最大 + /// + /// + public async Task FridgeMaxSetting(float max, int iIndex) + { + try + { + int iMax = Convert.ToInt32(max * 10); + fridgeSerial.DiscardInBuffer(); + //byte[] bufferMin = new byte[] { 0x01, 0x06, 0x10, 0xC9, 0x00, 0x15, 0x9C, 0xFB }; + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] bufferMax = new byte[] { bAddress, 0x06, 0x10, 0xC8, 0x00, (byte)(iMax & 0xff) }; + //获取数组CRC校验码 + byte[] byteDate = CRC16MODBUS.CrcModBus(bufferMax); + //Array.Reverse(byteDate); + int dataLength = bufferMax.Length; + Array.Resize(ref bufferMax, dataLength + byteDate.Length); + for (int i = 0; i < byteDate.Length; i++) + { + bufferMax[dataLength + i] = byteDate[i]; + } + logger.Info($"冰箱温度设定Max:【{Convert.ToHexString(bufferMax)}】"); + fridgeSerial.Write(bufferMax, 0, 8); + } + catch (Exception ex) + { + logger.Info($"获取冰箱温度发生异常:ex:{ex.Message}"); + } + } + /// + /// 获取冰箱温度 + /// + /// + public async Task GetFridgeTemperature(int iIndex) + { + float temperature = 0.0f; + try + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x03, 0x10, 0x02, 0x00, 0x01, 0x21, 0x0A }; + //byte[] buffer = new byte[] { 0x01, 0x03, 0x10, 0x02, 0x00, 0x01 }; + + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + + logger.Info($"获取冰箱温度【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + + byte[] retByte = await GetBufferByPort(fridgeSerial, 7); + + logger.Info($"获取冰箱温度返回【{Convert.ToHexString(retByte)}】"); + + if (retByte != null && retByte.Length >= 7) + { + var hight = retByte[3]; + var low = retByte[4]; + int iHight = Convert.ToInt32(hight << 8); + int iLow = Convert.ToInt32(retByte[4]); + temperature = Convert.ToSingle(iHight + iLow) / 10; + } + } + catch (Exception ex) + { + + logger.Info($"获取冰箱温度发生异常:ex:{ex.Message}"); + } + return temperature; + } + /// + /// 设置冰箱温度 + /// + /// + public async Task SetFridgeTemperature(float temperature, int iIndex) + { + int tpt = (int)temperature * 10; + byte Temperature = (byte)(tpt & 0xff); + try + { + //if (!FridgeOperate) + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + //byte[] buffer = new byte[] { 0x01, 0x03, 0x10, 0x02, 0x00, 0x01, 0x21,0x0A }; + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0x02, 0x00, (byte)Temperature }; + + //获取数组CRC校验码 + byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + //Array.Reverse(byteDate); + int dataLength = buffer.Length; + Array.Resize(ref buffer, dataLength + byteDate.Length); + for (int i = 0; i < byteDate.Length; i++) + { + buffer[dataLength + i] = byteDate[i]; + } + logger.Info($"设置冰箱温度【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + + await GetBufferByPort(fridgeSerial, 8); + } + } + catch (Exception ex) + { + + logger.Info($"获取冰箱温度发生异常:ex:{ex.Message}"); + } + return temperature; + } + /// + /// 冰箱延迟报警 + /// + /// + public async Task FridgeDelayWarm(int iIndex) + { + try + { + //if (!FridgeOperate) + { + fridgeSerial.DiscardInBuffer(); + byte bAddress; + if (iIndex == 1) + { + bAddress = 0x01; + } + else + { + bAddress = 0x02; + } + byte[] buffer = new byte[] { bAddress, 0x06, 0x10, 0xCD, 0x00, 0x01, 0xDD, 0x35 }; + //byte[] buffer = new byte[] { 0x01, 0x06, 0x10, 0xCD, 0x00, 0x01 }; + ////获取数组CRC校验码 + //byte[] byteDate = CRC16MODBUS.CrcModBus(buffer); + ////Array.Reverse(byteDate); + //int dataLength = buffer.Length; + //Array.Resize(ref buffer, dataLength + byteDate.Length); + //for (int i = 0; i < byteDate.Length; i++) + //{ + // buffer[dataLength + i] = byteDate[i]; + //} + logger.Info($"冰箱延迟报警【{Convert.ToHexString(buffer)}】"); + fridgeSerial.Write(buffer, 0, 8); + } + } + catch (Exception ex) + { + + logger.Info($"获取冰箱温度发生异常:ex:{ex.Message}"); + } + } + #endregion + + } +} diff --git a/MasaBlazorApp3/Port/ScreenUtil.cs b/MasaBlazorApp3/Port/ScreenUtil.cs new file mode 100644 index 0000000..78cdce7 --- /dev/null +++ b/MasaBlazorApp3/Port/ScreenUtil.cs @@ -0,0 +1,171 @@ +using log4net; +using MasaBlazorApp3.Pojo; +using SuperSimpleTcp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Channels; +using System.Threading.Tasks; +using System.Windows.Markup; + +namespace MasaBlazorApp3.Port +{ + public class ScreenUtil + { + private readonly ILog logger = LogManager.GetLogger(typeof(ScreenUtil)); + SimpleTcpServer server = new SimpleTcpServer("0.0.0.0:8888"); + + string ipport { get; set; } = ""; + public ScreenUtil() + { + server.Events.ClientConnected += (object sender, ConnectionEventArgs e) => + { + ipport = e.IpPort; + logger.Info($"[{e.IpPort}] client connected"); + }; + server.Events.ClientDisconnected += (object sender, ConnectionEventArgs e) => + { + logger.Info($"[{e.IpPort}] client disconnected: {e.Reason}"); + }; + server.Events.DataReceived += (object sender, DataReceivedEventArgs e) => + { + logger.Info($"[{e.IpPort}]: {e.Data.Array}"); + }; + // let's go! + server.Start(); + } + + + private byte[] head = new byte[] { 0xee, 0xb1, 0x12 }; + + private byte[] end = new byte[] { 0xFF, 0xFC, 0xFF, 0xFF }; + public void SetStockInfo(ChannelStock channel, int screenId) + { + // 添加画面id + byte[] a = Copy2NewArr(head, HighLow(screenId)); + + + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + //if (channel.DrugInfo.DrugName != null) + //{ + byte[] content = Encoding.GetEncoding("gb2312").GetBytes(channel.Drug?.DrugName??""); + a = WriteInfo(a, content, channel.ColNo * 10 + 1); + //} + //if (channel.DrugInfo.Manufactory != null) + //{ + byte[] content1 = Encoding.GetEncoding("gb2312").GetBytes(channel.Drug?.Manufactory?? ""); + a = WriteInfo(a, content1, channel.ColNo * 10 + 2); + //} + //if (channel.DrugInfo.DrugSpec != null) + //{ + byte[] content2 = Encoding.GetEncoding("gb2312").GetBytes(channel.Drug?.DrugSpec ?? ""); + a = WriteInfo(a, content2, channel.ColNo * 10 + 3); + //} + //if (channel.ManuNo != null) + //{ + + byte[] content3 = Encoding.GetEncoding("gb2312").GetBytes(channel.ManuNo); + a = WriteInfo(a, content3, channel.ColNo * 10 + 4); + //} + //if (channel.EffDate != null) + //{ + byte[] content4 = Encoding.GetEncoding("gb2312").GetBytes(channel.EffDate); + a = WriteInfo(a, content4, channel.ColNo * 10 + 5); + //} + //if (channel.Quantity != null) + //{ + byte[] content5 = Encoding.GetEncoding("gb2312").GetBytes(channel.Quantity.ToString()); + a = WriteInfo(a, content5, channel.ColNo * 10 + 6); + //} + // 添加结束块 + byte[] b = Copy2NewArr(a, end); + server.Send(ipport, b); + } + + + public void TellChange(int d) + { + byte[] buffer = new byte[] { 0xee, 0xb5, 0x01, 0x00, 0xFF, 0xFC, 0xFF, 0xFF }; + + } + + public void SetStockInfo(List channels, int screenId) + { + // 添加画面id + byte[] a = Copy2NewArr(head, HighLow(screenId)); + + + for (int i = 0; i < channels.Count; i++) + { + ChannelStock channel = channels[i]; + if (channel.Drug.DrugName != null) + { + byte[] content = Encoding.ASCII.GetBytes(channel.Drug.DrugName); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 1); + } + if (channel.Drug.Manufactory != null) + { + byte[] content = Encoding.ASCII.GetBytes(channel.Drug.Manufactory); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 2); + } + if (channel.Drug.DrugSpec != null) + { + byte[] content = Encoding.ASCII.GetBytes(channel.Drug.DrugSpec); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 3); + } + if (channel.ManuNo != null) + { + + byte[] content = Encoding.ASCII.GetBytes(channel.ManuNo); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 4); + } + if (channel.EffDate != null) + { + byte[] content = Encoding.ASCII.GetBytes(channel.EffDate); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 5); + } + if (channel.Quantity != null) + { + byte[] content = Encoding.ASCII.GetBytes(channel.Quantity.ToString()); + a = WriteInfo(a, content, channels[0].DrawerNo * 10 + 6); + } + + + } + // 添加结束块 + byte[] b = Copy2NewArr(a, end); + server.Send(ipport, b); + } + + + public byte[] WriteInfo(byte[] a, byte[] content, int id) + { + // 添加控件id + byte[] b = Copy2NewArr(a, HighLow(id)); + // 添加需要向控件内写入的字节长度 + byte[] c = Copy2NewArr(b, HighLow(content.Length)); + // 写入内容 + return Copy2NewArr(c, content); + } + + public byte[] HighLow(int data) + { + byte high = Convert.ToByte((data >> 8) & 0x00ff); //位运算:右移8位 + byte low = Convert.ToByte(data & 0x00ff); //去掉高位 + return new byte[] {high, low}; + } + + public byte[] Copy2NewArr(byte[] source1, byte[] source2) + { + byte[] target = new byte[source1.Length + source2.Length]; + Buffer.BlockCopy(source1, 0, target, 0, source1.Length); + Buffer.BlockCopy(source2, 0, target, source1.Length, source2.Length); + return target; + } + + + + } +} diff --git a/MasaBlazorApp3/Program.cs b/MasaBlazorApp3/Program.cs new file mode 100644 index 0000000..6209e87 --- /dev/null +++ b/MasaBlazorApp3/Program.cs @@ -0,0 +1,102 @@ +using log4net.Config; +using MasaBlazorApp3; +using MasaBlazorApp3.DataAccess.Dao; +using MasaBlazorApp3.DataAccess.Impl; +using MasaBlazorApp3.DataAccess; +using MasaBlazorApp3.Finger; +using Microsoft.Extensions.DependencyInjection; +using Photino.Blazor; +using LinqToDB.AspNet; +using LinqToDB; +using Microsoft.Extensions.Configuration; +using LinqToDB.AspNet.Logging; +using Radzen; +using MasaBlazorApp3.Pojo.Config; +using MasaBlazorApp3.Port; + +internal class Program +{ + + [STAThread] + private static void Main(string[] args) + { + var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args); + + appBuilder.RootComponents.Add("#app"); + appBuilder.Services.AddRadzenComponents(); + // 指纹机工具类 + appBuilder.Services.AddSingleton(); + // 串口工具类 + appBuilder.Services.AddSingleton(); + // 登录用户全局存放 + appBuilder.Services.AddSingleton(); + // 框架自带通知服务注入 + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + + // 注入log + XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config")); + + //设置配置文件 + var config = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .Build(); + // 注入配置 + appBuilder.Services.Configure(config.GetSection("finger")); + appBuilder.Services.Configure(config.GetSection("setting")); + appBuilder.Services.Configure(config.GetSection("port")); + appBuilder.Services.Configure(config.GetSection("drawer")); + appBuilder.Services.Configure(config.GetSection("fridge")); + + // i18n + //appBuilder.Services.AddI18nText(); + // 数据库 + appBuilder.Services.AddLinqToDBContext((provider, options) => + options.UseMySql(config.GetValue("connectionStrings")) + .UseDefaultLogging(provider), ServiceLifetime.Transient); + // dao层数据库操作 + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + appBuilder.Services.AddScoped(); + + //自选取药 + appBuilder.Services.AddScoped(); + + //药品批次 + appBuilder.Services.AddScoped(); + + //报表 + appBuilder.Services.AddScoped(); + + + //交接班记录 + appBuilder.Services.AddScoped(); + //GlobalStateService.connStr = config.GetValue("connectionStrings"); + var app = appBuilder.Build(); + app.MainWindow + .SetHeight(768) + .SetWidth(1024) + .SetIconFile("favicon.ico") + .SetContextMenuEnabled(false) +#if DEBUG + .SetFullScreen(false) +#else + .SetChromeless(true) + .SetFullScreen(true) +#endif + ; + + + AppDomain.CurrentDomain.UnhandledException += (sender, error) => + { + }; + app.Run(); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Report/GridReportUtil.cs b/MasaBlazorApp3/Report/GridReportUtil.cs new file mode 100644 index 0000000..7b25aa9 --- /dev/null +++ b/MasaBlazorApp3/Report/GridReportUtil.cs @@ -0,0 +1,35 @@ +using gregn6Lib; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Report +{ + public class GridReportUtil + { + + // 定义Grid++Report报表主对象 + public static GridppReport Report = new GridppReport(); + /** + * 打印预览 + * tempname: 模板文件名称 + * data: 模板数据 + */ + public static void PrintReport(string tempname, object data) + { + // 定义Grid++Report报表主对象 + // 加载模板文件 + Report.LoadFromFile(new FileInfo(AppDomain.CurrentDomain.BaseDirectory) + "ReportTemp//" + tempname); + string s = JsonConvert.SerializeObject(data); + // 加载数据 + Report.LoadDataFromXML(JsonConvert.SerializeObject(data)); + Report.PrintPreview(true); + } + } +} diff --git a/MasaBlazorApp3/ReportTemp/Apply_Temp.grf b/MasaBlazorApp3/ReportTemp/Apply_Temp.grf new file mode 100644 index 0000000..d11a926 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/Apply_Temp.grf @@ -0,0 +1,334 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "LeftMargin":0.3175, + "TopMargin":0.899583, + "RightMargin":0.396875 + }, + "DetailGrid":{ + "CenterView":true, + "IsCrossTab":true, + "AppendBlankRow":true, + "Recordset":{ + "Field":[ + { + "Name":"手术间", + "DBFieldName":"DrawerNo" + }, + { + "Name":"请领时间", + "DBFieldName":"TTime" + }, + { + "Name":"二线", + "DBFieldName":"LineTwo" + }, + { + "Name":"一线", + "DBFieldName":"LineOne" + }, + { + "Name":"操作人", + "DBFieldName":"Nickname" + }, + { + "Name":"时间", + "Type":"DateTime", + "Format":"yyyy年MM月dd日", + "DBFieldName":"operationTime" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"数量", + "DBFieldName":"quantity" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"效期", + "Type":"DateTime", + "Format":"yyyy/MM/dd", + "DBFieldName":"effDate" + }, + { + "Name":"库位", + "DBFieldName":"drawerNo" + }, + { + "Name":"colNo" + }, + { + "Name":"type2", + "Type":"Integer", + "DBFieldName":"type" + }, + { + "Name":"医生签名", + "DBFieldName":"Doctor" + }, + { + "Name":"管理者签名", + "DBFieldName":"Manager" + } + ] + }, + "Column":[ + { + "Name":"手术间", + "Width":0.978958 + }, + { + "Name":"请领时间", + "Width":2.19604 + }, + { + "Name":"二线", + "Width":2.01083 + }, + { + "Name":"一线", + "Width":1.98438 + }, + { + "Name":"药品名称", + "Width":3.81 + }, + { + "Name":"医生签名", + "Width":2.01083 + }, + { + "Name":"管理者签名", + "Width":1.61396 + }, + { + "Name":"数量", + "Width":1.19063 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"手术间", + "TextAlign":"MiddleCenter", + "DataField":"操作人" + }, + { + "Column":"请领时间", + "TextAlign":"MiddleCenter", + "DataField":"请领时间" + }, + { + "Column":"二线", + "TextAlign":"MiddleCenter", + "DataField":"二线" + }, + { + "Column":"一线", + "TextAlign":"MiddleCenter", + "DataField":"一线" + }, + { + "Column":"药品名称", + "TextAlign":"MiddleCenter", + "DataField":"数量" + }, + { + "Column":"医生签名", + "TextAlign":"MiddleCenter", + "DataField":"医生签名" + }, + { + "Column":"管理者签名", + "TextAlign":"MiddleCenter", + "DataField":"管理者签名" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + } + ] + }, + "ColumnTitle":{ + "Height":1.79917, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"手术间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"手\r\n术\r\n间" + }, + { + "GroupTitle":false, + "Column":"请领时间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"请领时间" + }, + { + "GroupTitle":true, + "Name":"麻醉医生", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"二线", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"二线" + }, + { + "GroupTitle":false, + "Column":"一线", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"一线" + } + ], + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"麻醉医生" + }, + { + "GroupTitle":false, + "Column":"药品名称", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"[#药品名称#]" + }, + { + "GroupTitle":false, + "Column":"医生签名", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"医生\r\n签名" + }, + { + "GroupTitle":false, + "Column":"管理者签名", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"管理者\r\n签名" + }, + { + "GroupTitle":false, + "Column":"数量", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + } + ] + }, + "CrossTab":{ + "PercentFormat":"0.##%", + "HCrossFields":"药品名称", + "VCrossFields":"手术间", + "ListCols":4, + "TotalCols":3 + } + }, + "Parameter":[ + { + "Name":"startDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/1/1" + }, + { + "Name":"endDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/4/28 23:59:59" + }, + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.19063, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Anchor":"[Left|Top|Right|Bottom]", + "Dock":"Fill", + "Center":"Both", + "Border":{ + "Styles":"[DrawLeft|DrawTop|DrawRight]" + }, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"[#时间#]麻醉科毒麻药品请领登记表" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/ChangeShifts_Temp.grf b/MasaBlazorApp3/ReportTemp/ChangeShifts_Temp.grf new file mode 100644 index 0000000..7b39c0c --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/ChangeShifts_Temp.grf @@ -0,0 +1,275 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape", + "LeftMargin":1, + "TopMargin":1.42875, + "RightMargin":1, + "BottomMargin":1.8 + }, + "DetailGrid":{ + "CenterView":true, + "IsCrossTab":true, + "FixCols":2, + "AppendBlankRow":true, + "Recordset":{ + "Field":[ + { + "Name":"日期", + "Type":"DateTime", + "Format":"yyyy年MM月dd日", + "DBFieldName":"Ddate" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"DrugId" + }, + { + "Name":"时间", + "DBFieldName":"TDateTime" + }, + { + "Name":"实物", + "DBFieldName":"Quantity" + }, + { + "Name":"处方", + "DBFieldName":"OrderQuantity" + }, + { + "Name":"备注", + "DBFieldName":"Remarks" + }, + { + "Name":"交班人", + "DBFieldName":"FromUser" + }, + { + "Name":"接班人", + "DBFieldName":"ToUser" + }, + { + "Name":"规格", + "DBFieldName":"Spec" + }, + { + "Name":"基数", + "DBFieldName":"BaseQuantity" + } + ] + }, + "Column":[ + { + "Name":"日期" + }, + { + "Name":"时间" + }, + { + "Name":"实物" + }, + { + "Name":"处方" + }, + { + "Name":"备注" + }, + { + "Name":"交班人" + }, + { + "Name":"接班人" + } + ], + "ColumnContent":{ + "Height":0.79375, + "ColumnContentCell":[ + { + "Column":"日期", + "TextAlign":"MiddleCenter", + "DataField":"日期" + }, + { + "Column":"时间", + "TextAlign":"MiddleCenter", + "DataField":"时间" + }, + { + "Column":"实物", + "TextAlign":"MiddleCenter", + "DataField":"实物" + }, + { + "Column":"处方", + "TextAlign":"MiddleCenter", + "DataField":"处方" + }, + { + "Column":"备注", + "TextAlign":"MiddleCenter", + "DataField":"备注" + }, + { + "Column":"交班人", + "TextAlign":"MiddleCenter", + "DataField":"交班人" + }, + { + "Column":"接班人", + "TextAlign":"MiddleCenter", + "DataField":"接班人" + } + ] + }, + "ColumnTitle":{ + "Height":1.5875, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":true, + "Name":"药品名称", + "ColumnTitleCell":[ + { + "GroupTitle":true, + "Name":"药品规格", + "ColumnTitleCell":[ + { + "GroupTitle":true, + "Name":"固定基数", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"日期", + "TextAlign":"MiddleCenter", + "Text":"日期" + }, + { + "GroupTitle":false, + "Column":"时间", + "TextAlign":"MiddleCenter", + "Text":"时间" + } + ], + "TextAlign":"MiddleCenter", + "Text":"固定基数" + } + ], + "TextAlign":"MiddleCenter", + "Text":"药品规格" + } + ], + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":true, + "Name":"绑定的药名", + "ColumnTitleCell":[ + { + "GroupTitle":true, + "Name":"规格", + "ColumnTitleCell":[ + { + "GroupTitle":true, + "Name":"基数", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"实物", + "TextAlign":"MiddleCenter", + "Text":"实物" + }, + { + "GroupTitle":false, + "Column":"处方", + "TextAlign":"MiddleCenter", + "Text":"处方" + } + ], + "TextAlign":"MiddleCenter", + "Text":"[#规格#]" + } + ], + "TextAlign":"MiddleCenter", + "Text":"[#规格#]" + } + ], + "TextAlign":"MiddleCenter", + "Text":"[#药品名称#]" + }, + { + "GroupTitle":false, + "Column":"备注", + "TextAlign":"MiddleCenter", + "Text":"备注" + }, + { + "GroupTitle":false, + "Column":"交班人", + "TextAlign":"MiddleCenter", + "Text":"交班人" + }, + { + "GroupTitle":false, + "Column":"接班人", + "TextAlign":"MiddleCenter", + "Text":"接班人" + } + ] + }, + "CrossTab":{ + "PercentFormat":"0.##%", + "GroupAutoSum":false, + "HCrossFields":"DrugId", + "VCrossFields":"日期;时间", + "ListCols":2, + "TotalCols":3 + } + }, + "Parameter":[ + { + "Name":"machine_id" + }, + { + "Name":"startDate", + "DataType":"DateTime" + }, + { + "Name":"endDate", + "DataType":"DateTime" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.00542, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "ShrinkFontToFit":true, + "TextAlign":"MiddleCenter", + "Text":"中部战区总医院麻醉科特殊管理药品交接班记录" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/Usage_Temp.grf b/MasaBlazorApp3/ReportTemp/Usage_Temp.grf new file mode 100644 index 0000000..cd56045 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/Usage_Temp.grf @@ -0,0 +1,374 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape", + "LeftMargin":1, + "TopMargin":1.42875, + "RightMargin":1, + "BottomMargin":1.8 + }, + "DetailGrid":{ + "CenterView":true, + "IsCrossTab":true, + "FixCols":2, + "AppendBlankRow":true, + "Recordset":{ + "Field":[ + { + "Name":"日期", + "Type":"DateTime", + "Format":"yyyy年MM月dd日", + "DBFieldName":"portdate" + }, + { + "Name":"手术间", + "DBFieldName":"ShouShuJian" + }, + { + "Name":"主麻", + "DBFieldName":"ZhuMa" + }, + { + "Name":"副麻", + "DBFieldName":"FuMa" + }, + { + "Name":"ID号", + "DBFieldName":"IDNumber" + }, + { + "Name":"姓名", + "DBFieldName":"PName" + }, + { + "Name":"诊断", + "DBFieldName":"Diagnose" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"批号", + "DBFieldName":"ManuNo" + }, + { + "Name":"用量", + "DBFieldName":"UsageDosage" + }, + { + "Name":"残液量", + "DBFieldName":"CanYeLiang" + }, + { + "Name":"残液处置方式", + "DBFieldName":"CanYeChuZhi" + }, + { + "Name":"使用人签名", + "DBFieldName":"UseUserName" + }, + { + "Name":"复核人签名", + "DBFieldName":"CheckUserName" + }, + { + "Name":"DrugId" + } + ] + }, + "Column":[ + { + "Name":"手术间", + "Width":1.56104 + }, + { + "Name":"主麻", + "Width":1.82563 + }, + { + "Name":"副麻", + "Width":1.79917 + }, + { + "Name":"ID号" + }, + { + "Name":"姓名", + "Width":1.79917 + }, + { + "Name":"诊断", + "Width":4.39208 + }, + { + "Name":"批号" + }, + { + "Name":"用量", + "Width":2.2225 + }, + { + "Name":"残液量", + "Width":2.01083 + }, + { + "Name":"残液处置方式", + "Width":0.978958 + }, + { + "Name":"使用人签名", + "Width":1.61396 + }, + { + "Name":"复核人签名", + "Width":1.5875 + } + ], + "ColumnContent":{ + "Height":0.79375, + "ColumnContentCell":[ + { + "Column":"手术间", + "TextAlign":"MiddleCenter", + "DataField":"手术间" + }, + { + "Column":"主麻", + "TextAlign":"MiddleCenter", + "DataField":"主麻" + }, + { + "Column":"副麻", + "TextAlign":"MiddleCenter", + "DataField":"副麻" + }, + { + "Column":"ID号", + "TextAlign":"MiddleCenter", + "DataField":"ID号" + }, + { + "Column":"姓名", + "TextAlign":"MiddleCenter", + "DataField":"姓名" + }, + { + "Column":"诊断", + "TextAlign":"MiddleCenter", + "DataField":"诊断" + }, + { + "Column":"批号", + "TextAlign":"MiddleCenter", + "DataField":"批号" + }, + { + "Column":"用量", + "TextAlign":"MiddleCenter", + "DataField":"用量" + }, + { + "Column":"残液量", + "TextAlign":"MiddleCenter", + "DataField":"残液量" + }, + { + "Column":"残液处置方式", + "TextAlign":"MiddleCenter", + "DataField":"残液处置方式" + }, + { + "Column":"使用人签名", + "TextAlign":"MiddleCenter", + "DataField":"使用人签名" + }, + { + "Column":"复核人签名", + "TextAlign":"MiddleCenter", + "DataField":"复核人签名" + } + ] + }, + "ColumnTitle":{ + "Height":1.37583, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"手术间", + "TextAlign":"MiddleCenter", + "Text":"手\r\n术\r\n间" + }, + { + "GroupTitle":true, + "Name":"麻醉医师", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"主麻", + "TextAlign":"MiddleCenter", + "Text":"主麻" + }, + { + "GroupTitle":false, + "Column":"副麻", + "TextAlign":"MiddleCenter", + "Text":"副麻" + } + ], + "TextAlign":"MiddleCenter", + "Text":"麻醉医师" + }, + { + "GroupTitle":true, + "Name":"患者基本信息", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"ID号", + "TextAlign":"MiddleCenter", + "Text":"ID号" + }, + { + "GroupTitle":false, + "Column":"姓名", + "TextAlign":"MiddleCenter", + "Text":"姓名" + }, + { + "GroupTitle":false, + "Column":"诊断", + "TextAlign":"MiddleCenter", + "Text":"诊断" + } + ], + "TextAlign":"MiddleCenter", + "Text":"患者基本信息" + }, + { + "GroupTitle":true, + "Name":"药品名称", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"批号", + "TextAlign":"MiddleCenter", + "Text":"批号" + }, + { + "GroupTitle":false, + "Column":"用量", + "TextAlign":"MiddleCenter", + "Text":"用量" + }, + { + "GroupTitle":false, + "Column":"残液量", + "TextAlign":"MiddleCenter", + "Text":"残液量" + } + ], + "TextAlign":"MiddleCenter", + "Text":"[#药品名称#]" + }, + { + "GroupTitle":false, + "Column":"残液处置方式", + "TextAlign":"MiddleCenter", + "Text":"残液\r\n处置\r\n方式" + }, + { + "GroupTitle":false, + "Column":"使用人签名", + "TextAlign":"MiddleCenter", + "Text":"使用人\r\n签名" + }, + { + "GroupTitle":false, + "Column":"复核人签名", + "TextAlign":"MiddleCenter", + "Text":"复核人\r\n签名" + } + ] + }, + "CrossTab":{ + "PercentFormat":"0.##%", + "GroupAutoSum":false, + "HCrossFields":"DrugId", + "VCrossFields":"ID号", + "ListCols":6, + "TotalCols":3, + "TotalExcludeColumns":"残液处置方式;使用人签名;复核人签名" + } + }, + "Parameter":[ + { + "Name":"machine_id" + }, + { + "Name":"startDate", + "DataType":"DateTime" + }, + { + "Name":"endDate", + "DataType":"DateTime" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":3.81, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox12", + "Anchor":"[Right|Bottom]", + "AlignColumnSide":"Right", + "Left":19.4469, + "Top":2.98979, + "Width":3.46604, + "Height":0.582083, + "ShrinkFontToFit":true, + "Text":"日期:[#日期#]" + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Center":"Both", + "Left":2.93688, + "Top":1.00542, + "Width":21.8017, + "Height":1.79917, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "ShrinkFontToFit":true, + "TextAlign":"MiddleCenter", + "Text":"中国人民解放军中部战区总医院手术患者麻醉药品使用登记本" + }, + { + "Type":"MemoBox", + "Name":"MemoBox13", + "Anchor":"[Right|Bottom]", + "Left":23.2569, + "Top":3.01625, + "Width":3.01625, + "Height":0.582083, + "ShrinkFontToFit":true, + "Text":"手术室:武昌院区" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/account_book_temp.grf b/MasaBlazorApp3/ReportTemp/account_book_temp.grf new file mode 100644 index 0000000..d1481a7 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/account_book_temp.grf @@ -0,0 +1,579 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape", + "LeftMargin":1, + "TopMargin":1.42875, + "RightMargin":1, + "BottomMargin":1.8 + }, + "DetailGrid":{ + "CenterView":true, + "Recordset":{ + "Field":[ + { + "Name":"日期", + "Type":"DateTime", + "Format":"M/d", + "DBFieldName":"operationTime" + }, + { + "Name":"操作类型", + "DBFieldName":"type" + }, + { + "Name":"批号", + "DBFieldName":"manuNo" + }, + { + "Name":"入库数量", + "Type":"Integer", + "DBFieldName":"inQuantity" + }, + { + "Name":"出库数量", + "Type":"Integer", + "DBFieldName":"outQuantity" + }, + { + "Name":"批号结存", + "Type":"Integer", + "DBFieldName":"manuQuantity" + }, + { + "Name":"总结存", + "Type":"Integer", + "DBFieldName":"stockQuantity" + }, + { + "Name":"收/发药人", + "DBFieldName":"operatorName" + }, + { + "Name":"复核人", + "DBFieldName":"reviewerName" + }, + { + "Name":"药品名称", + "DBFieldName":"drugName" + }, + { + "Name":"规格", + "DBFieldName":"drugSpec" + }, + { + "Name":"单位", + "DBFieldName":"bigUnit" + }, + { + "Name":"剂型", + "DBFieldName":"dosage" + }, + { + "Name":"厂家", + "DBFieldName":"manuFactory" + }, + { + "Name":"有效期", + "Type":"DateTime", + "Format":"yy/M/d", + "DBFieldName":"effDate" + }, + { + "Name":"drugId" + }, + { + "Name":"凭证号", + "DBFieldName":"invoiceId" + }, + { + "Name":"供应单位", + "DBFieldName":"supplierDept" + }, + { + "Name":"领用部门", + "DBFieldName":"receiveDept" + }, + { + "Name":"备注", + "DBFieldName":"Remarks" + } + ] + }, + "Column":[ + { + "Name":"日期", + "Width":1.77271 + }, + { + "Name":"凭证号", + "Width":2.19604 + }, + { + "Name":"供货单位" + }, + { + "Name":"入库数量", + "Width":1.79917 + }, + { + "Name":"出库数量", + "Width":1.79917 + }, + { + "Name":"结存数量" + }, + { + "Name":"批号", + "Width":3.99521 + }, + { + "Name":"有效期", + "Width":2.43417 + }, + { + "Name":"接收(发药人)", + "Width":2.80458 + }, + { + "Name":"复核人", + "Width":2.80458 + }, + { + "Name":"备注" + } + ], + "ColumnContent":{ + "Height":0.85, + "ColumnContentCell":[ + { + "Column":"日期", + "WordWrap":true, + "TextAlign":"MiddleCenter", + "ShrinkFontToFit":true, + "DataField":"日期" + }, + { + "Column":"凭证号", + "TextAlign":"MiddleCenter", + "DataField":"凭证号" + }, + { + "Column":"供货单位", + "TextAlign":"MiddleCenter", + "DataField":"供应单位" + }, + { + "Column":"入库数量", + "TextAlign":"MiddleCenter", + "DataField":"入库数量" + }, + { + "Column":"出库数量", + "TextAlign":"MiddleCenter", + "DataField":"出库数量" + }, + { + "Column":"结存数量", + "TextAlign":"MiddleCenter", + "DataField":"批号结存" + }, + { + "Column":"批号", + "TextAlign":"MiddleCenter", + "DataField":"批号" + }, + { + "Column":"有效期", + "TextAlign":"MiddleCenter", + "DataField":"有效期" + }, + { + "Column":"接收(发药人)", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox12", + "Dock":"Fill", + "TextAlign":"MiddleCenter", + "DataField":"收/发药人" + } + ] + }, + { + "Column":"复核人", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox13", + "Dock":"Fill", + "TextAlign":"MiddleCenter", + "DataField":"复核人" + } + ] + }, + { + "Column":"备注", + "TextAlign":"MiddleCenter", + "DataField":"备注" + } + ] + }, + "ColumnTitle":{ + "Height":1.19063, + "RepeatStyle":"OnGroupHeaderPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"日期", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"日期" + }, + { + "GroupTitle":false, + "Column":"凭证号", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"凭证号" + }, + { + "GroupTitle":false, + "Column":"供货单位", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"供货单位\r\n(领用部门)" + }, + { + "GroupTitle":false, + "Column":"入库数量", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"入库\r\n数量" + }, + { + "GroupTitle":false, + "Column":"出库数量", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"出库\r\n数量" + }, + { + "GroupTitle":false, + "Column":"结存数量", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"结存数量" + }, + { + "GroupTitle":false, + "Column":"批号", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批号" + }, + { + "GroupTitle":false, + "Column":"有效期", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"有效\r\n期" + }, + { + "GroupTitle":false, + "Column":"接收(发药人)", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"接收人\r\n(发药人)" + }, + { + "GroupTitle":false, + "Column":"复核人", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"复核人" + }, + { + "GroupTitle":false, + "Column":"备注", + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"备注" + } + ] + }, + "Group":[ + { + "Name":"Group1", + "ByFields":"drugId", + "GroupHeader":{ + "PrintGridBorder":false, + "RepeatOnPage":true, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox11", + "Left":30.3742, + "Top":0.211667, + "Width":5.3975, + "Height":0.79375, + "Text":"[#manuFactory#]" + }, + { + "Type":"StaticBox", + "Name":"StaticBox16", + "Top":0.0529167, + "Width":1.19063, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "Text":"药品名称:" + }, + { + "Type":"FieldBox", + "Name":"FieldBox7", + "Left":1.16417, + "Top":0.0529167, + "Width":5.63563, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "DataField":"药品名称" + }, + { + "Type":"StaticBox", + "Name":"StaticBox17", + "Left":6.93208, + "Top":0.0529167, + "Width":1.11125, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "Text":"规格:" + }, + { + "Type":"FieldBox", + "Name":"FieldBox8", + "Left":8.01688, + "Top":0.0529167, + "Width":3.175, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "DataField":"规格" + }, + { + "Type":"StaticBox", + "Name":"StaticBox18", + "Left":11.5888, + "Top":0.0529167, + "Width":1.21708, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "Text":"单位:" + }, + { + "Type":"FieldBox", + "Name":"FieldBox9", + "Left":12.7794, + "Top":0.0529167, + "Width":1.87854, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "DataField":"单位" + }, + { + "Type":"StaticBox", + "Name":"StaticBox19", + "Left":15.3988, + "Top":0.0529167, + "Width":1.16417, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "Text":"剂型:" + }, + { + "Type":"FieldBox", + "Name":"FieldBox10", + "Left":16.5365, + "Top":0.0529167, + "Width":2.83104, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "DataField":"剂型" + }, + { + "Type":"StaticBox", + "Name":"StaticBox20", + "Left":19.7379, + "Top":0.0529167, + "Width":2.01083, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "Text":"生产企业:" + }, + { + "Type":"FieldBox", + "Name":"FieldBox11", + "Left":21.7223, + "Top":0.05, + "Width":5.92667, + "Height":0.978958, + "Font":{ + "Name":"宋体", + "Size":105000, + "Bold":true, + "Charset":134 + }, + "DataField":"厂家" + } + ], + "NewPageColumn":"Before" + }, + "GroupFooter":{ + "Visible":false + } + } + ] + }, + "Parameter":[ + { + "Name":"machine_id" + }, + { + "Name":"startDate", + "DataType":"DateTime" + }, + { + "Name":"endDate", + "DataType":"DateTime" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.79917, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "Font":{ + "Name":"宋体", + "Size":262500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"中部战区总医院麻醉药品、第一类精神药品进出专用账册" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/machine_log_add.grf b/MasaBlazorApp3/ReportTemp/machine_log_add.grf new file mode 100644 index 0000000..cb34783 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/machine_log_add.grf @@ -0,0 +1,284 @@ +{ + "Version":"6.8.5.2", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "LeftMargin":0.3175, + "TopMargin":0.899583, + "RightMargin":0.396875 + }, + "DetailGrid":{ + "CenterView":true, + "AppendBlankRow":true, + "Recordset":{ + "ConnectionString":"MYSQL;\r\nDatabase=hkcdb;\r\nPassword=qq1223;\r\nPort=3307;\r\nServer=127.0.0.1;\r\nUser=root;", + "QuerySQL":"SELECT \r\n dmr.`drawer_no` AS drawerNo,\r\n dmr.`col_no` AS colNo,\r\n dmr.`type` AS `type`,\r\n dmr.`quantity` AS quantity,\r\n dmr.`manu_no` AS manuNo,\r\n dmr.`eff_date` AS effDate,\r\n dmr.`operation_time` AS operationTime,\r\n di.`drug_name` AS drugName,\r\n di.`drug_spec` AS drugSpec,\r\n di.`pack_unit` AS packUnit,\r\n di.`manufactory` AS manuFactory,\r\n di.`max_stock` AS baseQuantity,\r\n dmr.`drug_id` AS drugId,\r\n ul.`user_name` AS nickname\r\nFROM\r\n dm_machine_record dmr\r\nLEFT JOIN drug_info di ON di.`drug_id` = dmr.`drug_id`\r\nLEFT JOIN user_list ul ON ul.`id` = dmr.`Operator`\r\nWHERE dmr.`type` = 1 \r\n AND dmr.`machine_id` = :machine_id\r\n AND dmr.`operation_time` > :startDate\r\n AND dmr.`operation_time` < :endDate", + "Field":[ + { + "Name":"操作人", + "DBFieldName":"Nickname" + }, + { + "Name":"时间", + "Type":"DateTime", + "Format":"yyyy/MM/dd HH:mm:ss", + "DBFieldName":"operationTime" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"数量", + "DBFieldName":"quantity" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"效期", + "Type":"DateTime", + "Format":"yyyy/MM/dd", + "DBFieldName":"effDate" + }, + { + "Name":"库位", + "DBFieldName":"drawerNo" + }, + { + "Name":"colNo" + }, + { + "Name":"type2", + "Type":"Integer", + "DBFieldName":"type" + } + ] + }, + "Column":[ + { + "Name":"操作人", + "Width":2.38125 + }, + { + "Name":"时间", + "Width":3.78354 + }, + { + "Name":"药品名称", + "Width":4.63021 + }, + { + "Name":"数量", + "Width":1.98438 + }, + { + "Name":"批次", + "Width":2.61938 + }, + { + "Name":"效期", + "Width":2.38125 + }, + { + "Name":"库位", + "Width":2.59292 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"操作人", + "TextAlign":"MiddleCenter", + "DataField":"操作人" + }, + { + "Column":"时间", + "TextAlign":"MiddleCenter", + "DataField":"时间" + }, + { + "Column":"药品名称", + "TextAlign":"MiddleCenter", + "DataField":"药品名称" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + }, + { + "Column":"批次", + "TextAlign":"MiddleCenter", + "DataField":"批次" + }, + { + "Column":"效期", + "TextAlign":"MiddleCenter", + "DataField":"效期" + }, + { + "Column":"库位", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox1", + "Left":9.60438, + "Top":-2.16958, + "Width":2.80458, + "Height":0.661458 + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "TextAlign":"MiddleCenter", + "Text":"[#库位#] - [#colNo#]" + } + ] + } + ] + }, + "ColumnTitle":{ + "Height":1.40229, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"操作人", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"操作人" + }, + { + "GroupTitle":false, + "Column":"时间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"时间" + }, + { + "GroupTitle":false, + "Column":"药品名称", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":false, + "Column":"数量", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + }, + { + "GroupTitle":false, + "Column":"批次", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"效期", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"效期" + }, + { + "GroupTitle":false, + "Column":"库位", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"库位" + } + ] + } + }, + "Parameter":[ + { + "Name":"startDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/1/1" + }, + { + "Name":"endDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/4/28 23:59:59" + }, + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.79917, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Left":7.59354, + "Top":0.211667, + "Width":5.60917, + "Height":1.19063, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"入库记录" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/machine_log_check.grf b/MasaBlazorApp3/ReportTemp/machine_log_check.grf new file mode 100644 index 0000000..95463f8 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/machine_log_check.grf @@ -0,0 +1,284 @@ +{ + "Version":"6.8.5.2", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "LeftMargin":0.3175, + "TopMargin":0.899583, + "RightMargin":0.396875 + }, + "DetailGrid":{ + "CenterView":true, + "AppendBlankRow":true, + "Recordset":{ + "ConnectionString":"MYSQL;\r\nDatabase=hkcdb;\r\nPassword=qq1223;\r\nPort=3307;\r\nServer=127.0.0.1;\r\nUser=root;", + "QuerySQL":"SELECT \r\n dmr.`drawer_no` AS drawerNo,\r\n dmr.`col_no` AS colNo,\r\n dmr.`type` AS `type`,\r\n dmr.`quantity` AS quantity,\r\n dmr.`manu_no` AS manuNo,\r\n dmr.`eff_date` AS effDate,\r\n dmr.`operation_time` AS operationTime,\r\n di.`drug_name` AS drugName,\r\n di.`drug_spec` AS drugSpec,\r\n di.`pack_unit` AS packUnit,\r\n di.`manufactory` AS manuFactory,\r\n di.`max_stock` AS baseQuantity,\r\n dmr.`drug_id` AS drugId,\r\n ul.`user_name` AS nickname\r\nFROM\r\n dm_machine_record dmr\r\nLEFT JOIN drug_info di ON di.`drug_id` = dmr.`drug_id`\r\nLEFT JOIN user_list ul ON ul.`id` = dmr.`Operator`\r\nWHERE dmr.`type` = 4 \r\n AND dmr.`machine_id` = :machine_id\r\n AND dmr.`operation_time` > :startDate\r\n AND dmr.`operation_time` < :endDate", + "Field":[ + { + "Name":"操作人", + "DBFieldName":"Nickname" + }, + { + "Name":"时间", + "Type":"DateTime", + "Format":"yyyy/MM/dd HH:mm:ss", + "DBFieldName":"operationTime" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"数量", + "DBFieldName":"quantity" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"效期", + "Type":"DateTime", + "Format":"yyyy/MM/dd", + "DBFieldName":"effDate" + }, + { + "Name":"库位", + "DBFieldName":"drawerNo" + }, + { + "Name":"colNo" + }, + { + "Name":"type2", + "Type":"Integer", + "DBFieldName":"type" + } + ] + }, + "Column":[ + { + "Name":"操作人", + "Width":2.38125 + }, + { + "Name":"时间", + "Width":3.78354 + }, + { + "Name":"药品名称", + "Width":4.63021 + }, + { + "Name":"数量", + "Width":1.98438 + }, + { + "Name":"批次", + "Width":2.61938 + }, + { + "Name":"效期", + "Width":2.38125 + }, + { + "Name":"库位", + "Width":2.59292 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"操作人", + "TextAlign":"MiddleCenter", + "DataField":"操作人" + }, + { + "Column":"时间", + "TextAlign":"MiddleCenter", + "DataField":"时间" + }, + { + "Column":"药品名称", + "TextAlign":"MiddleCenter", + "DataField":"药品名称" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + }, + { + "Column":"批次", + "TextAlign":"MiddleCenter", + "DataField":"批次" + }, + { + "Column":"效期", + "TextAlign":"MiddleCenter", + "DataField":"效期" + }, + { + "Column":"库位", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox1", + "Left":9.60438, + "Top":-2.16958, + "Width":2.80458, + "Height":0.661458 + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "TextAlign":"MiddleCenter", + "Text":"[#库位#] - [#colNo#]" + } + ] + } + ] + }, + "ColumnTitle":{ + "Height":1.40229, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"操作人", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"操作人" + }, + { + "GroupTitle":false, + "Column":"时间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"时间" + }, + { + "GroupTitle":false, + "Column":"药品名称", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":false, + "Column":"数量", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + }, + { + "GroupTitle":false, + "Column":"批次", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"效期", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"效期" + }, + { + "GroupTitle":false, + "Column":"库位", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"库位" + } + ] + } + }, + "Parameter":[ + { + "Name":"startDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/1/1" + }, + { + "Name":"endDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/4/28 23:59:59" + }, + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.79917, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Left":7.59354, + "Top":0.211667, + "Width":5.60917, + "Height":1.19063, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"盘点记录" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/machine_log_return.grf b/MasaBlazorApp3/ReportTemp/machine_log_return.grf new file mode 100644 index 0000000..106b501 --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/machine_log_return.grf @@ -0,0 +1,284 @@ +{ + "Version":"6.8.5.2", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "LeftMargin":0.3175, + "TopMargin":0.899583, + "RightMargin":0.396875 + }, + "DetailGrid":{ + "CenterView":true, + "AppendBlankRow":true, + "Recordset":{ + "ConnectionString":"MYSQL;\r\nDatabase=hkcdb;\r\nPassword=qq1223;\r\nPort=3307;\r\nServer=127.0.0.1;\r\nUser=root;", + "QuerySQL":"SELECT \r\n dmr.`drawer_no` AS drawerNo,\r\n dmr.`col_no` AS colNo,\r\n dmr.`type` AS `type`,\r\n CONCAT(dmr.`quantity`,IF(dmr.`type`=32,\"(空瓶)\",\"\")) AS quantity,\r\n dmr.`manu_no` AS manuNo,\r\n dmr.`eff_date` AS effDate,\r\n dmr.`operation_time` AS operationTime,\r\n di.`drug_name` AS drugName,\r\n di.`drug_spec` AS drugSpec,\r\n di.`pack_unit` AS packUnit,\r\n di.`manufactory` AS manuFactory,\r\n di.`max_stock` AS baseQuantity,\r\n dmr.`drug_id` AS drugId,\r\n ul.`user_name` AS nickname\r\nFROM\r\n dm_machine_record dmr\r\nLEFT JOIN drug_info di ON di.`drug_id` = dmr.`drug_id`\r\nLEFT JOIN user_list ul ON ul.`id` = dmr.`Operator`\r\nWHERE dmr.`type` in (31, 32)\r\n AND dmr.`machine_id` = :machine_id\r\n AND dmr.`operation_time` > :startDate\r\n AND dmr.`operation_time` < :endDate", + "Field":[ + { + "Name":"操作人", + "DBFieldName":"Nickname" + }, + { + "Name":"时间", + "Type":"DateTime", + "Format":"yyyy/MM/dd HH:mm:ss", + "DBFieldName":"operationTime" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"数量", + "DBFieldName":"quantity" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"效期", + "Type":"DateTime", + "Format":"yyyy/MM/dd", + "DBFieldName":"effDate" + }, + { + "Name":"库位", + "DBFieldName":"drawerNo" + }, + { + "Name":"colNo" + }, + { + "Name":"type2", + "Type":"Integer", + "DBFieldName":"type" + } + ] + }, + "Column":[ + { + "Name":"操作人", + "Width":2.38125 + }, + { + "Name":"时间", + "Width":3.78354 + }, + { + "Name":"药品名称", + "Width":4.63021 + }, + { + "Name":"数量", + "Width":1.98438 + }, + { + "Name":"批次", + "Width":2.61938 + }, + { + "Name":"效期", + "Width":2.38125 + }, + { + "Name":"库位", + "Width":2.59292 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"操作人", + "TextAlign":"MiddleCenter", + "DataField":"操作人" + }, + { + "Column":"时间", + "TextAlign":"MiddleCenter", + "DataField":"时间" + }, + { + "Column":"药品名称", + "TextAlign":"MiddleCenter", + "DataField":"药品名称" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + }, + { + "Column":"批次", + "TextAlign":"MiddleCenter", + "DataField":"批次" + }, + { + "Column":"效期", + "TextAlign":"MiddleCenter", + "DataField":"效期" + }, + { + "Column":"库位", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox1", + "Left":9.60438, + "Top":-2.16958, + "Width":2.80458, + "Height":0.661458 + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "TextAlign":"MiddleCenter", + "Text":"[#库位#] - [#colNo#]" + } + ] + } + ] + }, + "ColumnTitle":{ + "Height":1.40229, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"操作人", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"操作人" + }, + { + "GroupTitle":false, + "Column":"时间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"时间" + }, + { + "GroupTitle":false, + "Column":"药品名称", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":false, + "Column":"数量", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + }, + { + "GroupTitle":false, + "Column":"批次", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"效期", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"效期" + }, + { + "GroupTitle":false, + "Column":"库位", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"库位" + } + ] + } + }, + "Parameter":[ + { + "Name":"startDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/1/1" + }, + { + "Name":"endDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/4/28 23:59:59" + }, + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.79917, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Left":7.59354, + "Top":0.211667, + "Width":5.60917, + "Height":1.19063, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"归还记录" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/machine_log_take.grf b/MasaBlazorApp3/ReportTemp/machine_log_take.grf new file mode 100644 index 0000000..c17fb9f --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/machine_log_take.grf @@ -0,0 +1,284 @@ +{ + "Version":"6.8.5.2", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "LeftMargin":0.3175, + "TopMargin":0.899583, + "RightMargin":0.396875 + }, + "DetailGrid":{ + "CenterView":true, + "AppendBlankRow":true, + "Recordset":{ + "ConnectionString":"MYSQL;\r\nDatabase=hkcdb;\r\nPassword=qq1223;\r\nPort=3307;\r\nServer=127.0.0.1;\r\nUser=root;", + "QuerySQL":"SELECT \r\n dmr.`drawer_no` AS drawerNo,\r\n dmr.`col_no` AS colNo,\r\n dmr.`type` AS `type`,\r\n dmr.`quantity` AS quantity,\r\n dmr.`manu_no` AS manuNo,\r\n dmr.`eff_date` AS effDate,\r\n dmr.`operation_time` AS operationTime,\r\n di.`drug_name` AS drugName,\r\n di.`drug_spec` AS drugSpec,\r\n di.`pack_unit` AS packUnit,\r\n di.`manufactory` AS manuFactory,\r\n di.`max_stock` AS baseQuantity,\r\n dmr.`drug_id` AS drugId,\r\n ul.`user_name` AS nickname\r\nFROM\r\n dm_machine_record dmr\r\nLEFT JOIN drug_info di ON di.`drug_id` = dmr.`drug_id`\r\nLEFT JOIN user_list ul ON ul.`id` = dmr.`Operator`\r\nWHERE dmr.`type` = 2 \r\n AND dmr.`machine_id` = :machine_id\r\n AND dmr.`operation_time` > :startDate\r\n AND dmr.`operation_time` < :endDate", + "Field":[ + { + "Name":"操作人", + "DBFieldName":"Nickname" + }, + { + "Name":"时间", + "Type":"DateTime", + "Format":"yyyy/MM/dd HH:mm:ss", + "DBFieldName":"operationTime" + }, + { + "Name":"药品名称", + "DBFieldName":"DrugName" + }, + { + "Name":"数量", + "DBFieldName":"quantity" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"效期", + "Type":"DateTime", + "Format":"yyyy/MM/dd", + "DBFieldName":"effDate" + }, + { + "Name":"库位", + "DBFieldName":"drawerNo" + }, + { + "Name":"colNo" + }, + { + "Name":"type2", + "Type":"Integer", + "DBFieldName":"type" + } + ] + }, + "Column":[ + { + "Name":"操作人", + "Width":2.38125 + }, + { + "Name":"时间", + "Width":3.78354 + }, + { + "Name":"药品名称", + "Width":4.63021 + }, + { + "Name":"数量", + "Width":1.98438 + }, + { + "Name":"批次", + "Width":2.61938 + }, + { + "Name":"效期", + "Width":2.38125 + }, + { + "Name":"库位", + "Width":2.59292 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"操作人", + "TextAlign":"MiddleCenter", + "DataField":"操作人" + }, + { + "Column":"时间", + "TextAlign":"MiddleCenter", + "DataField":"时间" + }, + { + "Column":"药品名称", + "TextAlign":"MiddleCenter", + "DataField":"药品名称" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + }, + { + "Column":"批次", + "TextAlign":"MiddleCenter", + "DataField":"批次" + }, + { + "Column":"效期", + "TextAlign":"MiddleCenter", + "DataField":"效期" + }, + { + "Column":"库位", + "FreeCell":true, + "Control":[ + { + "Type":"FieldBox", + "Name":"FieldBox1", + "Left":9.60438, + "Top":-2.16958, + "Width":2.80458, + "Height":0.661458 + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Dock":"Fill", + "Center":"Both", + "TextAlign":"MiddleCenter", + "Text":"[#库位#] - [#colNo#]" + } + ] + } + ] + }, + "ColumnTitle":{ + "Height":1.40229, + "RepeatStyle":"OnPage", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"操作人", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"操作人" + }, + { + "GroupTitle":false, + "Column":"时间", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"时间" + }, + { + "GroupTitle":false, + "Column":"药品名称", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":false, + "Column":"数量", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + }, + { + "GroupTitle":false, + "Column":"批次", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"效期", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"效期" + }, + { + "GroupTitle":false, + "Column":"库位", + "Font":{ + "Name":"宋体", + "Size":120000, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"库位" + } + ] + } + }, + "Parameter":[ + { + "Name":"startDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/1/1" + }, + { + "Name":"endDate", + "DataType":"DateTime", + "Format":"yyyy-MM-dd hh:mm:ss", + "Value":"2023/4/28 23:59:59" + }, + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":1.79917, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Left":7.59354, + "Top":0.211667, + "Width":5.60917, + "Height":1.19063, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"出库记录" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/stock_template.grf b/MasaBlazorApp3/ReportTemp/stock_template.grf new file mode 100644 index 0000000..1466cad --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/stock_template.grf @@ -0,0 +1,349 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape" + }, + "DetailGrid":{ + "CenterView":true, + "PrintAdaptMethod":"ResizeToFit", + "AppendBlankRow":true, + "Recordset":{ + "ConnectionString":"MYSQL;\r\nDatabase=hkcdb;\r\nPassword=qq1223;\r\nPort=3307;\r\nServer=127.0.0.1;\r\nUser=root;", + "QuerySQL":"SELECT \r\n cl.`row_no` AS drawerNo,\r\n cl.`col_no` AS colNo,\r\n cl.`quantity` AS quantity,\r\n cl.`manu_no` AS manuNo,\r\n cl.`eff_date` AS effDate,\r\n di.`drug_name` AS drugName,\r\n di.`drug_spec` AS drugSpec,\r\n di.`pack_unit` AS packUnit,\r\n di.`manufactory` AS manuFactory,\r\n di.`max_stock` AS baseQuantity,\r\n cl.`drug_id` AS drugId\r\nFROM\r\n channel_stock cl\r\nINNER JOIN drug_info di ON di.`drug_id` = cl.`drug_id`\r\nWHERE cl.`machine_id` = :machine_id\r\n AND cl.`drawer_type` = 1\r\n ORDER BY cl.`drug_id`", + "Field":[ + { + "Name":"drugName" + }, + { + "Name":"drugSpec" + }, + { + "Name":"manuFactory" + }, + { + "Name":"quantityCount", + "DBFieldName":"quantity" + }, + { + "Name":"manuNo" + }, + { + "Name":"effDate" + }, + { + "Name":"quantity", + "Type":"Integer", + "Format":"0" + }, + { + "Name":"drawerNo" + }, + { + "Name":"drugId" + }, + { + "Name":"baseQuantity", + "Type":"Integer" + } + ] + }, + "Column":[ + { + "Name":"drugName", + "Width":5.37104 + }, + { + "Name":"drugSpec" + }, + { + "Name":"manuFactory", + "Width":4.60375 + }, + { + "Name":"Column1" + }, + { + "Name":"quantityCount", + "Width":2.59292 + }, + { + "Name":"manuNo" + }, + { + "Name":"effDate" + }, + { + "Name":"quantity", + "Width":2.43417 + } + ], + "ColumnContent":{ + "Height":0.79375, + "ColumnContentCell":[ + { + "Column":"drugName", + "TextAlign":"MiddleCenter", + "DataField":"drugName" + }, + { + "Column":"drugSpec", + "TextAlign":"MiddleCenter", + "DataField":"drugSpec" + }, + { + "Column":"manuFactory", + "TextAlign":"MiddleCenter", + "DataField":"manuFactory" + }, + { + "Column":"Column1", + "FreeCell":true + }, + { + "Column":"quantityCount", + "FreeCell":true + }, + { + "Column":"manuNo", + "TextAlign":"MiddleCenter", + "DataField":"manuNo" + }, + { + "Column":"effDate", + "TextAlign":"MiddleCenter", + "DataField":"effDate" + }, + { + "Column":"quantity", + "TextAlign":"MiddleCenter", + "DataField":"quantity" + } + ] + }, + "ColumnTitle":{ + "Height":1.19063, + "RepeatStyle":"OnPage", + "BeforeHeaders":true, + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"drugName", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"药品名称" + }, + { + "GroupTitle":false, + "Column":"drugSpec", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"规格" + }, + { + "GroupTitle":false, + "Column":"manuFactory", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"厂家" + }, + { + "GroupTitle":false, + "Column":"Column1", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"基数" + }, + { + "GroupTitle":false, + "Column":"quantityCount", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"总库存" + }, + { + "GroupTitle":false, + "Column":"manuNo", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"effDate", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"效期" + }, + { + "GroupTitle":false, + "Column":"quantity", + "Font":{ + "Name":"宋体", + "Size":142500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"数量" + } + ] + }, + "Group":[ + { + "Name":"drugId", + "ByFields":"drugId", + "GroupHeader":{ + "Visible":false, + "Height":0.79375, + "RepeatOnPage":true, + "OccupyColumn":true, + "IncludeFooter":true, + "OccupiedColumns":"drugName;drugSpec;manuFactory;quantityCount;Column1", + "VAlign":"Middle" + }, + "GroupFooter":{ + "Visible":false, + "Height":0.396875 + } + }, + { + "Name":"Group1", + "ByFields":"drugId", + "GroupHeader":{ + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox3", + "AlignColumn":"drugName", + "Width":5.34458, + "Height":1.19063, + "TextAlign":"MiddleCenter", + "Text":"[#drugName#]" + }, + { + "Type":"MemoBox", + "Name":"MemoBox4", + "AlignColumn":"drugSpec", + "Left":5.37104, + "Width":2.96333, + "Height":1.19063, + "TextAlign":"MiddleCenter", + "Text":"[#drugSpec#]" + }, + { + "Type":"MemoBox", + "Name":"MemoBox5", + "AlignColumn":"manuFactory", + "Left":8.36083, + "Width":4.57729, + "Height":1.19063, + "TextAlign":"MiddleCenter", + "Text":"[#manuFactory#]" + }, + { + "Type":"MemoBox", + "Name":"MemoBox6", + "AlignColumn":"Column1", + "Left":12.9646, + "Width":2.96333, + "Height":1.19063, + "TextAlign":"MiddleCenter", + "Text":"[#baseQuantity#]" + }, + { + "Type":"SummaryBox", + "Name":"SummaryBox1", + "AlignColumn":"quantityCount", + "Left":15.9544, + "Width":2.56646, + "Height":1.19063, + "TextAlign":"MiddleCenter", + "DataField":"quantity", + "Format":"0" + } + ], + "OccupyColumn":true, + "SameAsColumn":false, + "OccupiedColumns":"Column1;drugName;drugSpec;manuFactory;quantityCount", + "VAlign":"Middle" + }, + "GroupFooter":{ + "Visible":false + } + } + ] + }, + "Parameter":[ + { + "Name":"machine_id", + "Value":"DM1" + } + ], + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":2.40771, + "Control":[ + { + "Type":"StaticBox", + "Name":"StaticBox1", + "Center":"Horizontal", + "Left":8.89, + "Top":0.608542, + "Width":9.18104, + "Height":1.21708, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "TextAlign":"MiddleCenter", + "Text":"毒麻药品库存信息" + } + ], + "RepeatOnPage":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/ReportTemp/use_book.grf b/MasaBlazorApp3/ReportTemp/use_book.grf new file mode 100644 index 0000000..3c0d3cf --- /dev/null +++ b/MasaBlazorApp3/ReportTemp/use_book.grf @@ -0,0 +1,453 @@ +{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape" + }, + "DetailGrid":{ + "Recordset":{ + "Field":[ + { + "Name":"药品", + "DBFieldName":"drugName1" + }, + { + "Name":"批次", + "DBFieldName":"manuNo1" + }, + { + "Name":"数量", + "DBFieldName":"quantity1" + }, + { + "Name":"日期", + "Type":"DateTime", + "Format":"yyyy年MM月dd日", + "DBFieldName":"portDate" + } + ] + }, + "Column":[ + { + "Name":"药品", + "Width":6.16479 + }, + { + "Name":"批次", + "Width":2.40771 + }, + { + "Name":"数量", + "Width":1.79917 + } + ], + "ColumnContent":{ + "Height":1.00542, + "ColumnContentCell":[ + { + "Column":"药品", + "TextAlign":"MiddleCenter", + "DataField":"药品" + }, + { + "Column":"批次", + "TextAlign":"MiddleCenter", + "DataField":"批次" + }, + { + "Column":"数量", + "TextAlign":"MiddleCenter", + "DataField":"数量" + } + ] + }, + "ColumnTitle":{ + "Height":0.608542, + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"药品", + "TextAlign":"MiddleCenter", + "Text":"药品" + }, + { + "GroupTitle":false, + "Column":"批次", + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"数量", + "TextAlign":"MiddleCenter", + "Text":"数量" + } + ] + } + }, + "ReportHeader":[ + { + "Name":"ReportHeader1", + "Height":3.41313, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox12", + "Anchor":"[Right|Bottom]", + "AlignColumnSide":"Right", + "Left":17.6212, + "Top":2.80458, + "Width":3.46604, + "Height":0.582083, + "ShrinkFontToFit":true, + "Text":"日期:[#日期#]" + }, + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Center":"Both", + "Left":1.45521, + "Top":0.79375, + "Width":21.8017, + "Height":1.79917, + "Font":{ + "Name":"宋体", + "Size":217500, + "Bold":true, + "Charset":134 + }, + "ShrinkFontToFit":true, + "TextAlign":"MiddleCenter", + "Text":"中国人民解放军中部战区总医院手术患者麻醉药品使用登记本" + }, + { + "Type":"MemoBox", + "Name":"MemoBox13", + "Anchor":"[Right|Bottom]", + "Left":21.4313, + "Top":2.83104, + "Width":3.01625, + "Height":0.582083, + "ShrinkFontToFit":true, + "Text":"手术室:武昌院区" + } + ] + } + ], + "ReportFooter":[ + { + "Name":"ReportFooter2", + "Height":0.608542 + }, + { + "Name":"ReportFooter1", + "CanGrow":true, + "Height":1.5875, + "Control":[ + { + "Type":"SubReport", + "Name":"SubReport1", + "Dock":"Fill", +"Report":{ + "Version":"6.8.1.1", + "Font":{ + "Name":"宋体", + "Size":105000, + "Weight":400, + "Charset":134 + }, + "Printer":{ + "Oriention":"Landscape" + }, + "DetailGrid":{ + "Recordset":{ + "Field":[ + { + "Name":"药品", + "DBFieldName":"drugName" + }, + { + "Name":"批次", + "DBFieldName":"manuNo" + }, + { + "Name":"数量", + "Type":"Integer", + "DBFieldName":"quantity" + }, + { + "Name":"主麻", + "DBFieldName":"doctor1" + }, + { + "Name":"药品id", + "DBFieldName":"DrugId" + }, + { + "Name":"副麻", + "DBFieldName":"doctor2" + }, + { + "Name":"患者", + "DBFieldName":"PName" + }, + { + "Name":"患者id", + "DBFieldName":"patientId" + }, + { + "Name":"诊断", + "DBFieldName":"Diagnose" + }, + { + "Name":"残余液", + "DBFieldName":"residual" + }, + { + "Name":"用量", + "DBFieldName":"usage" + }, + { + "Name":"残液处置方式", + "DBFieldName":"CanYeChuZhi" + } + ] + }, + "Column":[ + { + "Name":"药品", + "Width":5.76792 + }, + { + "Name":"批次", + "Width":3.41313 + }, + { + "Name":"数量", + "Width":1.21708 + }, + { + "Name":"患者" + }, + { + "Name":"患者id" + }, + { + "Name":"诊断" + }, + { + "Name":"残余液", + "Width":2.03729 + }, + { + "Name":"用量", + "Width":1.19063 + }, + { + "Name":"残液处置方式", + "Width":1.77271 + } + ], + "ColumnContent":{ + "Height":0.6, + "ColumnContentCell":[ + { + "Column":"药品", + "ShrinkFontToFit":true, + "DataField":"药品" + }, + { + "Column":"批次", + "CanGrow":true, + "DataField":"批次" + }, + { + "Column":"数量", + "FreeCell":true, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox2", + "Dock":"Fill", + "Text":"[#SumAcc(数量)#]" + } + ] + }, + { + "Column":"患者", + "DataField":"患者" + }, + { + "Column":"患者id", + "DataField":"患者id" + }, + { + "Column":"诊断", + "DataField":"诊断" + }, + { + "Column":"残余液", + "DataField":"残余液" + }, + { + "Column":"用量", + "DataField":"用量" + }, + { + "Column":"残液处置方式", + "DataField":"残液处置方式" + } + ] + }, + "ColumnTitle":{ + "RepeatStyle":"OnGroupHeader", + "ColumnTitleCell":[ + { + "GroupTitle":false, + "Column":"药品", + "TextAlign":"MiddleCenter", + "Text":"药品" + }, + { + "GroupTitle":false, + "Column":"批次", + "TextAlign":"MiddleCenter", + "Text":"批次" + }, + { + "GroupTitle":false, + "Column":"数量", + "TextAlign":"MiddleCenter", + "Text":"数量" + }, + { + "GroupTitle":false, + "Column":"患者", + "TextAlign":"MiddleCenter", + "Text":"患者" + }, + { + "GroupTitle":false, + "Column":"患者id", + "TextAlign":"MiddleCenter", + "Text":"患者id" + }, + { + "GroupTitle":false, + "Column":"诊断", + "TextAlign":"MiddleCenter", + "Text":"诊断" + }, + { + "GroupTitle":false, + "Column":"残余液", + "TextAlign":"MiddleCenter", + "Text":"残余液" + }, + { + "GroupTitle":false, + "Column":"用量", + "TextAlign":"MiddleCenter", + "Text":"用量" + }, + { + "GroupTitle":false, + "Column":"残液处置方式", + "TextAlign":"MiddleCenter", + "CanGrow":true, + "CanShrink":true, + "Text":"残液\r\n处置\r\n方式" + } + ] + }, + "Group":[ + { + "Name":"Group1", + "ByFields":"主麻;副麻", + "GroupHeader":{ + "Height":2.98979, + "PrintGridBorder":false, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox1", + "Top":0.79375, + "Width":6.79979, + "Height":2.19604, + "Text":"麻醉医师\r\n主麻:[#主麻#]\r\n副麻:[#副麻#]" + } + ] + }, + "GroupFooter":{ + "Visible":false, + "Height":0 + } + }, + { + "Name":"Group2", + "ByFields":"药品id", + "GroupHeader":{ + "CanGrow":true, + "Height":0.6, + "Control":[ + { + "Type":"MemoBox", + "Name":"MemoBox3", + "AlignColumn":"药品", + "Width":5.74146, + "Height":0.6, + "CanGrow":true, + "ShrinkFontToFit":true, + "Text":"[#药品#]" + }, + { + "Type":"SummaryBox", + "Name":"SummaryBox1", + "AlignColumn":"数量", + "Left":9.18104, + "Width":1.19063, + "Height":0.6, + "DataField":"数量" + } + ], + "OccupyColumn":true, + "SameAsColumn":false, + "OccupiedColumns":"药品;数量", + "VAlign":"Middle" + }, + "GroupFooter":{ + "Visible":false, + "Height":0 + } + } + ] + } +} + } + ] + }, + { + "Name":"ReportFooter3", + "Height":0.79375, + "Control":[ + { + "Type":"StaticBox", + "Name":"StaticBox1", + "AlignColumnSide":"Left", + "Left":0.396875, + "Top":0.211667, + "Width":24.2094, + "Height":0.396875, + "ShrinkFontToFit":true, + "Text":"残余毒麻药品处置方法:①未使用完的注射液和镇痛泵中的残余药液,由医师、药师或护士在视频监控下双人将残余液完全倾泻入下水道并用水冲净,双人复核确认并签字,空安瓿按流程回收;②废贴需核对批次和数量,在领用后次日交回药房,并在药房签字确认" + } + ], + "PrintAtBottom":true + } + ] +} \ No newline at end of file diff --git a/MasaBlazorApp3/Shared/EmptyLayout.razor b/MasaBlazorApp3/Shared/EmptyLayout.razor new file mode 100644 index 0000000..046dd4c --- /dev/null +++ b/MasaBlazorApp3/Shared/EmptyLayout.razor @@ -0,0 +1,6 @@ +@inherits LayoutComponentBase + + @Body + + + \ No newline at end of file diff --git a/MasaBlazorApp3/Shared/MainLayout.razor b/MasaBlazorApp3/Shared/MainLayout.razor new file mode 100644 index 0000000..92334b6 --- /dev/null +++ b/MasaBlazorApp3/Shared/MainLayout.razor @@ -0,0 +1,219 @@ +@namespace MasaBlazorApp3 +@using MasaBlazorApp3.Pojo.Config +@using MasaBlazorApp3.Util +@using log4net +@inherits LayoutComponentBase + + + + + + + + + + + + + @if (children.Count > 5) + { + + + @foreach (Premission p in children) + { + if (childrenIds.Any(id => id == p.Id)) + { + @p.PremissionName + } + } + @if (children.Any(c => c.PremissionPath.Contains("Box"))) + { + + } + + } + else + { + + + + @foreach (Premission p in children) + { + if (childrenIds.Any(id => id == p.Id)) + { + @p.PremissionName + } + } + @if (children.Any(c => c.PremissionPath.Contains("Box"))) + { + + } + + } + + + + + + + + + +
+ + @Body + +
+
+ + +
+ +@code +{ + @inject IJSRuntime JSRuntime + @inject GlobalStateService globalStateService; + @inject NavigationManager na; + int selectedIndex = 0; + Pojo.User Operator; + List childrenIds; + List children; + @inject Microsoft.Extensions.Options.IOptions setting; + @inject PortUtil _portUtil; + @inject NotificationService _message + private readonly ILog logger = LogManager.GetLogger(typeof(MainLayout)); + bool currentPage = true; + + protected override void OnInitialized() + { + string Uri = na.Uri; + string[] s = Uri.Split("/"); + + Operator = globalStateService.Operator; + Premission parent = new Premission().getAdminPremission().Find(p => p.PremissionPath == s[3]); + childrenIds = Operator.role.permissionIds.Where(id => id - (parent.Id * 10) < 10).ToList(); + children = parent.Items.ToList(); + + if (setting.Value.autoOutLog > 0) + { + // 是否需要自动退出 + var promiseUtil = new PromiseUtil(); + promiseUtil.taskAsyncLoop(500, null, async (data, next, stop) => + { + if (globalStateService.Operator == null || !currentPage) + { + + logger.Info($"MainLayout页自动退出循环停止{globalStateService.Operator == null},{!currentPage}"); + stop(); + } + else + { + try + { + //没有在操作抽屉 + if (!_portUtil.Operate) + { + // 无人操作鼠标键盘 + if ((DateTime.Now - _portUtil.dateTime).TotalSeconds > setting.Value.autoOutLog && (DateTime.Now - _portUtil.mouseClickTime).TotalSeconds > setting.Value.autoOutLog) + { + logger.Info($"设备{setting.Value.autoOutLog}内无人操作,用户【{Operator?.NickName}】自动退出登录,_portUtil.Operate:{_portUtil.Operate},totalSecond:{(DateTime.Now - _portUtil.dateTime).TotalSeconds},lastInputTime:{CheckComputerFreeState.GetLastInputTime()},autoOutLog:{setting.Value.autoOutLog}"); + globalStateService.Operator = null; + globalStateService.Reviewer = null; + na.NavigateTo(""); + stop(); + } + else + { + next(); + } + } + else + { + next(); + } + } + catch (Exception ex) + { + logger.Info($"检查是否自动退出循环异常:{ex.Message}"); + next(); + } + } + }); + } + + base.OnInitialized(); + } + + + + void backHome() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + currentPage = false; + na.NavigateTo(""); + } + + void logout() + { + PortUtil.speechSynthesizer.SpeakAsyncCancelAll(); + globalStateService.Operator = null; + globalStateService.Reviewer = null; + na.NavigateTo(""); + } + async Task OpenStorage() + { + try + { + var b = await _portUtil.OpenStorage(); + } + catch (Exception ex) + { + logger.Info($"开储物箱发生错误,{ex.Message}"); + _message.Notify( + new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "提示", Detail = $"开储物箱发生错误,{ex.Message}", Duration = 4000 } + ); + } + } + + private DotNetObjectReference? dotNetObjectReference; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + dotNetObjectReference = DotNetObjectReference.Create(this); + await JSRuntime.InvokeVoidAsync("registerMouseClickHandler", dotNetObjectReference); + } + } + + [JSInvokable] + public void HandleMouseClick(int clientX, int clientY) + { + // 这里处理鼠标点击事件,例如记录日志或更新状态 + // Console.WriteLine($"Mouse clicked at: ({clientX}, {clientY})"); + _portUtil.mouseClickTime = DateTime.Now; + } + + public void Dispose() + { + dotNetObjectReference?.Dispose(); + } +} \ No newline at end of file diff --git a/MasaBlazorApp3/Shared/SettingLayout.razor b/MasaBlazorApp3/Shared/SettingLayout.razor new file mode 100644 index 0000000..23ff7d6 --- /dev/null +++ b/MasaBlazorApp3/Shared/SettingLayout.razor @@ -0,0 +1,94 @@ +@inherits LayoutComponentBase +@* @page "/manage/setting" *@ + +@layout MainLayout + +
+ + +
+
+ @Body +
+
+
+ + + +@inject NavigationManager Navigation +@inject ISettingManuDao settingManuDao; +@code { + RadzenPanelMenu panelMenu; + List menuItems = new(); + + protected override async Task OnInitializedAsync() + { + menuItems = await settingManuDao.GetMenuItemsAsync(); + } + // async void jump2Page(string path) + // { + // Navigation.NavigateTo(path); + // //可以在这里添加其他逻辑,例如记录导航历史或更新状态 + // Console.WriteLine($"Navigating to: {path}"); + // } +} diff --git a/MasaBlazorApp3/Util/CRC16MODBUS.cs b/MasaBlazorApp3/Util/CRC16MODBUS.cs new file mode 100644 index 0000000..a695875 --- /dev/null +++ b/MasaBlazorApp3/Util/CRC16MODBUS.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Util +{ + public class CRC16MODBUS + { + /// Name: CRC-16/MODBUS x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///******************************添加数据CRC16MODBUS校验位******************************************* + public static byte[] CrcModBus(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + //Array.Reverse(ret); + return ret; + } + } +} diff --git a/MasaBlazorApp3/Util/CheckComputerFreeState.cs b/MasaBlazorApp3/Util/CheckComputerFreeState.cs new file mode 100644 index 0000000..13d7bc0 --- /dev/null +++ b/MasaBlazorApp3/Util/CheckComputerFreeState.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace MasaBlazorApp3.Util +{ + public class CheckComputerFreeState + { + /// + /// 创建结构体用于返回捕获时间 + /// + [StructLayout(LayoutKind.Sequential)] + struct LASTINPUTINFO + { + /// + /// 设置结构体块容量 + /// + [MarshalAs(UnmanagedType.U4)] + public int cbSize; + + /// + /// 抓获的时间 + /// + [MarshalAs(UnmanagedType.U4)] + public uint dwTime; + } + + [DllImport("user32.dll")] + private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); + /// + /// 获取键盘和鼠标没有操作的时间 + /// + /// 用户上次使用系统到现在的时间间隔,单位为秒 + public static long GetLastInputTime() + { + LASTINPUTINFO vLastInputInfo = new LASTINPUTINFO(); + vLastInputInfo.cbSize = Marshal.SizeOf(vLastInputInfo); + if (!GetLastInputInfo(ref vLastInputInfo)) + { + return 0; + } + else + { + var count = (Environment.TickCount & Int32.MaxValue) - (long)vLastInputInfo.dwTime; + var icount = count / 1000; + return icount; + } + } + } +} diff --git a/MasaBlazorApp3/Util/MD5.cs b/MasaBlazorApp3/Util/MD5.cs new file mode 100644 index 0000000..272f5ff --- /dev/null +++ b/MasaBlazorApp3/Util/MD5.cs @@ -0,0 +1,30 @@ +using System.Text; +using System.Security.Cryptography; + +namespace MasaBlazorApp3.Util +{ + public class MD5 + { + public static string GetMD5Hash(string password) + { + //就是比string往后一直加要好的优化容器 + StringBuilder sb = new StringBuilder(); + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + //将输入字符串转换为字节数组并计算哈希。 + byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); + + //X为 十六进制 X都是大写 x都为小写 + //2为 每次都是两位数 + //假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A。 + //遍历哈希数据的每个字节 + //并将每个字符串格式化为十六进制字符串。 + int length = data.Length; + for (int i = 0; i < length; i++) + sb.Append(data[i].ToString("x2")); + + } + return sb.ToString(); + } + } +} diff --git a/MasaBlazorApp3/Util/PromiseUtil.cs b/MasaBlazorApp3/Util/PromiseUtil.cs new file mode 100644 index 0000000..26e7779 --- /dev/null +++ b/MasaBlazorApp3/Util/PromiseUtil.cs @@ -0,0 +1,44 @@ +using SharpPromise; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static LinqToDB.Reflection.Methods.LinqToDB.Insert; + +namespace MasaBlazorApp3.Util +{ + public class PromiseUtil + { + + public int _delay { get; set; } + + public T? _data { get; set; } + + public async Task taskAsyncLoop(int delay, T data, Action, Action, Action> action) + { + _data = data; + _delay = 0; + while (_delay >= 0) + { + await new Promise(async (Action onResolve, Action onReject) => + { + await Task.Delay(_delay); + try + { + await Task.Run(() => action(this, onResolve, onReject)); + } catch (Exception ex) + { + onReject(); + } + }).Then(() => + { + _delay = delay; + }).Catch((Exception e) => + { + _delay = -1; + }); + } + } + } +} diff --git a/MasaBlazorApp3/Util/VirtualKeyboardHelper.cs b/MasaBlazorApp3/Util/VirtualKeyboardHelper.cs new file mode 100644 index 0000000..4e564a2 --- /dev/null +++ b/MasaBlazorApp3/Util/VirtualKeyboardHelper.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Management; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +namespace MasaBlazorApp3.Util +{ + public class VirtualKeyboardHelper + { + private const uint WS_VISIBLE = 0x10000000; + private const int GWL_STYLE = -16; + private const int WM_SYSCOMMAND = 0x0112; + private const uint SC_CLOSE = 0xF060; + private const int WS_DISABLED = 0x08000000; + private const int DWMWA_CLOAKED = 14; + + private const string ApplicationFrameHostClassName = "ApplicationFrameWindow"; + private const string CoreWindowClassName = "Windows.UI.Core.CoreWindow"; + + private const string TextInputApplicationCaption = "Microsoft Text Input Application"; + + + /// + /// win10 虚拟键盘路径 + /// + private const string Win10TabTipPath = @"C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe"; + + /// + /// win7 虚拟键盘路径 + /// + private const string Win7OskPath = @"C:\WINDOWS\system32\osk.exe"; + + /// + /// 虚拟键盘 窗口名称 + /// + private const string TabTipWindowClassName = "IPTIP_Main_Window"; + + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32.dll", EntryPoint = "FindWindowEx")] + private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, + string lpszWindow); + + + [DllImport("user32.dll", EntryPoint = "GetWindowLong")] + private static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern bool PostMessage(IntPtr hWnd, int msg, uint wParam, uint lParam); + + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr); + + + [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", SetLastError = false)] + private static extern IntPtr GetDesktopWindow(); + + [DllImport("dwmapi.dll", EntryPoint = "DwmGetWindowAttribute")] + private static extern int DwmGetWindowAttribute(IntPtr intPtr, int dwAttribute, out int pvAttribute, + uint cbAttribute); + + + + /// + /// 判断键盘是否连接 + /// + /// + public static bool IsKeyboardAttached() + { + try + { + ManagementObjectSearcher searcher = + new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Keyboard"); + + int devCount = 0; + + foreach (ManagementObject obj in searcher.Get()) + { + if (obj["Status"].ToString().Contains("OK")) // if device is ready + { + //surface测试时发现,HID设备,不是键盘,比较特殊 + if (!obj["Description"].ToString().Contains("HID Keyboard Device")) + { + devCount++; + } + } + } + + return devCount > 0; + } + catch (Exception) + { + return false; + } + } + + /// + /// 打开虚拟键盘,目前支持win7 64位,win10 64位,exe编译为x86。 + /// + public static void ShowVirtualKeyboard() + { + //+------------------------------------------------------------------------------+ + //| | PlatformID | Major version | Minor version | + //+------------------------------------------------------------------------------+ + //| Windows 95 | Win32Windows | 4 | 0 | + //| Windows 98 | Win32Windows | 4 | 10 | + //| Windows Me | Win32Windows | 4 | 90 | + //| Windows NT 4.0 | Win32NT | 4 | 0 | + //| Windows 2000 | Win32NT | 5 | 0 | + //| Windows XP | Win32NT | 5 | 1 | + //| Windows 2003 | Win32NT | 5 | 2 | + //| Windows Vista | Win32NT | 6 | 0 | + //| Windows 2008 | Win32NT | 6 | 0 | + //| Windows 7 | Win32NT | 6 | 1 | + //| Windows 2008 R2 | Win32NT | 6 | 1 | + //| Windows 8 | Win32NT | 6 | 2 | + //| Windows 8.1 | Win32NT | 6 | 3 | + //+------------------------------------------------------------------------------+ + //| Windows 10 | Win32NT | 10 | 0 | + + try + { + var isWin7 = Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1; + var isWin8OrWin10 = + Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 2; + var isWin10 = Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Minor == 0; + if (isWin7) + { + //win7 + ShowWin7VirtualKeyboard(); + } + else if (isWin8OrWin10 || isWin10) + { + //win10 + ShowWin10VirtualKeyboard(); + } + } + catch (Exception) + { + // ignored + } + } + /// + /// 关闭虚拟键盘 + /// + public void CloseVirtualKeyboard() + { + var touchhWnd = FindWindow("IPTip_Main_Window", null); + if (touchhWnd == IntPtr.Zero) + { + return; + } + + PostMessage(touchhWnd, WM_SYSCOMMAND, SC_CLOSE, 0); + } + private static void ShowWin7VirtualKeyboard() + { + if (!Environment.Is64BitProcess && Environment.Is64BitOperatingSystem) + { + //32位程序 运行在64位系统上,打开32位程序,需要禁用文件重定向 + var ptr = new IntPtr(); + var isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr); + + Process.Start(Win7OskPath); + + if (isWow64FsRedirectionDisabled) + { + Wow64RevertWow64FsRedirection(ptr); + } + } + else if (Environment.Is64BitProcess && Environment.Is64BitOperatingSystem) + { + Process.Start(Win7OskPath); + } + } + + private static void ShowWin10VirtualKeyboard() + { + if (!IsTabTipProcessPresent()) + { + + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.FileName = Win10TabTipPath; + startInfo.UseShellExecute = true; + startInfo.Verb = "runas"; + Process.Start(startInfo); + while (!IsValidHandle(FindWindow("IPTIP_Main_Window", ""))) + { + Thread.Sleep(100); + } + } + + //判断可见性 + if (!IsWin10OnScreenKeyboardVisible()) + { + ShowByCom(); + } + } + + private static bool IsWin10OnScreenKeyboardVisible() + { + var handle = FindWindow(TabTipWindowClassName, ""); + if (!IsValidHandle(handle)) + { + return false; + } + + var isVisible = IsWindowVisibleByHandle(handle); + if (isVisible.HasValue) + { + return isVisible.Value; + } + + // hard way + var textInputHandle = FindTextInputWindow(); + return IsValidHandle(textInputHandle); + } + + private static IntPtr FindTextInputWindow() + { + var lastProbed = IntPtr.Zero; + do + { + lastProbed = FindWindowEx(IntPtr.Zero, lastProbed, ApplicationFrameHostClassName, null); + if (IsValidHandle(lastProbed)) + { + var textInput = FindWindowEx(lastProbed, IntPtr.Zero, CoreWindowClassName, + TextInputApplicationCaption); + return textInput; + } + } while (IsValidHandle(lastProbed)); + + return IntPtr.Zero; + } + + + + private static bool? IsWindowVisibleByHandle(IntPtr handle) + { + var style = GetWindowLong(handle, GWL_STYLE); + //Console.WriteLine( "Style {0:X8}", style ); + + // if is disabled - not visible + if ((style & WS_DISABLED) != 0) + { + return false; + } + + // if has visible style - visible :) + if ((style & WS_VISIBLE) != 0) + { + return true; + } + + // DWM Window can be cloaked + // see https://social.msdn.microsoft.com/Forums/vstudio/en-US/f8341376-6015-4796-8273-31e0be91da62/difference-between-actually-visible-and-not-visiblewhich-are-there-but-we-cant-see-windows-of?forum=vcgeneral + if (DwmGetWindowAttribute(handle, DWMWA_CLOAKED, out var cloaked, 4) == 0) + { + if (cloaked != 0) + { + return false; + } + } + + // undefined + return null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsValidHandle(IntPtr handle) + { + // if (?:) will be eliminated by jit + return IntPtr.Size == 4 + ? handle.ToInt32() > 0 + : handle.ToInt64() > 0; + } + + private static bool IsTabTipProcessPresent() + { + var handle = FindWindow(TabTipWindowClassName, ""); + return IntPtr.Size == 4 + ? handle.ToInt32() > 0 + : handle.ToInt64() > 0; + } + + private static void ShowByCom() + { + ITipInvocation instance = null; + try + { + instance = (ITipInvocation)Activator.CreateInstance(ComTypes.TipInvocationType); + instance.Toggle(GetDesktopWindow()); + } + finally + { + if (!ReferenceEquals(instance, null)) + { + Marshal.ReleaseComObject(instance); + } + } + } + } + + [ComImport] + [Guid("37c994e7-432b-4834-a2f7-dce1f13b834b")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface ITipInvocation + { + void Toggle(IntPtr hwnd); + } + + internal static class ComTypes + { + internal static readonly Guid ImmersiveShellBrokerGuid; + internal static readonly Type ImmersiveShellBrokerType; + + internal static readonly Guid TipInvocationGuid; + internal static readonly Type TipInvocationType; + + static ComTypes() + { + TipInvocationGuid = Guid.Parse("4ce576fa-83dc-4F88-951c-9d0782b4e376"); + TipInvocationType = Type.GetTypeFromCLSID(TipInvocationGuid); + + ImmersiveShellBrokerGuid = new Guid("228826af-02e1-4226-a9e0-99a855e455a6"); + ImmersiveShellBrokerType = Type.GetTypeFromCLSID(ImmersiveShellBrokerGuid); + } + } +} diff --git a/MasaBlazorApp3/Validator/LoginModelValidator.cs b/MasaBlazorApp3/Validator/LoginModelValidator.cs new file mode 100644 index 0000000..7018b4e --- /dev/null +++ b/MasaBlazorApp3/Validator/LoginModelValidator.cs @@ -0,0 +1,22 @@ +using FluentValidation; +using MasaBlazorApp3.Pojo; + +namespace MasaBlazorApp3.Validator +{ + public class LoginModelValidator : AbstractValidator + { + public LoginModelValidator() + { + RuleFor(u => u.Username).NotEmpty().WithMessage("用户名不能为空"); + RuleFor(u => u.Password).NotEmpty(); + } + + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((User)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; + } +} diff --git a/MasaBlazorApp3/_Imports.razor b/MasaBlazorApp3/_Imports.razor new file mode 100644 index 0000000..0237b18 --- /dev/null +++ b/MasaBlazorApp3/_Imports.razor @@ -0,0 +1,24 @@ +@using System.Net.Http +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Radzen +@using Radzen.Blazor +@using MasaBlazorApp3.Shared; +@using System.Net.Http.Json +@using System.IO; +@using System.Text.Json; + +@using MasaBlazorApp3.Pojo +@using MasaBlazorApp3.Validator +@using MasaBlazorApp3.Finger +@using MasaBlazorApp3.Port + + + +@using MasaBlazorApp3.DataAccess.Impl; +@using MasaBlazorApp3.DataAccess.Dao; +@using MasaBlazorApp3.DataAccess; +@using MasaBlazorApp3; \ No newline at end of file diff --git a/MasaBlazorApp3/appsettings.json b/MasaBlazorApp3/appsettings.json new file mode 100644 index 0000000..48ff920 --- /dev/null +++ b/MasaBlazorApp3/appsettings.json @@ -0,0 +1,54 @@ +{ + "connectionStrings": "server=127.0.0.1;port=3306;database=scsezdm;userid=root;password=qq1223;Charset=utf8mb4;", + "finger": { + "ip": "192.168.50.59", + "port": 4370, + "type": 2 + }, + "setting": { + "machineId": "DM1", + //药房代码,有则写无则空 + //. 药房代码 + "storage": "07010323", + "inPharmacyId": "062303", + "roomName": "麻醉科手术室", + "loginMode": 1, + "opFirst": true, + //自动退出登录时间,单位秒(0不自动退出) + "autoOutLog": 10, + "boxMachineId": "DM5", + "boxColor": "白,绿" + }, + "port": { + "drawerPortPath": "COM2", + "drawerProtocol": 485, + "scanCodePortPath": "COM1", + "canBusExsit": true, + "canBusPortPath": "COM5", + "totalDrawerCount": 16, + "canBusTwoExsit": true, + "StorageCan": 1, + //第二个can总线端口 + "canBusPortPathTwo": "COM9", + "doorAddr": 0, + "storageBoxAddr": 0, + "fridgePortExist": false, + "fridgePortPath": "COM3" + }, + "drawer": { + "single": [ 1,2 ], + "weigh": [ 4 ], + "box": [ 4 ], + "label": [ 4 ], + "returnDrawer": [12,14] + }, + "fridge": { + //冰箱温度区间 + "temperatureRange": "2-8", + //冰箱状态1关闭;0打开 + "fridgeState": 0, + //冰箱报警状态1关闭;0打开 + "alertState": 0 + } + +} \ No newline at end of file diff --git a/MasaBlazorApp3/favicon.ico b/MasaBlazorApp3/favicon.ico new file mode 100644 index 0000000..8a22d00 Binary files /dev/null and b/MasaBlazorApp3/favicon.ico differ diff --git a/MasaBlazorApp3/i18ntext/MyText.en.json b/MasaBlazorApp3/i18ntext/MyText.en.json new file mode 100644 index 0000000..41ec533 --- /dev/null +++ b/MasaBlazorApp3/i18ntext/MyText.en.json @@ -0,0 +1,4 @@ +{ + "login": "LOGIN", + "exit": "EXIT" +} diff --git a/MasaBlazorApp3/i18ntext/MyText.zh.json b/MasaBlazorApp3/i18ntext/MyText.zh.json new file mode 100644 index 0000000..6360d23 --- /dev/null +++ b/MasaBlazorApp3/i18ntext/MyText.zh.json @@ -0,0 +1,4 @@ +{ + "login": "登录", + "exit": "退出" +} diff --git a/MasaBlazorApp3/log4net.config b/MasaBlazorApp3/log4net.config new file mode 100644 index 0000000..a5c3389 --- /dev/null +++ b/MasaBlazorApp3/log4net.config @@ -0,0 +1,53 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MasaBlazorApp3/wwwroot/css/app.css b/MasaBlazorApp3/wwwroot/css/app.css new file mode 100644 index 0000000..6c60549 --- /dev/null +++ b/MasaBlazorApp3/wwwroot/css/app.css @@ -0,0 +1,62 @@ +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif, SimHei !important; +} + +h1:focus { + outline: none; +} + +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + +.blazor-error-boundary::after { + content: "An error has occurred." +} + +.status-bar-safe-area { + display: none; +} + +@supports (-webkit-touch-callout: none) { + .status-bar-safe-area { + display: flex; + position: sticky; + top: 0; + height: env(safe-area-inset-top); + background-color: #f7f7f7; + width: 100%; + z-index: 1; + } + + .flex-column, .navbar-brand { + padding-left: env(safe-area-inset-left); + } +} +.rz-datatable-thead th .rz-column-title, .rz-grid-table thead th .rz-column-title { + font-weight: 600 !important; +} +.rz-grid-table thead th { + background-color: #f2fafb !important; +} diff --git a/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css b/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..bd25b2e --- /dev/null +++ b/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css @@ -0,0 +1,11599 @@ +@charset "UTF-8"; /*! + * Bootstrap v5.1.0 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +:root { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #0d6efd; + --bs-secondary: #6c757d; + --bs-success: #198754; + --bs-info: #0dcaf0; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 13,110,253; + --bs-secondary-rgb: 108,117,125; + --bs-success-rgb: 25,135,84; + --bs-info-rgb: 13,202,240; + --bs-warning-rgb: 255,193,7; + --bs-danger-rgb: 220,53,69; + --bs-light-rgb: 248,249,250; + --bs-dark-rgb: 33,37,41; + --bs-white-rgb: 255,255,255; + --bs-black-rgb: 0,0,0; + --bs-body-rgb: 33,37,41; + --bs-font-sans-serif: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-bg: #fff +} + +*, ::after, ::before { + box-sizing: border-box +} + +@media (prefers-reduced-motion:no-preference) { + :root { + scroll-behavior: smooth + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: transparent +} + +hr { + margin: 1rem 0; + color: inherit; + background-color: currentColor; + border: 0; + opacity: .25 +} + + hr:not([size]) { + height: 1px + } + +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: .5rem; + font-weight: 500; + line-height: 1.2 +} + +.h1, h1 { + font-size: calc(1.375rem + 1.5vw) +} + +@media (min-width:1200px) { + .h1, h1 { + font-size: 2.5rem + } +} + +.h2, h2 { + font-size: calc(1.325rem + .9vw) +} + +@media (min-width:1200px) { + .h2, h2 { + font-size: 2rem + } +} + +.h3, h3 { + font-size: calc(1.3rem + .6vw) +} + +@media (min-width:1200px) { + .h3, h3 { + font-size: 1.75rem + } +} + +.h4, h4 { + font-size: calc(1.275rem + .3vw) +} + +@media (min-width:1200px) { + .h4, h4 { + font-size: 1.5rem + } +} + +.h5, h5 { + font-size: 1.25rem +} + +.h6, h6 { + font-size: 1rem +} + +p { + margin-top: 0; + margin-bottom: 1rem +} + +abbr[data-bs-original-title], abbr[title] { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit +} + +ol, ul { + padding-left: 2rem +} + +dl, ol, ul { + margin-top: 0; + margin-bottom: 1rem +} + + ol ol, ol ul, ul ol, ul ul { + margin-bottom: 0 + } + +dt { + font-weight: 700 +} + +dd { + margin-bottom: .5rem; + margin-left: 0 +} + +blockquote { + margin: 0 0 1rem +} + +b, strong { + font-weight: bolder +} + +.small, small { + font-size: .875em +} + +.mark, mark { + padding: .2em; + background-color: #fcf8e3 +} + +sub, sup { + position: relative; + font-size: .75em; + line-height: 0; + vertical-align: baseline +} + +sub { + bottom: -.25em +} + +sup { + top: -.5em +} + +a { + color: #0d6efd; + text-decoration: underline +} + + a:hover { + color: #0a58ca + } + + a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none + } + +code, kbd, pre, samp { + font-family: var(--bs-font-monospace); + font-size: 1em; + direction: ltr; + unicode-bidi: bidi-override +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: .875em +} + + pre code { + font-size: inherit; + color: inherit; + word-break: normal + } + +code { + font-size: .875em; + color: #d63384; + word-wrap: break-word +} + +a > code { + color: inherit +} + +kbd { + padding: .2rem .4rem; + font-size: .875em; + color: #fff; + background-color: #212529; + border-radius: .2rem +} + + kbd kbd { + padding: 0; + font-size: 1em; + font-weight: 700 + } + +figure { + margin: 0 0 1rem +} + +img, svg { + vertical-align: middle +} + +table { + caption-side: bottom; + border-collapse: collapse +} + +caption { + padding-top: .5rem; + padding-bottom: .5rem; + color: #6c757d; + text-align: left +} + +th { + text-align: inherit; + text-align: -webkit-match-parent +} + +tbody, td, tfoot, th, thead, tr { + border-color: inherit; + border-style: solid; + border-width: 0 +} + +label { + display: inline-block +} + +button { + border-radius: 0 +} + + button:focus:not(:focus-visible) { + outline: 0 + } + +button, input, optgroup, select, textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit +} + +button, select { + text-transform: none +} + +[role=button] { + cursor: pointer +} + +select { + word-wrap: normal +} + + select:disabled { + opacity: 1 + } + +[list]::-webkit-calendar-picker-indicator { + display: none +} + +[type=button], [type=reset], [type=submit], button { + -webkit-appearance: button +} + + [type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled), button:not(:disabled) { + cursor: pointer + } + +::-moz-focus-inner { + padding: 0; + border-style: none +} + +textarea { + resize: vertical +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0 +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: .5rem; + font-size: calc(1.275rem + .3vw); + line-height: inherit +} + +@media (min-width:1200px) { + legend { + font-size: 1.5rem + } +} + +legend + * { + clear: left +} + +::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-fields-wrapper, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-text, ::-webkit-datetime-edit-year-field { + padding: 0 +} + +::-webkit-inner-spin-button { + height: auto +} + +[type=search] { + outline-offset: -2px; + -webkit-appearance: textfield +} + +::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-color-swatch-wrapper { + padding: 0 +} + +::file-selector-button { + font: inherit +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button +} + +output { + display: inline-block +} + +iframe { + border: 0 +} + +summary { + display: list-item; + cursor: pointer +} + +progress { + vertical-align: baseline +} + +[hidden] { + display: none !important +} + +.lead { + font-size: 1.25rem; + font-weight: 300 +} + +.display-1 { + font-size: calc(1.625rem + 4.5vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-1 { + font-size: 5rem + } +} + +.display-2 { + font-size: calc(1.575rem + 3.9vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-2 { + font-size: 4.5rem + } +} + +.display-3 { + font-size: calc(1.525rem + 3.3vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-3 { + font-size: 4rem + } +} + +.display-4 { + font-size: calc(1.475rem + 2.7vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-4 { + font-size: 3.5rem + } +} + +.display-5 { + font-size: calc(1.425rem + 2.1vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-5 { + font-size: 3rem + } +} + +.display-6 { + font-size: calc(1.375rem + 1.5vw); + font-weight: 300; + line-height: 1.2 +} + +@media (min-width:1200px) { + .display-6 { + font-size: 2.5rem + } +} + +.list-unstyled { + padding-left: 0; + list-style: none +} + +.list-inline { + padding-left: 0; + list-style: none +} + +.list-inline-item { + display: inline-block +} + + .list-inline-item:not(:last-child) { + margin-right: .5rem + } + +.initialism { + font-size: .875em; + text-transform: uppercase +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem +} + + .blockquote > :last-child { + margin-bottom: 0 + } + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: .875em; + color: #6c757d +} + + .blockquote-footer::before { + content: "— " + } + +.img-fluid { + max-width: 100%; + height: auto +} + +.img-thumbnail { + padding: .25rem; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: .25rem; + max-width: 100%; + height: auto +} + +.figure { + display: inline-block +} + +.figure-img { + margin-bottom: .5rem; + line-height: 1 +} + +.figure-caption { + font-size: .875em; + color: #6c757d +} + +.container, .container-fluid, .container-lg, .container-md, .container-sm, .container-xl, .container-xxl { + width: 100%; + padding-right: var(--bs-gutter-x,.75rem); + padding-left: var(--bs-gutter-x,.75rem); + margin-right: auto; + margin-left: auto +} + +@media (min-width:576px) { + .container, .container-sm { + max-width: 540px + } +} + +@media (min-width:768px) { + .container, .container-md, .container-sm { + max-width: 720px + } +} + +@media (min-width:992px) { + .container, .container-lg, .container-md, .container-sm { + max-width: 960px + } +} + +@media (min-width:1200px) { + .container, .container-lg, .container-md, .container-sm, .container-xl { + max-width: 1140px + } +} + +@media (min-width:1400px) { + .container, .container-lg, .container-md, .container-sm, .container-xl, .container-xxl { + max-width: 1320px + } +} + +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(var(--bs-gutter-y) * -1); + margin-right: calc(var(--bs-gutter-x) * -.5); + margin-left: calc(var(--bs-gutter-x) * -.5) +} + + .row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * .5); + padding-left: calc(var(--bs-gutter-x) * .5); + margin-top: var(--bs-gutter-y) + } + +.col { + flex: 1 0 0% +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100% +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50% +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.3333333333% +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25% +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20% +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.6666666667% +} + +.col-auto { + flex: 0 0 auto; + width: auto +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333% +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667% +} + +.col-3 { + flex: 0 0 auto; + width: 25% +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333% +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667% +} + +.col-6 { + flex: 0 0 auto; + width: 50% +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333% +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667% +} + +.col-9 { + flex: 0 0 auto; + width: 75% +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333% +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667% +} + +.col-12 { + flex: 0 0 auto; + width: 100% +} + +.offset-1 { + margin-left: 8.33333333% +} + +.offset-2 { + margin-left: 16.66666667% +} + +.offset-3 { + margin-left: 25% +} + +.offset-4 { + margin-left: 33.33333333% +} + +.offset-5 { + margin-left: 41.66666667% +} + +.offset-6 { + margin-left: 50% +} + +.offset-7 { + margin-left: 58.33333333% +} + +.offset-8 { + margin-left: 66.66666667% +} + +.offset-9 { + margin-left: 75% +} + +.offset-10 { + margin-left: 83.33333333% +} + +.offset-11 { + margin-left: 91.66666667% +} + +.g-0, .gx-0 { + --bs-gutter-x: 0 +} + +.g-0, .gy-0 { + --bs-gutter-y: 0 +} + +.g-1, .gx-1 { + --bs-gutter-x: 0.25rem +} + +.g-1, .gy-1 { + --bs-gutter-y: 0.25rem +} + +.g-2, .gx-2 { + --bs-gutter-x: 0.5rem +} + +.g-2, .gy-2 { + --bs-gutter-y: 0.5rem +} + +.g-3, .gx-3 { + --bs-gutter-x: 1rem +} + +.g-3, .gy-3 { + --bs-gutter-y: 1rem +} + +.g-4, .gx-4 { + --bs-gutter-x: 1.5rem +} + +.g-4, .gy-4 { + --bs-gutter-y: 1.5rem +} + +.g-5, .gx-5 { + --bs-gutter-x: 3rem +} + +.g-5, .gy-5 { + --bs-gutter-y: 3rem +} + +@media (min-width:576px) { + .col-sm { + flex: 1 0 0% + } + + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto + } + + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100% + } + + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50% + } + + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.3333333333% + } + + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25% + } + + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20% + } + + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.6666666667% + } + + .col-sm-auto { + flex: 0 0 auto; + width: auto + } + + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333% + } + + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667% + } + + .col-sm-3 { + flex: 0 0 auto; + width: 25% + } + + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333% + } + + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667% + } + + .col-sm-6 { + flex: 0 0 auto; + width: 50% + } + + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333% + } + + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667% + } + + .col-sm-9 { + flex: 0 0 auto; + width: 75% + } + + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333% + } + + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667% + } + + .col-sm-12 { + flex: 0 0 auto; + width: 100% + } + + .offset-sm-0 { + margin-left: 0 + } + + .offset-sm-1 { + margin-left: 8.33333333% + } + + .offset-sm-2 { + margin-left: 16.66666667% + } + + .offset-sm-3 { + margin-left: 25% + } + + .offset-sm-4 { + margin-left: 33.33333333% + } + + .offset-sm-5 { + margin-left: 41.66666667% + } + + .offset-sm-6 { + margin-left: 50% + } + + .offset-sm-7 { + margin-left: 58.33333333% + } + + .offset-sm-8 { + margin-left: 66.66666667% + } + + .offset-sm-9 { + margin-left: 75% + } + + .offset-sm-10 { + margin-left: 83.33333333% + } + + .offset-sm-11 { + margin-left: 91.66666667% + } + + .g-sm-0, .gx-sm-0 { + --bs-gutter-x: 0 + } + + .g-sm-0, .gy-sm-0 { + --bs-gutter-y: 0 + } + + .g-sm-1, .gx-sm-1 { + --bs-gutter-x: 0.25rem + } + + .g-sm-1, .gy-sm-1 { + --bs-gutter-y: 0.25rem + } + + .g-sm-2, .gx-sm-2 { + --bs-gutter-x: 0.5rem + } + + .g-sm-2, .gy-sm-2 { + --bs-gutter-y: 0.5rem + } + + .g-sm-3, .gx-sm-3 { + --bs-gutter-x: 1rem + } + + .g-sm-3, .gy-sm-3 { + --bs-gutter-y: 1rem + } + + .g-sm-4, .gx-sm-4 { + --bs-gutter-x: 1.5rem + } + + .g-sm-4, .gy-sm-4 { + --bs-gutter-y: 1.5rem + } + + .g-sm-5, .gx-sm-5 { + --bs-gutter-x: 3rem + } + + .g-sm-5, .gy-sm-5 { + --bs-gutter-y: 3rem + } +} + +@media (min-width:768px) { + .col-md { + flex: 1 0 0% + } + + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto + } + + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100% + } + + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50% + } + + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.3333333333% + } + + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25% + } + + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20% + } + + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.6666666667% + } + + .col-md-auto { + flex: 0 0 auto; + width: auto + } + + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333% + } + + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667% + } + + .col-md-3 { + flex: 0 0 auto; + width: 25% + } + + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333% + } + + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667% + } + + .col-md-6 { + flex: 0 0 auto; + width: 50% + } + + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333% + } + + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667% + } + + .col-md-9 { + flex: 0 0 auto; + width: 75% + } + + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333% + } + + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667% + } + + .col-md-12 { + flex: 0 0 auto; + width: 100% + } + + .offset-md-0 { + margin-left: 0 + } + + .offset-md-1 { + margin-left: 8.33333333% + } + + .offset-md-2 { + margin-left: 16.66666667% + } + + .offset-md-3 { + margin-left: 25% + } + + .offset-md-4 { + margin-left: 33.33333333% + } + + .offset-md-5 { + margin-left: 41.66666667% + } + + .offset-md-6 { + margin-left: 50% + } + + .offset-md-7 { + margin-left: 58.33333333% + } + + .offset-md-8 { + margin-left: 66.66666667% + } + + .offset-md-9 { + margin-left: 75% + } + + .offset-md-10 { + margin-left: 83.33333333% + } + + .offset-md-11 { + margin-left: 91.66666667% + } + + .g-md-0, .gx-md-0 { + --bs-gutter-x: 0 + } + + .g-md-0, .gy-md-0 { + --bs-gutter-y: 0 + } + + .g-md-1, .gx-md-1 { + --bs-gutter-x: 0.25rem + } + + .g-md-1, .gy-md-1 { + --bs-gutter-y: 0.25rem + } + + .g-md-2, .gx-md-2 { + --bs-gutter-x: 0.5rem + } + + .g-md-2, .gy-md-2 { + --bs-gutter-y: 0.5rem + } + + .g-md-3, .gx-md-3 { + --bs-gutter-x: 1rem + } + + .g-md-3, .gy-md-3 { + --bs-gutter-y: 1rem + } + + .g-md-4, .gx-md-4 { + --bs-gutter-x: 1.5rem + } + + .g-md-4, .gy-md-4 { + --bs-gutter-y: 1.5rem + } + + .g-md-5, .gx-md-5 { + --bs-gutter-x: 3rem + } + + .g-md-5, .gy-md-5 { + --bs-gutter-y: 3rem + } +} + +@media (min-width:992px) { + .col-lg { + flex: 1 0 0% + } + + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto + } + + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100% + } + + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50% + } + + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.3333333333% + } + + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25% + } + + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20% + } + + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.6666666667% + } + + .col-lg-auto { + flex: 0 0 auto; + width: auto + } + + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333% + } + + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667% + } + + .col-lg-3 { + flex: 0 0 auto; + width: 25% + } + + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333% + } + + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667% + } + + .col-lg-6 { + flex: 0 0 auto; + width: 50% + } + + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333% + } + + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667% + } + + .col-lg-9 { + flex: 0 0 auto; + width: 75% + } + + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333% + } + + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667% + } + + .col-lg-12 { + flex: 0 0 auto; + width: 100% + } + + .offset-lg-0 { + margin-left: 0 + } + + .offset-lg-1 { + margin-left: 8.33333333% + } + + .offset-lg-2 { + margin-left: 16.66666667% + } + + .offset-lg-3 { + margin-left: 25% + } + + .offset-lg-4 { + margin-left: 33.33333333% + } + + .offset-lg-5 { + margin-left: 41.66666667% + } + + .offset-lg-6 { + margin-left: 50% + } + + .offset-lg-7 { + margin-left: 58.33333333% + } + + .offset-lg-8 { + margin-left: 66.66666667% + } + + .offset-lg-9 { + margin-left: 75% + } + + .offset-lg-10 { + margin-left: 83.33333333% + } + + .offset-lg-11 { + margin-left: 91.66666667% + } + + .g-lg-0, .gx-lg-0 { + --bs-gutter-x: 0 + } + + .g-lg-0, .gy-lg-0 { + --bs-gutter-y: 0 + } + + .g-lg-1, .gx-lg-1 { + --bs-gutter-x: 0.25rem + } + + .g-lg-1, .gy-lg-1 { + --bs-gutter-y: 0.25rem + } + + .g-lg-2, .gx-lg-2 { + --bs-gutter-x: 0.5rem + } + + .g-lg-2, .gy-lg-2 { + --bs-gutter-y: 0.5rem + } + + .g-lg-3, .gx-lg-3 { + --bs-gutter-x: 1rem + } + + .g-lg-3, .gy-lg-3 { + --bs-gutter-y: 1rem + } + + .g-lg-4, .gx-lg-4 { + --bs-gutter-x: 1.5rem + } + + .g-lg-4, .gy-lg-4 { + --bs-gutter-y: 1.5rem + } + + .g-lg-5, .gx-lg-5 { + --bs-gutter-x: 3rem + } + + .g-lg-5, .gy-lg-5 { + --bs-gutter-y: 3rem + } +} + +@media (min-width:1200px) { + .col-xl { + flex: 1 0 0% + } + + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto + } + + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100% + } + + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50% + } + + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.3333333333% + } + + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25% + } + + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20% + } + + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.6666666667% + } + + .col-xl-auto { + flex: 0 0 auto; + width: auto + } + + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333% + } + + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667% + } + + .col-xl-3 { + flex: 0 0 auto; + width: 25% + } + + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333% + } + + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667% + } + + .col-xl-6 { + flex: 0 0 auto; + width: 50% + } + + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333% + } + + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667% + } + + .col-xl-9 { + flex: 0 0 auto; + width: 75% + } + + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333% + } + + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667% + } + + .col-xl-12 { + flex: 0 0 auto; + width: 100% + } + + .offset-xl-0 { + margin-left: 0 + } + + .offset-xl-1 { + margin-left: 8.33333333% + } + + .offset-xl-2 { + margin-left: 16.66666667% + } + + .offset-xl-3 { + margin-left: 25% + } + + .offset-xl-4 { + margin-left: 33.33333333% + } + + .offset-xl-5 { + margin-left: 41.66666667% + } + + .offset-xl-6 { + margin-left: 50% + } + + .offset-xl-7 { + margin-left: 58.33333333% + } + + .offset-xl-8 { + margin-left: 66.66666667% + } + + .offset-xl-9 { + margin-left: 75% + } + + .offset-xl-10 { + margin-left: 83.33333333% + } + + .offset-xl-11 { + margin-left: 91.66666667% + } + + .g-xl-0, .gx-xl-0 { + --bs-gutter-x: 0 + } + + .g-xl-0, .gy-xl-0 { + --bs-gutter-y: 0 + } + + .g-xl-1, .gx-xl-1 { + --bs-gutter-x: 0.25rem + } + + .g-xl-1, .gy-xl-1 { + --bs-gutter-y: 0.25rem + } + + .g-xl-2, .gx-xl-2 { + --bs-gutter-x: 0.5rem + } + + .g-xl-2, .gy-xl-2 { + --bs-gutter-y: 0.5rem + } + + .g-xl-3, .gx-xl-3 { + --bs-gutter-x: 1rem + } + + .g-xl-3, .gy-xl-3 { + --bs-gutter-y: 1rem + } + + .g-xl-4, .gx-xl-4 { + --bs-gutter-x: 1.5rem + } + + .g-xl-4, .gy-xl-4 { + --bs-gutter-y: 1.5rem + } + + .g-xl-5, .gx-xl-5 { + --bs-gutter-x: 3rem + } + + .g-xl-5, .gy-xl-5 { + --bs-gutter-y: 3rem + } +} + +@media (min-width:1400px) { + .col-xxl { + flex: 1 0 0% + } + + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto + } + + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100% + } + + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50% + } + + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.3333333333% + } + + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25% + } + + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20% + } + + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.6666666667% + } + + .col-xxl-auto { + flex: 0 0 auto; + width: auto + } + + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333% + } + + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667% + } + + .col-xxl-3 { + flex: 0 0 auto; + width: 25% + } + + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333% + } + + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667% + } + + .col-xxl-6 { + flex: 0 0 auto; + width: 50% + } + + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333% + } + + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667% + } + + .col-xxl-9 { + flex: 0 0 auto; + width: 75% + } + + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333% + } + + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667% + } + + .col-xxl-12 { + flex: 0 0 auto; + width: 100% + } + + .offset-xxl-0 { + margin-left: 0 + } + + .offset-xxl-1 { + margin-left: 8.33333333% + } + + .offset-xxl-2 { + margin-left: 16.66666667% + } + + .offset-xxl-3 { + margin-left: 25% + } + + .offset-xxl-4 { + margin-left: 33.33333333% + } + + .offset-xxl-5 { + margin-left: 41.66666667% + } + + .offset-xxl-6 { + margin-left: 50% + } + + .offset-xxl-7 { + margin-left: 58.33333333% + } + + .offset-xxl-8 { + margin-left: 66.66666667% + } + + .offset-xxl-9 { + margin-left: 75% + } + + .offset-xxl-10 { + margin-left: 83.33333333% + } + + .offset-xxl-11 { + margin-left: 91.66666667% + } + + .g-xxl-0, .gx-xxl-0 { + --bs-gutter-x: 0 + } + + .g-xxl-0, .gy-xxl-0 { + --bs-gutter-y: 0 + } + + .g-xxl-1, .gx-xxl-1 { + --bs-gutter-x: 0.25rem + } + + .g-xxl-1, .gy-xxl-1 { + --bs-gutter-y: 0.25rem + } + + .g-xxl-2, .gx-xxl-2 { + --bs-gutter-x: 0.5rem + } + + .g-xxl-2, .gy-xxl-2 { + --bs-gutter-y: 0.5rem + } + + .g-xxl-3, .gx-xxl-3 { + --bs-gutter-x: 1rem + } + + .g-xxl-3, .gy-xxl-3 { + --bs-gutter-y: 1rem + } + + .g-xxl-4, .gx-xxl-4 { + --bs-gutter-x: 1.5rem + } + + .g-xxl-4, .gy-xxl-4 { + --bs-gutter-y: 1.5rem + } + + .g-xxl-5, .gx-xxl-5 { + --bs-gutter-x: 3rem + } + + .g-xxl-5, .gy-xxl-5 { + --bs-gutter-y: 3rem + } +} + +.table { + --bs-table-bg: transparent; + --bs-table-accent-bg: transparent; + --bs-table-striped-color: #212529; + --bs-table-striped-bg: rgba(0, 0, 0, 0.05); + --bs-table-active-color: #212529; + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: #212529; + --bs-table-hover-bg: rgba(0, 0, 0, 0.075); + width: 100%; + margin-bottom: 1rem; + color: #212529; + vertical-align: top; + border-color: #dee2e6 +} + + .table > :not(caption) > * > * { + padding: .5rem .5rem; + background-color: var(--bs-table-bg); + border-bottom-width: 1px; + box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg) + } + + .table > tbody { + vertical-align: inherit + } + + .table > thead { + vertical-align: bottom + } + + .table > :not(:last-child) > :last-child > * { + border-bottom-color: currentColor + } + +.caption-top { + caption-side: top +} + +.table-sm > :not(caption) > * > * { + padding: .25rem .25rem +} + +.table-bordered > :not(caption) > * { + border-width: 1px 0 +} + + .table-bordered > :not(caption) > * > * { + border-width: 0 1px + } + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0 +} + +.table-striped > tbody > tr:nth-of-type(odd) { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color) +} + +.table-active { + --bs-table-accent-bg: var(--bs-table-active-bg); + color: var(--bs-table-active-color) +} + +.table-hover > tbody > tr:hover { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color) +} + +.table-primary { + --bs-table-bg: #cfe2ff; + --bs-table-striped-bg: #c5d7f2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bacbe6; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfd1ec; + --bs-table-hover-color: #000; + color: #000; + border-color: #bacbe6 +} + +.table-secondary { + --bs-table-bg: #e2e3e5; + --bs-table-striped-bg: #d7d8da; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbccce; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d2d4; + --bs-table-hover-color: #000; + color: #000; + border-color: #cbccce +} + +.table-success { + --bs-table-bg: #d1e7dd; + --bs-table-striped-bg: #c7dbd2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bcd0c7; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c1d6cc; + --bs-table-hover-color: #000; + color: #000; + border-color: #bcd0c7 +} + +.table-info { + --bs-table-bg: #cff4fc; + --bs-table-striped-bg: #c5e8ef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #badce3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfe2e9; + --bs-table-hover-color: #000; + color: #000; + border-color: #badce3 +} + +.table-warning { + --bs-table-bg: #fff3cd; + --bs-table-striped-bg: #f2e7c3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dbb9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece1be; + --bs-table-hover-color: #000; + color: #000; + border-color: #e6dbb9 +} + +.table-danger { + --bs-table-bg: #f8d7da; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfc2c4 +} + +.table-light { + --bs-table-bg: #f8f9fa; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfe0e1 +} + +.table-dark { + --bs-table-bg: #212529; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: #fff; + border-color: #373b3e +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch +} + +@media (max-width:575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch + } +} + +@media (max-width:767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch + } +} + +@media (max-width:991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch + } +} + +@media (max-width:1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch + } +} + +@media (max-width:1399.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch + } +} + +.form-label { + margin-bottom: .5rem +} + +.col-form-label { + padding-top: calc(.375rem + 1px); + padding-bottom: calc(.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5 +} + +.col-form-label-lg { + padding-top: calc(.5rem + 1px); + padding-bottom: calc(.5rem + 1px); + font-size: 1.25rem +} + +.col-form-label-sm { + padding-top: calc(.25rem + 1px); + padding-bottom: calc(.25rem + 1px); + font-size: .875rem +} + +.form-text { + margin-top: .25rem; + font-size: .875em; + color: #6c757d +} + +.form-control { + display: block; + width: 100%; + padding: .375rem .75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border-radius: .25rem; + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .form-control { + transition: none + } +} + +.form-control[type=file] { + overflow: hidden +} + + .form-control[type=file]:not(:disabled):not([readonly]) { + cursor: pointer + } + +.form-control:focus { + color: #212529; + background-color: #fff; + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) +} + +.form-control::-webkit-date-and-time-value { + height: 1.5em +} + +.form-control::-moz-placeholder { + color: #6c757d; + opacity: 1 +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1 +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1 +} + +.form-control::file-selector-button { + padding: .375rem .75rem; + margin: -.375rem -.75rem; + -webkit-margin-end: .75rem; + margin-inline-end: .75rem; + color: #212529; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .form-control::file-selector-button { + transition: none + } +} + +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: #dde0e3 +} + +.form-control::-webkit-file-upload-button { + padding: .375rem .75rem; + margin: -.375rem -.75rem; + -webkit-margin-end: .75rem; + margin-inline-end: .75rem; + color: #212529; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + -webkit-transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .form-control::-webkit-file-upload-button { + -webkit-transition: none; + transition: none + } +} + +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: #dde0e3 +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: .375rem 0; + margin-bottom: 0; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0 +} + + .form-control-plaintext.form-control-lg, .form-control-plaintext.form-control-sm { + padding-right: 0; + padding-left: 0 + } + +.form-control-sm { + min-height: calc(1.5em + .5rem + 2px); + padding: .25rem .5rem; + font-size: .875rem; + border-radius: .2rem +} + + .form-control-sm::file-selector-button { + padding: .25rem .5rem; + margin: -.25rem -.5rem; + -webkit-margin-end: .5rem; + margin-inline-end: .5rem + } + + .form-control-sm::-webkit-file-upload-button { + padding: .25rem .5rem; + margin: -.25rem -.5rem; + -webkit-margin-end: .5rem; + margin-inline-end: .5rem + } + +.form-control-lg { + min-height: calc(1.5em + 1rem + 2px); + padding: .5rem 1rem; + font-size: 1.25rem; + border-radius: .3rem +} + + .form-control-lg::file-selector-button { + padding: .5rem 1rem; + margin: -.5rem -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem + } + + .form-control-lg::-webkit-file-upload-button { + padding: .5rem 1rem; + margin: -.5rem -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem + } + +textarea.form-control { + min-height: calc(1.5em + .75rem + 2px) +} + +textarea.form-control-sm { + min-height: calc(1.5em + .5rem + 2px) +} + +textarea.form-control-lg { + min-height: calc(1.5em + 1rem + 2px) +} + +.form-control-color { + width: 3rem; + height: auto; + padding: .375rem +} + + .form-control-color:not(:disabled):not([readonly]) { + cursor: pointer + } + + .form-control-color::-moz-color-swatch { + height: 1.5em; + border-radius: .25rem + } + + .form-control-color::-webkit-color-swatch { + height: 1.5em; + border-radius: .25rem + } + +.form-select { + display: block; + width: 100%; + padding: .375rem 2.25rem .375rem .75rem; + -moz-padding-start: calc(0.75rem - 3px); + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + background-color: #fff; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right .75rem center; + background-size: 16px 12px; + border: 1px solid #ced4da; + border-radius: .25rem; + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + +@media (prefers-reduced-motion:reduce) { + .form-select { + transition: none + } +} + +.form-select:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) +} + +.form-select[multiple], .form-select[size]:not([size="1"]) { + padding-right: .75rem; + background-image: none +} + +.form-select:disabled { + background-color: #e9ecef +} + +.form-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #212529 +} + +.form-select-sm { + padding-top: .25rem; + padding-bottom: .25rem; + padding-left: .5rem; + font-size: .875rem +} + +.form-select-lg { + padding-top: .5rem; + padding-bottom: .5rem; + padding-left: 1rem; + font-size: 1.25rem +} + +.form-check { + display: block; + min-height: 1.5rem; + padding-left: 1.5em; + margin-bottom: .125rem +} + + .form-check .form-check-input { + float: left; + margin-left: -1.5em + } + +.form-check-input { + width: 1em; + height: 1em; + margin-top: .25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0,0,0,.25); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-print-color-adjust: exact; + color-adjust: exact +} + + .form-check-input[type=checkbox] { + border-radius: .25em + } + + .form-check-input[type=radio] { + border-radius: 50% + } + + .form-check-input:active { + filter: brightness(90%) + } + + .form-check-input:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) + } + + .form-check-input:checked { + background-color: #0d6efd; + border-color: #0d6efd + } + + .form-check-input:checked[type=checkbox] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e") + } + + .form-check-input:checked[type=radio] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e") + } + + .form-check-input[type=checkbox]:indeterminate { + background-color: #0d6efd; + border-color: #0d6efd; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e") + } + + .form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: .5 + } + + .form-check-input:disabled ~ .form-check-label, .form-check-input[disabled] ~ .form-check-label { + opacity: .5 + } + +.form-switch { + padding-left: 2.5em +} + + .form-switch .form-check-input { + width: 2em; + margin-left: -2.5em; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + background-position: left center; + border-radius: 2em; + transition: background-position .15s ease-in-out + } + +@media (prefers-reduced-motion:reduce) { + .form-switch .form-check-input { + transition: none + } +} + +.form-switch .form-check-input:focus { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e") +} + +.form-switch .form-check-input:checked { + background-position: right center; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e") +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem +} + +.btn-check { + position: absolute; + clip: rect(0,0,0,0); + pointer-events: none +} + + .btn-check:disabled + .btn, .btn-check[disabled] + .btn { + pointer-events: none; + filter: none; + opacity: .65 + } + +.form-range { + width: 100%; + height: 1.5rem; + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none +} + + .form-range:focus { + outline: 0 + } + + .form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25) + } + + .form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25) + } + + .form-range::-moz-focus-outer { + border: 0 + } + + .form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -.25rem; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + -webkit-appearance: none; + appearance: none + } + +@media (prefers-reduced-motion:reduce) { + .form-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none + } +} + +.form-range::-webkit-slider-thumb:active { + background-color: #b6d4fe +} + +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: .5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem +} + +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + -moz-transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + -moz-appearance: none; + appearance: none +} + +@media (prefers-reduced-motion:reduce) { + .form-range::-moz-range-thumb { + -moz-transition: none; + transition: none + } +} + +.form-range::-moz-range-thumb:active { + background-color: #b6d4fe +} + +.form-range::-moz-range-track { + width: 100%; + height: .5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem +} + +.form-range:disabled { + pointer-events: none +} + + .form-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd + } + + .form-range:disabled::-moz-range-thumb { + background-color: #adb5bd + } + +.form-floating { + position: relative +} + + .form-floating > .form-control, .form-floating > .form-select { + height: calc(3.5rem + 2px); + line-height: 1.25 + } + + .form-floating > label { + position: absolute; + top: 0; + left: 0; + height: 100%; + padding: 1rem .75rem; + pointer-events: none; + border: 1px solid transparent; + transform-origin: 0 0; + transition: opacity .1s ease-in-out,transform .1s ease-in-out + } + +@media (prefers-reduced-motion:reduce) { + .form-floating > label { + transition: none + } +} + +.form-floating > .form-control { + padding: 1rem .75rem +} + + .form-floating > .form-control::-moz-placeholder { + color: transparent + } + + .form-floating > .form-control::placeholder { + color: transparent + } + + .form-floating > .form-control:not(:-moz-placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: .625rem + } + + .form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: .625rem + } + + .form-floating > .form-control:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: .625rem + } + +.form-floating > .form-select { + padding-top: 1.625rem; + padding-bottom: .625rem +} + +.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label { + opacity: .65; + transform: scale(.85) translateY(-.5rem) translateX(.15rem) +} + +.form-floating > .form-control:focus ~ label, .form-floating > .form-control:not(:placeholder-shown) ~ label, .form-floating > .form-select ~ label { + opacity: .65; + transform: scale(.85) translateY(-.5rem) translateX(.15rem) +} + +.form-floating > .form-control:-webkit-autofill ~ label { + opacity: .65; + transform: scale(.85) translateY(-.5rem) translateX(.15rem) +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100% +} + + .input-group > .form-control, .input-group > .form-select { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0 + } + + .input-group > .form-control:focus, .input-group > .form-select:focus { + z-index: 3 + } + + .input-group .btn { + position: relative; + z-index: 2 + } + + .input-group .btn:focus { + z-index: 3 + } + +.input-group-text { + display: flex; + align-items: center; + padding: .375rem .75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: .25rem +} + +.input-group-lg > .btn, .input-group-lg > .form-control, .input-group-lg > .form-select, .input-group-lg > .input-group-text { + padding: .5rem 1rem; + font-size: 1.25rem; + border-radius: .3rem +} + +.input-group-sm > .btn, .input-group-sm > .form-control, .input-group-sm > .form-select, .input-group-sm > .input-group-text { + padding: .25rem .5rem; + font-size: .875rem; + border-radius: .2rem +} + +.input-group-lg > .form-select, .input-group-sm > .form-select { + padding-right: 3rem +} + +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), .input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu) { + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), .input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu) { + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0 +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: .25rem; + font-size: .875em; + color: #198754 +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: .25rem .5rem; + margin-top: .1rem; + font-size: .875rem; + color: #fff; + background-color: rgba(25,135,84,.9); + border-radius: .25rem +} + +.is-valid ~ .valid-feedback, .is-valid ~ .valid-tooltip, .was-validated :valid ~ .valid-feedback, .was-validated :valid ~ .valid-tooltip { + display: block +} + +.form-control.is-valid, .was-validated .form-control:valid { + border-color: #198754; + padding-right: calc(1.5em + .75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(.375em + .1875rem) center; + background-size: calc(.75em + .375rem) calc(.75em + .375rem) +} + + .form-control.is-valid:focus, .was-validated .form-control:valid:focus { + border-color: #198754; + box-shadow: 0 0 0 .25rem rgba(25,135,84,.25) + } + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: calc(1.5em + .75rem); + background-position: top calc(.375em + .1875rem) right calc(.375em + .1875rem) +} + +.form-select.is-valid, .was-validated .form-select:valid { + border-color: #198754 +} + + .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"], .was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"] { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-position: right .75rem center,center right 2.25rem; + background-size: 16px 12px,calc(.75em + .375rem) calc(.75em + .375rem) + } + + .form-select.is-valid:focus, .was-validated .form-select:valid:focus { + border-color: #198754; + box-shadow: 0 0 0 .25rem rgba(25,135,84,.25) + } + +.form-check-input.is-valid, .was-validated .form-check-input:valid { + border-color: #198754 +} + + .form-check-input.is-valid:checked, .was-validated .form-check-input:valid:checked { + background-color: #198754 + } + + .form-check-input.is-valid:focus, .was-validated .form-check-input:valid:focus { + box-shadow: 0 0 0 .25rem rgba(25,135,84,.25) + } + + .form-check-input.is-valid ~ .form-check-label, .was-validated .form-check-input:valid ~ .form-check-label { + color: #198754 + } + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: .5em +} + +.input-group .form-control.is-valid, .input-group .form-select.is-valid, .was-validated .input-group .form-control:valid, .was-validated .input-group .form-select:valid { + z-index: 1 +} + + .input-group .form-control.is-valid:focus, .input-group .form-select.is-valid:focus, .was-validated .input-group .form-control:valid:focus, .was-validated .input-group .form-select:valid:focus { + z-index: 3 + } + +.invalid-feedback { + display: none; + width: 100%; + margin-top: .25rem; + font-size: .875em; + color: #dc3545 +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: .25rem .5rem; + margin-top: .1rem; + font-size: .875rem; + color: #fff; + background-color: rgba(220,53,69,.9); + border-radius: .25rem +} + +.is-invalid ~ .invalid-feedback, .is-invalid ~ .invalid-tooltip, .was-validated :invalid ~ .invalid-feedback, .was-validated :invalid ~ .invalid-tooltip { + display: block +} + +.form-control.is-invalid, .was-validated .form-control:invalid { + border-color: #dc3545; + padding-right: calc(1.5em + .75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(.375em + .1875rem) center; + background-size: calc(.75em + .375rem) calc(.75em + .375rem) +} + + .form-control.is-invalid:focus, .was-validated .form-control:invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 .25rem rgba(220,53,69,.25) + } + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: calc(1.5em + .75rem); + background-position: top calc(.375em + .1875rem) right calc(.375em + .1875rem) +} + +.form-select.is-invalid, .was-validated .form-select:invalid { + border-color: #dc3545 +} + + .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"], .was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"] { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-position: right .75rem center,center right 2.25rem; + background-size: 16px 12px,calc(.75em + .375rem) calc(.75em + .375rem) + } + + .form-select.is-invalid:focus, .was-validated .form-select:invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 .25rem rgba(220,53,69,.25) + } + +.form-check-input.is-invalid, .was-validated .form-check-input:invalid { + border-color: #dc3545 +} + + .form-check-input.is-invalid:checked, .was-validated .form-check-input:invalid:checked { + background-color: #dc3545 + } + + .form-check-input.is-invalid:focus, .was-validated .form-check-input:invalid:focus { + box-shadow: 0 0 0 .25rem rgba(220,53,69,.25) + } + + .form-check-input.is-invalid ~ .form-check-label, .was-validated .form-check-input:invalid ~ .form-check-label { + color: #dc3545 + } + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: .5em +} + +.input-group .form-control.is-invalid, .input-group .form-select.is-invalid, .was-validated .input-group .form-control:invalid, .was-validated .input-group .form-select:invalid { + z-index: 2 +} + + .input-group .form-control.is-invalid:focus, .input-group .form-select.is-invalid:focus, .was-validated .input-group .form-control:invalid:focus, .was-validated .input-group .form-select:invalid:focus { + z-index: 3 + } + +.btn { + display: inline-block; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: center; + text-decoration: none; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: .375rem .75rem; + font-size: 1rem; + border-radius: .25rem; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .btn { + transition: none + } +} + +.btn:hover { + color: #212529 +} + +.btn-check:focus + .btn, .btn:focus { + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) +} + +.btn.disabled, .btn:disabled, fieldset:disabled .btn { + pointer-events: none; + opacity: .65 +} + +.btn-primary { + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd +} + + .btn-primary:hover { + color: #fff; + background-color: #0b5ed7; + border-color: #0a58ca + } + + .btn-check:focus + .btn-primary, .btn-primary:focus { + color: #fff; + background-color: #0b5ed7; + border-color: #0a58ca; + box-shadow: 0 0 0 .25rem rgba(49,132,253,.5) + } + + .btn-check:active + .btn-primary, .btn-check:checked + .btn-primary, .btn-primary.active, .btn-primary:active, .show > .btn-primary.dropdown-toggle { + color: #fff; + background-color: #0a58ca; + border-color: #0a53be + } + + .btn-check:active + .btn-primary:focus, .btn-check:checked + .btn-primary:focus, .btn-primary.active:focus, .btn-primary:active:focus, .show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(49,132,253,.5) + } + + .btn-primary.disabled, .btn-primary:disabled { + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd + } + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d +} + + .btn-secondary:hover { + color: #fff; + background-color: #5c636a; + border-color: #565e64 + } + + .btn-check:focus + .btn-secondary, .btn-secondary:focus { + color: #fff; + background-color: #5c636a; + border-color: #565e64; + box-shadow: 0 0 0 .25rem rgba(130,138,145,.5) + } + + .btn-check:active + .btn-secondary, .btn-check:checked + .btn-secondary, .btn-secondary.active, .btn-secondary:active, .show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #565e64; + border-color: #51585e + } + + .btn-check:active + .btn-secondary:focus, .btn-check:checked + .btn-secondary:focus, .btn-secondary.active:focus, .btn-secondary:active:focus, .show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(130,138,145,.5) + } + + .btn-secondary.disabled, .btn-secondary:disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d + } + +.btn-success { + color: #fff; + background-color: #198754; + border-color: #198754 +} + + .btn-success:hover { + color: #fff; + background-color: #157347; + border-color: #146c43 + } + + .btn-check:focus + .btn-success, .btn-success:focus { + color: #fff; + background-color: #157347; + border-color: #146c43; + box-shadow: 0 0 0 .25rem rgba(60,153,110,.5) + } + + .btn-check:active + .btn-success, .btn-check:checked + .btn-success, .btn-success.active, .btn-success:active, .show > .btn-success.dropdown-toggle { + color: #fff; + background-color: #146c43; + border-color: #13653f + } + + .btn-check:active + .btn-success:focus, .btn-check:checked + .btn-success:focus, .btn-success.active:focus, .btn-success:active:focus, .show > .btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(60,153,110,.5) + } + + .btn-success.disabled, .btn-success:disabled { + color: #fff; + background-color: #198754; + border-color: #198754 + } + +.btn-info { + color: #000; + background-color: #0dcaf0; + border-color: #0dcaf0 +} + + .btn-info:hover { + color: #000; + background-color: #31d2f2; + border-color: #25cff2 + } + + .btn-check:focus + .btn-info, .btn-info:focus { + color: #000; + background-color: #31d2f2; + border-color: #25cff2; + box-shadow: 0 0 0 .25rem rgba(11,172,204,.5) + } + + .btn-check:active + .btn-info, .btn-check:checked + .btn-info, .btn-info.active, .btn-info:active, .show > .btn-info.dropdown-toggle { + color: #000; + background-color: #3dd5f3; + border-color: #25cff2 + } + + .btn-check:active + .btn-info:focus, .btn-check:checked + .btn-info:focus, .btn-info.active:focus, .btn-info:active:focus, .show > .btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(11,172,204,.5) + } + + .btn-info.disabled, .btn-info:disabled { + color: #000; + background-color: #0dcaf0; + border-color: #0dcaf0 + } + +.btn-warning { + color: #000; + background-color: #ffc107; + border-color: #ffc107 +} + + .btn-warning:hover { + color: #000; + background-color: #ffca2c; + border-color: #ffc720 + } + + .btn-check:focus + .btn-warning, .btn-warning:focus { + color: #000; + background-color: #ffca2c; + border-color: #ffc720; + box-shadow: 0 0 0 .25rem rgba(217,164,6,.5) + } + + .btn-check:active + .btn-warning, .btn-check:checked + .btn-warning, .btn-warning.active, .btn-warning:active, .show > .btn-warning.dropdown-toggle { + color: #000; + background-color: #ffcd39; + border-color: #ffc720 + } + + .btn-check:active + .btn-warning:focus, .btn-check:checked + .btn-warning:focus, .btn-warning.active:focus, .btn-warning:active:focus, .show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(217,164,6,.5) + } + + .btn-warning.disabled, .btn-warning:disabled { + color: #000; + background-color: #ffc107; + border-color: #ffc107 + } + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545 +} + + .btn-danger:hover { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37 + } + + .btn-check:focus + .btn-danger, .btn-danger:focus { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37; + box-shadow: 0 0 0 .25rem rgba(225,83,97,.5) + } + + .btn-check:active + .btn-danger, .btn-check:checked + .btn-danger, .btn-danger.active, .btn-danger:active, .show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #b02a37; + border-color: #a52834 + } + + .btn-check:active + .btn-danger:focus, .btn-check:checked + .btn-danger:focus, .btn-danger.active:focus, .btn-danger:active:focus, .show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(225,83,97,.5) + } + + .btn-danger.disabled, .btn-danger:disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545 + } + +.btn-light { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa +} + + .btn-light:hover { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb + } + + .btn-check:focus + .btn-light, .btn-light:focus { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; + box-shadow: 0 0 0 .25rem rgba(211,212,213,.5) + } + + .btn-check:active + .btn-light, .btn-check:checked + .btn-light, .btn-light.active, .btn-light:active, .show > .btn-light.dropdown-toggle { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb + } + + .btn-check:active + .btn-light:focus, .btn-check:checked + .btn-light:focus, .btn-light.active:focus, .btn-light:active:focus, .show > .btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(211,212,213,.5) + } + + .btn-light.disabled, .btn-light:disabled { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa + } + +.btn-dark { + color: #fff; + background-color: #212529; + border-color: #212529 +} + + .btn-dark:hover { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21 + } + + .btn-check:focus + .btn-dark, .btn-dark:focus { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21; + box-shadow: 0 0 0 .25rem rgba(66,70,73,.5) + } + + .btn-check:active + .btn-dark, .btn-check:checked + .btn-dark, .btn-dark.active, .btn-dark:active, .show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1a1e21; + border-color: #191c1f + } + + .btn-check:active + .btn-dark:focus, .btn-check:checked + .btn-dark:focus, .btn-dark.active:focus, .btn-dark:active:focus, .show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 .25rem rgba(66,70,73,.5) + } + + .btn-dark.disabled, .btn-dark:disabled { + color: #fff; + background-color: #212529; + border-color: #212529 + } + +.btn-outline-primary { + color: #0d6efd; + border-color: #0d6efd +} + + .btn-outline-primary:hover { + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd + } + + .btn-check:focus + .btn-outline-primary, .btn-outline-primary:focus { + box-shadow: 0 0 0 .25rem rgba(13,110,253,.5) + } + + .btn-check:active + .btn-outline-primary, .btn-check:checked + .btn-outline-primary, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show, .btn-outline-primary:active { + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd + } + + .btn-check:active + .btn-outline-primary:focus, .btn-check:checked + .btn-outline-primary:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus, .btn-outline-primary:active:focus { + box-shadow: 0 0 0 .25rem rgba(13,110,253,.5) + } + + .btn-outline-primary.disabled, .btn-outline-primary:disabled { + color: #0d6efd; + background-color: transparent + } + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d +} + + .btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d + } + + .btn-check:focus + .btn-outline-secondary, .btn-outline-secondary:focus { + box-shadow: 0 0 0 .25rem rgba(108,117,125,.5) + } + + .btn-check:active + .btn-outline-secondary, .btn-check:checked + .btn-outline-secondary, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show, .btn-outline-secondary:active { + color: #fff; + background-color: #6c757d; + border-color: #6c757d + } + + .btn-check:active + .btn-outline-secondary:focus, .btn-check:checked + .btn-outline-secondary:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus, .btn-outline-secondary:active:focus { + box-shadow: 0 0 0 .25rem rgba(108,117,125,.5) + } + + .btn-outline-secondary.disabled, .btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent + } + +.btn-outline-success { + color: #198754; + border-color: #198754 +} + + .btn-outline-success:hover { + color: #fff; + background-color: #198754; + border-color: #198754 + } + + .btn-check:focus + .btn-outline-success, .btn-outline-success:focus { + box-shadow: 0 0 0 .25rem rgba(25,135,84,.5) + } + + .btn-check:active + .btn-outline-success, .btn-check:checked + .btn-outline-success, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show, .btn-outline-success:active { + color: #fff; + background-color: #198754; + border-color: #198754 + } + + .btn-check:active + .btn-outline-success:focus, .btn-check:checked + .btn-outline-success:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus, .btn-outline-success:active:focus { + box-shadow: 0 0 0 .25rem rgba(25,135,84,.5) + } + + .btn-outline-success.disabled, .btn-outline-success:disabled { + color: #198754; + background-color: transparent + } + +.btn-outline-info { + color: #0dcaf0; + border-color: #0dcaf0 +} + + .btn-outline-info:hover { + color: #000; + background-color: #0dcaf0; + border-color: #0dcaf0 + } + + .btn-check:focus + .btn-outline-info, .btn-outline-info:focus { + box-shadow: 0 0 0 .25rem rgba(13,202,240,.5) + } + + .btn-check:active + .btn-outline-info, .btn-check:checked + .btn-outline-info, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show, .btn-outline-info:active { + color: #000; + background-color: #0dcaf0; + border-color: #0dcaf0 + } + + .btn-check:active + .btn-outline-info:focus, .btn-check:checked + .btn-outline-info:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus, .btn-outline-info:active:focus { + box-shadow: 0 0 0 .25rem rgba(13,202,240,.5) + } + + .btn-outline-info.disabled, .btn-outline-info:disabled { + color: #0dcaf0; + background-color: transparent + } + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107 +} + + .btn-outline-warning:hover { + color: #000; + background-color: #ffc107; + border-color: #ffc107 + } + + .btn-check:focus + .btn-outline-warning, .btn-outline-warning:focus { + box-shadow: 0 0 0 .25rem rgba(255,193,7,.5) + } + + .btn-check:active + .btn-outline-warning, .btn-check:checked + .btn-outline-warning, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show, .btn-outline-warning:active { + color: #000; + background-color: #ffc107; + border-color: #ffc107 + } + + .btn-check:active + .btn-outline-warning:focus, .btn-check:checked + .btn-outline-warning:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus, .btn-outline-warning:active:focus { + box-shadow: 0 0 0 .25rem rgba(255,193,7,.5) + } + + .btn-outline-warning.disabled, .btn-outline-warning:disabled { + color: #ffc107; + background-color: transparent + } + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545 +} + + .btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545 + } + + .btn-check:focus + .btn-outline-danger, .btn-outline-danger:focus { + box-shadow: 0 0 0 .25rem rgba(220,53,69,.5) + } + + .btn-check:active + .btn-outline-danger, .btn-check:checked + .btn-outline-danger, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show, .btn-outline-danger:active { + color: #fff; + background-color: #dc3545; + border-color: #dc3545 + } + + .btn-check:active + .btn-outline-danger:focus, .btn-check:checked + .btn-outline-danger:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus, .btn-outline-danger:active:focus { + box-shadow: 0 0 0 .25rem rgba(220,53,69,.5) + } + + .btn-outline-danger.disabled, .btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent + } + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa +} + + .btn-outline-light:hover { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa + } + + .btn-check:focus + .btn-outline-light, .btn-outline-light:focus { + box-shadow: 0 0 0 .25rem rgba(248,249,250,.5) + } + + .btn-check:active + .btn-outline-light, .btn-check:checked + .btn-outline-light, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show, .btn-outline-light:active { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa + } + + .btn-check:active + .btn-outline-light:focus, .btn-check:checked + .btn-outline-light:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus, .btn-outline-light:active:focus { + box-shadow: 0 0 0 .25rem rgba(248,249,250,.5) + } + + .btn-outline-light.disabled, .btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent + } + +.btn-outline-dark { + color: #212529; + border-color: #212529 +} + + .btn-outline-dark:hover { + color: #fff; + background-color: #212529; + border-color: #212529 + } + + .btn-check:focus + .btn-outline-dark, .btn-outline-dark:focus { + box-shadow: 0 0 0 .25rem rgba(33,37,41,.5) + } + + .btn-check:active + .btn-outline-dark, .btn-check:checked + .btn-outline-dark, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show, .btn-outline-dark:active { + color: #fff; + background-color: #212529; + border-color: #212529 + } + + .btn-check:active + .btn-outline-dark:focus, .btn-check:checked + .btn-outline-dark:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus, .btn-outline-dark:active:focus { + box-shadow: 0 0 0 .25rem rgba(33,37,41,.5) + } + + .btn-outline-dark.disabled, .btn-outline-dark:disabled { + color: #212529; + background-color: transparent + } + +.btn-link { + font-weight: 400; + color: #0d6efd; + text-decoration: underline +} + + .btn-link:hover { + color: #0a58ca + } + + .btn-link.disabled, .btn-link:disabled { + color: #6c757d + } + +.btn-group-lg > .btn, .btn-lg { + padding: .5rem 1rem; + font-size: 1.25rem; + border-radius: .3rem +} + +.btn-group-sm > .btn, .btn-sm { + padding: .25rem .5rem; + font-size: .875rem; + border-radius: .2rem +} + +.fade { + transition: opacity .15s linear +} + +@media (prefers-reduced-motion:reduce) { + .fade { + transition: none + } +} + +.fade:not(.show) { + opacity: 0 +} + +.collapse:not(.show) { + display: none +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height .35s ease +} + +@media (prefers-reduced-motion:reduce) { + .collapsing { + transition: none + } +} + +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width .35s ease +} + +@media (prefers-reduced-motion:reduce) { + .collapsing.collapse-horizontal { + transition: none + } +} + +.dropdown, .dropend, .dropstart, .dropup { + position: relative +} + +.dropdown-toggle { + white-space: nowrap +} + + .dropdown-toggle::after { + display: inline-block; + margin-left: .255em; + vertical-align: .255em; + content: ""; + border-top: .3em solid; + border-right: .3em solid transparent; + border-bottom: 0; + border-left: .3em solid transparent + } + + .dropdown-toggle:empty::after { + margin-left: 0 + } + +.dropdown-menu { + position: absolute; + z-index: 1000; + display: none; + min-width: 10rem; + padding: .5rem 0; + margin: 0; + font-size: 1rem; + color: #212529; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.15); + border-radius: .25rem +} + + .dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: .125rem + } + +.dropdown-menu-start { + --bs-position: start +} + + .dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0 + } + +.dropdown-menu-end { + --bs-position: end +} + + .dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto + } + +@media (min-width:576px) { + .dropdown-menu-sm-start { + --bs-position: start + } + + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0 + } + + .dropdown-menu-sm-end { + --bs-position: end + } + + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto + } +} + +@media (min-width:768px) { + .dropdown-menu-md-start { + --bs-position: start + } + + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0 + } + + .dropdown-menu-md-end { + --bs-position: end + } + + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto + } +} + +@media (min-width:992px) { + .dropdown-menu-lg-start { + --bs-position: start + } + + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0 + } + + .dropdown-menu-lg-end { + --bs-position: end + } + + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto + } +} + +@media (min-width:1200px) { + .dropdown-menu-xl-start { + --bs-position: start + } + + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0 + } + + .dropdown-menu-xl-end { + --bs-position: end + } + + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto + } +} + +@media (min-width:1400px) { + .dropdown-menu-xxl-start { + --bs-position: start + } + + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0 + } + + .dropdown-menu-xxl-end { + --bs-position: end + } + + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto + } +} + +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: .125rem +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: .255em; + vertical-align: .255em; + content: ""; + border-top: 0; + border-right: .3em solid transparent; + border-bottom: .3em solid; + border-left: .3em solid transparent +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0 +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: .125rem +} + +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: .255em; + vertical-align: .255em; + content: ""; + border-top: .3em solid transparent; + border-right: 0; + border-bottom: .3em solid transparent; + border-left: .3em solid +} + +.dropend .dropdown-toggle:empty::after { + margin-left: 0 +} + +.dropend .dropdown-toggle::after { + vertical-align: 0 +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: .125rem +} + +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: .255em; + vertical-align: .255em; + content: "" +} + +.dropstart .dropdown-toggle::after { + display: none +} + +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: .255em; + vertical-align: .255em; + content: ""; + border-top: .3em solid transparent; + border-right: .3em solid; + border-bottom: .3em solid transparent +} + +.dropstart .dropdown-toggle:empty::after { + margin-left: 0 +} + +.dropstart .dropdown-toggle::before { + vertical-align: 0 +} + +.dropdown-divider { + height: 0; + margin: .5rem 0; + overflow: hidden; + border-top: 1px solid rgba(0,0,0,.15) +} + +.dropdown-item { + display: block; + width: 100%; + padding: .25rem 1rem; + clear: both; + font-weight: 400; + color: #212529; + text-align: inherit; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border: 0 +} + + .dropdown-item:focus, .dropdown-item:hover { + color: #1e2125; + background-color: #e9ecef + } + + .dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #0d6efd + } + + .dropdown-item.disabled, .dropdown-item:disabled { + color: #adb5bd; + pointer-events: none; + background-color: transparent + } + +.dropdown-menu.show { + display: block +} + +.dropdown-header { + display: block; + padding: .5rem 1rem; + margin-bottom: 0; + font-size: .875rem; + color: #6c757d; + white-space: nowrap +} + +.dropdown-item-text { + display: block; + padding: .25rem 1rem; + color: #212529 +} + +.dropdown-menu-dark { + color: #dee2e6; + background-color: #343a40; + border-color: rgba(0,0,0,.15) +} + + .dropdown-menu-dark .dropdown-item { + color: #dee2e6 + } + + .dropdown-menu-dark .dropdown-item:focus, .dropdown-menu-dark .dropdown-item:hover { + color: #fff; + background-color: rgba(255,255,255,.15) + } + + .dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active { + color: #fff; + background-color: #0d6efd + } + + .dropdown-menu-dark .dropdown-item.disabled, .dropdown-menu-dark .dropdown-item:disabled { + color: #adb5bd + } + + .dropdown-menu-dark .dropdown-divider { + border-color: rgba(0,0,0,.15) + } + + .dropdown-menu-dark .dropdown-item-text { + color: #dee2e6 + } + + .dropdown-menu-dark .dropdown-header { + color: #adb5bd + } + +.btn-group, .btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle +} + + .btn-group-vertical > .btn, .btn-group > .btn { + position: relative; + flex: 1 1 auto + } + + .btn-group-vertical > .btn-check:checked + .btn, .btn-group-vertical > .btn-check:focus + .btn, .btn-group-vertical > .btn.active, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:hover, .btn-group > .btn-check:checked + .btn, .btn-group > .btn-check:focus + .btn, .btn-group > .btn.active, .btn-group > .btn:active, .btn-group > .btn:focus, .btn-group > .btn:hover { + z-index: 1 + } + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start +} + + .btn-toolbar .input-group { + width: auto + } + +.btn-group > .btn-group:not(:first-child), .btn-group > .btn:not(:first-child) { + margin-left: -1px +} + +.btn-group > .btn-group:not(:last-child) > .btn, .btn-group > .btn:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.btn-group > .btn-group:not(:first-child) > .btn, .btn-group > .btn:nth-child(n+3), .btn-group > :not(.btn-check) + .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0 +} + +.dropdown-toggle-split { + padding-right: .5625rem; + padding-left: .5625rem +} + + .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after { + margin-left: 0 + } + +.dropstart .dropdown-toggle-split::before { + margin-right: 0 +} + +.btn-group-sm > .btn + .dropdown-toggle-split, .btn-sm + .dropdown-toggle-split { + padding-right: .375rem; + padding-left: .375rem +} + +.btn-group-lg > .btn + .dropdown-toggle-split, .btn-lg + .dropdown-toggle-split { + padding-right: .75rem; + padding-left: .75rem +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center +} + + .btn-group-vertical > .btn, .btn-group-vertical > .btn-group { + width: 100% + } + + .btn-group-vertical > .btn-group:not(:first-child), .btn-group-vertical > .btn:not(:first-child) { + margin-top: -1px + } + + .btn-group-vertical > .btn-group:not(:last-child) > .btn, .btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0 + } + + .btn-group-vertical > .btn-group:not(:first-child) > .btn, .btn-group-vertical > .btn ~ .btn { + border-top-left-radius: 0; + border-top-right-radius: 0 + } + +.nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none +} + +.nav-link { + display: block; + padding: .5rem 1rem; + color: #0d6efd; + text-decoration: none; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .nav-link { + transition: none + } +} + +.nav-link:focus, .nav-link:hover { + color: #0a58ca +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6 +} + + .nav-tabs .nav-link { + margin-bottom: -1px; + background: 0 0; + border: 1px solid transparent; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem + } + + .nav-tabs .nav-link:focus, .nav-tabs .nav-link:hover { + border-color: #e9ecef #e9ecef #dee2e6; + isolation: isolate + } + + .nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent + } + + .nav-tabs .nav-item.show .nav-link, .nav-tabs .nav-link.active { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff + } + + .nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0 + } + +.nav-pills .nav-link { + background: 0 0; + border: 0; + border-radius: .25rem +} + + .nav-pills .nav-link.active, .nav-pills .show > .nav-link { + color: #fff; + background-color: #0d6efd + } + +.nav-fill .nav-item, .nav-fill > .nav-link { + flex: 1 1 auto; + text-align: center +} + +.nav-justified .nav-item, .nav-justified > .nav-link { + flex-basis: 0; + flex-grow: 1; + text-align: center +} + + .nav-fill .nav-item .nav-link, .nav-justified .nav-item .nav-link { + width: 100% + } + +.tab-content > .tab-pane { + display: none +} + +.tab-content > .active { + display: block +} + +.navbar { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding-top: .5rem; + padding-bottom: .5rem +} + + .navbar > .container, .navbar > .container-fluid, .navbar > .container-lg, .navbar > .container-md, .navbar > .container-sm, .navbar > .container-xl, .navbar > .container-xxl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between + } + +.navbar-brand { + padding-top: .3125rem; + padding-bottom: .3125rem; + margin-right: 1rem; + font-size: 1.25rem; + text-decoration: none; + white-space: nowrap +} + +.navbar-nav { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none +} + + .navbar-nav .nav-link { + padding-right: 0; + padding-left: 0 + } + + .navbar-nav .dropdown-menu { + position: static + } + +.navbar-text { + padding-top: .5rem; + padding-bottom: .5rem +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center +} + +.navbar-toggler { + padding: .25rem .75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: .25rem; + transition: box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .navbar-toggler { + transition: none + } +} + +.navbar-toggler:hover { + text-decoration: none +} + +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 .25rem +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-repeat: no-repeat; + background-position: center; + background-size: 100% +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height,75vh); + overflow-y: auto +} + +@media (min-width:576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start + } + + .navbar-expand-sm .navbar-nav { + flex-direction: row + } + + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand-sm .navbar-toggler { + display: none + } + + .navbar-expand-sm .offcanvas-header { + display: none + } + + .navbar-expand-sm .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand-sm .offcanvas-bottom, .navbar-expand-sm .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } +} + +@media (min-width:768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start + } + + .navbar-expand-md .navbar-nav { + flex-direction: row + } + + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand-md .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand-md .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand-md .navbar-toggler { + display: none + } + + .navbar-expand-md .offcanvas-header { + display: none + } + + .navbar-expand-md .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand-md .offcanvas-bottom, .navbar-expand-md .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } +} + +@media (min-width:992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start + } + + .navbar-expand-lg .navbar-nav { + flex-direction: row + } + + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand-lg .navbar-toggler { + display: none + } + + .navbar-expand-lg .offcanvas-header { + display: none + } + + .navbar-expand-lg .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand-lg .offcanvas-bottom, .navbar-expand-lg .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } +} + +@media (min-width:1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start + } + + .navbar-expand-xl .navbar-nav { + flex-direction: row + } + + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand-xl .navbar-toggler { + display: none + } + + .navbar-expand-xl .offcanvas-header { + display: none + } + + .navbar-expand-xl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand-xl .offcanvas-bottom, .navbar-expand-xl .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } +} + +@media (min-width:1400px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start + } + + .navbar-expand-xxl .navbar-nav { + flex-direction: row + } + + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand-xxl .navbar-toggler { + display: none + } + + .navbar-expand-xxl .offcanvas-header { + display: none + } + + .navbar-expand-xxl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand-xxl .offcanvas-bottom, .navbar-expand-xxl .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } +} + +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start +} + + .navbar-expand .navbar-nav { + flex-direction: row + } + + .navbar-expand .navbar-nav .dropdown-menu { + position: absolute + } + + .navbar-expand .navbar-nav .nav-link { + padding-right: .5rem; + padding-left: .5rem + } + + .navbar-expand .navbar-nav-scroll { + overflow: visible + } + + .navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto + } + + .navbar-expand .navbar-toggler { + display: none + } + + .navbar-expand .offcanvas-header { + display: none + } + + .navbar-expand .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none + } + + .navbar-expand .offcanvas-bottom, .navbar-expand .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0 + } + + .navbar-expand .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible + } + +.navbar-light .navbar-brand { + color: rgba(0,0,0,.9) +} + + .navbar-light .navbar-brand:focus, .navbar-light .navbar-brand:hover { + color: rgba(0,0,0,.9) + } + +.navbar-light .navbar-nav .nav-link { + color: rgba(0,0,0,.55) +} + + .navbar-light .navbar-nav .nav-link:focus, .navbar-light .navbar-nav .nav-link:hover { + color: rgba(0,0,0,.7) + } + + .navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0,0,0,.3) + } + + .navbar-light .navbar-nav .nav-link.active, .navbar-light .navbar-nav .show > .nav-link { + color: rgba(0,0,0,.9) + } + +.navbar-light .navbar-toggler { + color: rgba(0,0,0,.55); + border-color: rgba(0,0,0,.1) +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") +} + +.navbar-light .navbar-text { + color: rgba(0,0,0,.55) +} + + .navbar-light .navbar-text a, .navbar-light .navbar-text a:focus, .navbar-light .navbar-text a:hover { + color: rgba(0,0,0,.9) + } + +.navbar-dark .navbar-brand { + color: #fff +} + + .navbar-dark .navbar-brand:focus, .navbar-dark .navbar-brand:hover { + color: #fff + } + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255,255,255,.55) +} + + .navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover { + color: rgba(255,255,255,.75) + } + + .navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255,255,255,.25) + } + + .navbar-dark .navbar-nav .nav-link.active, .navbar-dark .navbar-nav .show > .nav-link { + color: #fff + } + +.navbar-dark .navbar-toggler { + color: rgba(255,255,255,.55); + border-color: rgba(255,255,255,.1) +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") +} + +.navbar-dark .navbar-text { + color: rgba(255,255,255,.55) +} + + .navbar-dark .navbar-text a, .navbar-dark .navbar-text a:focus, .navbar-dark .navbar-text a:hover { + color: #fff + } + +.card { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 1px solid rgba(0,0,0,.125); + border-radius: .25rem +} + + .card > hr { + margin-right: 0; + margin-left: 0 + } + + .card > .list-group { + border-top: inherit; + border-bottom: inherit + } + + .card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: calc(.25rem - 1px); + border-top-right-radius: calc(.25rem - 1px) + } + + .card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: calc(.25rem - 1px); + border-bottom-left-radius: calc(.25rem - 1px) + } + + .card > .card-header + .list-group, .card > .list-group + .card-footer { + border-top: 0 + } + +.card-body { + flex: 1 1 auto; + padding: 1rem 1rem +} + +.card-title { + margin-bottom: .5rem +} + +.card-subtitle { + margin-top: -.25rem; + margin-bottom: 0 +} + +.card-text:last-child { + margin-bottom: 0 +} + +.card-link + .card-link { + margin-left: 1rem +} + +.card-header { + padding: .5rem 1rem; + margin-bottom: 0; + background-color: rgba(0,0,0,.03); + border-bottom: 1px solid rgba(0,0,0,.125) +} + + .card-header:first-child { + border-radius: calc(.25rem - 1px) calc(.25rem - 1px) 0 0 + } + +.card-footer { + padding: .5rem 1rem; + background-color: rgba(0,0,0,.03); + border-top: 1px solid rgba(0,0,0,.125) +} + + .card-footer:last-child { + border-radius: 0 0 calc(.25rem - 1px) calc(.25rem - 1px) + } + +.card-header-tabs { + margin-right: -.5rem; + margin-bottom: -.5rem; + margin-left: -.5rem; + border-bottom: 0 +} + +.card-header-pills { + margin-right: -.5rem; + margin-left: -.5rem +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1rem; + border-radius: calc(.25rem - 1px) +} + +.card-img, .card-img-bottom, .card-img-top { + width: 100% +} + +.card-img, .card-img-top { + border-top-left-radius: calc(.25rem - 1px); + border-top-right-radius: calc(.25rem - 1px) +} + +.card-img, .card-img-bottom { + border-bottom-right-radius: calc(.25rem - 1px); + border-bottom-left-radius: calc(.25rem - 1px) +} + +.card-group > .card { + margin-bottom: .75rem +} + +@media (min-width:576px) { + .card-group { + display: flex; + flex-flow: row wrap + } + + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0 + } + + .card-group > .card + .card { + margin-left: 0; + border-left: 0 + } + + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0 + } + + .card-group > .card:not(:last-child) .card-header, .card-group > .card:not(:last-child) .card-img-top { + border-top-right-radius: 0 + } + + .card-group > .card:not(:last-child) .card-footer, .card-group > .card:not(:last-child) .card-img-bottom { + border-bottom-right-radius: 0 + } + + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0 + } + + .card-group > .card:not(:first-child) .card-header, .card-group > .card:not(:first-child) .card-img-top { + border-top-left-radius: 0 + } + + .card-group > .card:not(:first-child) .card-footer, .card-group > .card:not(:first-child) .card-img-bottom { + border-bottom-left-radius: 0 + } +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: 1rem 1.25rem; + font-size: 1rem; + color: #212529; + text-align: left; + background-color: #fff; + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease +} + +@media (prefers-reduced-motion:reduce) { + .accordion-button { + transition: none + } +} + +.accordion-button:not(.collapsed) { + color: #0c63e4; + background-color: #e7f1ff; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.125) +} + + .accordion-button:not(.collapsed)::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + transform: rotate(-180deg) + } + +.accordion-button::after { + flex-shrink: 0; + width: 1.25rem; + height: 1.25rem; + margin-left: auto; + content: ""; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-size: 1.25rem; + transition: transform .2s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .accordion-button::after { + transition: none + } +} + +.accordion-button:hover { + z-index: 2 +} + +.accordion-button:focus { + z-index: 3; + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) +} + +.accordion-header { + margin-bottom: 0 +} + +.accordion-item { + background-color: #fff; + border: 1px solid rgba(0,0,0,.125) +} + + .accordion-item:first-of-type { + border-top-left-radius: .25rem; + border-top-right-radius: .25rem + } + + .accordion-item:first-of-type .accordion-button { + border-top-left-radius: calc(.25rem - 1px); + border-top-right-radius: calc(.25rem - 1px) + } + + .accordion-item:not(:first-of-type) { + border-top: 0 + } + + .accordion-item:last-of-type { + border-bottom-right-radius: .25rem; + border-bottom-left-radius: .25rem + } + + .accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: calc(.25rem - 1px); + border-bottom-left-radius: calc(.25rem - 1px) + } + + .accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: .25rem; + border-bottom-left-radius: .25rem + } + +.accordion-body { + padding: 1rem 1.25rem +} + +.accordion-flush .accordion-collapse { + border-width: 0 +} + +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0 +} + + .accordion-flush .accordion-item:first-child { + border-top: 0 + } + + .accordion-flush .accordion-item:last-child { + border-bottom: 0 + } + + .accordion-flush .accordion-item .accordion-button { + border-radius: 0 + } + +.breadcrumb { + display: flex; + flex-wrap: wrap; + padding: 0 0; + margin-bottom: 1rem; + list-style: none +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: .5rem +} + + .breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: .5rem; + color: #6c757d; + content: var(--bs-breadcrumb-divider, "/") + } + +.breadcrumb-item.active { + color: #6c757d +} + +.pagination { + display: flex; + padding-left: 0; + list-style: none +} + +.page-link { + position: relative; + display: block; + color: #0d6efd; + text-decoration: none; + background-color: #fff; + border: 1px solid #dee2e6; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .page-link { + transition: none + } +} + +.page-link:hover { + z-index: 2; + color: #0a58ca; + background-color: #e9ecef; + border-color: #dee2e6 +} + +.page-link:focus { + z-index: 3; + color: #0a58ca; + background-color: #e9ecef; + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25) +} + +.page-item:not(:first-child) .page-link { + margin-left: -1px +} + +.page-item.active .page-link { + z-index: 3; + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd +} + +.page-item.disabled .page-link { + color: #6c757d; + pointer-events: none; + background-color: #fff; + border-color: #dee2e6 +} + +.page-link { + padding: .375rem .75rem +} + +.page-item:first-child .page-link { + border-top-left-radius: .25rem; + border-bottom-left-radius: .25rem +} + +.page-item:last-child .page-link { + border-top-right-radius: .25rem; + border-bottom-right-radius: .25rem +} + +.pagination-lg .page-link { + padding: .75rem 1.5rem; + font-size: 1.25rem +} + +.pagination-lg .page-item:first-child .page-link { + border-top-left-radius: .3rem; + border-bottom-left-radius: .3rem +} + +.pagination-lg .page-item:last-child .page-link { + border-top-right-radius: .3rem; + border-bottom-right-radius: .3rem +} + +.pagination-sm .page-link { + padding: .25rem .5rem; + font-size: .875rem +} + +.pagination-sm .page-item:first-child .page-link { + border-top-left-radius: .2rem; + border-bottom-left-radius: .2rem +} + +.pagination-sm .page-item:last-child .page-link { + border-top-right-radius: .2rem; + border-bottom-right-radius: .2rem +} + +.badge { + display: inline-block; + padding: .35em .65em; + font-size: .75em; + font-weight: 700; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25rem +} + + .badge:empty { + display: none + } + +.btn .badge { + position: relative; + top: -1px +} + +.alert { + position: relative; + padding: 1rem 1rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: .25rem +} + +.alert-heading { + color: inherit +} + +.alert-link { + font-weight: 700 +} + +.alert-dismissible { + padding-right: 3rem +} + + .alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.25rem 1rem + } + +.alert-primary { + color: #084298; + background-color: #cfe2ff; + border-color: #b6d4fe +} + + .alert-primary .alert-link { + color: #06357a + } + +.alert-secondary { + color: #41464b; + background-color: #e2e3e5; + border-color: #d3d6d8 +} + + .alert-secondary .alert-link { + color: #34383c + } + +.alert-success { + color: #0f5132; + background-color: #d1e7dd; + border-color: #badbcc +} + + .alert-success .alert-link { + color: #0c4128 + } + +.alert-info { + color: #055160; + background-color: #cff4fc; + border-color: #b6effb +} + + .alert-info .alert-link { + color: #04414d + } + +.alert-warning { + color: #664d03; + background-color: #fff3cd; + border-color: #ffecb5 +} + + .alert-warning .alert-link { + color: #523e02 + } + +.alert-danger { + color: #842029; + background-color: #f8d7da; + border-color: #f5c2c7 +} + + .alert-danger .alert-link { + color: #6a1a21 + } + +.alert-light { + color: #636464; + background-color: #fefefe; + border-color: #fdfdfe +} + + .alert-light .alert-link { + color: #4f5050 + } + +.alert-dark { + color: #141619; + background-color: #d3d3d4; + border-color: #bcbebf +} + + .alert-dark .alert-link { + color: #101214 + } + +@-webkit-keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem + } +} + +@keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem + } +} + +.progress { + display: flex; + height: 1rem; + overflow: hidden; + font-size: .75rem; + background-color: #e9ecef; + border-radius: .25rem +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #0d6efd; + transition: width .6s ease +} + +@media (prefers-reduced-motion:reduce) { + .progress-bar { + transition: none + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent); + background-size: 1rem 1rem +} + +.progress-bar-animated { + -webkit-animation: 1s linear infinite progress-bar-stripes; + animation: 1s linear infinite progress-bar-stripes +} + +@media (prefers-reduced-motion:reduce) { + .progress-bar-animated { + -webkit-animation: none; + animation: none + } +} + +.list-group { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: .25rem +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section +} + + .list-group-numbered > li::before { + content: counters(section, ".") ". "; + counter-increment: section + } + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit +} + + .list-group-item-action:focus, .list-group-item-action:hover { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa + } + + .list-group-item-action:active { + color: #212529; + background-color: #e9ecef + } + +.list-group-item { + position: relative; + display: block; + padding: .5rem 1rem; + color: #212529; + text-decoration: none; + background-color: #fff; + border: 1px solid rgba(0,0,0,.125) +} + + .list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit + } + + .list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit + } + + .list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff + } + + .list-group-item.active { + z-index: 2; + color: #fff; + background-color: #0d6efd; + border-color: #0d6efd + } + + .list-group-item + .list-group-item { + border-top-width: 0 + } + + .list-group-item + .list-group-item.active { + margin-top: -1px; + border-top-width: 1px + } + +.list-group-horizontal { + flex-direction: row +} + + .list-group-horizontal > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } + +@media (min-width:576px) { + .list-group-horizontal-sm { + flex-direction: row + } + + .list-group-horizontal-sm > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal-sm > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } +} + +@media (min-width:768px) { + .list-group-horizontal-md { + flex-direction: row + } + + .list-group-horizontal-md > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal-md > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } +} + +@media (min-width:992px) { + .list-group-horizontal-lg { + flex-direction: row + } + + .list-group-horizontal-lg > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal-lg > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } +} + +@media (min-width:1200px) { + .list-group-horizontal-xl { + flex-direction: row + } + + .list-group-horizontal-xl > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal-xl > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } +} + +@media (min-width:1400px) { + .list-group-horizontal-xxl { + flex-direction: row + } + + .list-group-horizontal-xxl > .list-group-item:first-child { + border-bottom-left-radius: .25rem; + border-top-right-radius: 0 + } + + .list-group-horizontal-xxl > .list-group-item:last-child { + border-top-right-radius: .25rem; + border-bottom-left-radius: 0 + } + + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0 + } + + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0 + } + + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px + } +} + +.list-group-flush { + border-radius: 0 +} + + .list-group-flush > .list-group-item { + border-width: 0 0 1px + } + + .list-group-flush > .list-group-item:last-child { + border-bottom-width: 0 + } + +.list-group-item-primary { + color: #084298; + background-color: #cfe2ff +} + + .list-group-item-primary.list-group-item-action:focus, .list-group-item-primary.list-group-item-action:hover { + color: #084298; + background-color: #bacbe6 + } + + .list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #084298; + border-color: #084298 + } + +.list-group-item-secondary { + color: #41464b; + background-color: #e2e3e5 +} + + .list-group-item-secondary.list-group-item-action:focus, .list-group-item-secondary.list-group-item-action:hover { + color: #41464b; + background-color: #cbccce + } + + .list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #41464b; + border-color: #41464b + } + +.list-group-item-success { + color: #0f5132; + background-color: #d1e7dd +} + + .list-group-item-success.list-group-item-action:focus, .list-group-item-success.list-group-item-action:hover { + color: #0f5132; + background-color: #bcd0c7 + } + + .list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #0f5132; + border-color: #0f5132 + } + +.list-group-item-info { + color: #055160; + background-color: #cff4fc +} + + .list-group-item-info.list-group-item-action:focus, .list-group-item-info.list-group-item-action:hover { + color: #055160; + background-color: #badce3 + } + + .list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #055160; + border-color: #055160 + } + +.list-group-item-warning { + color: #664d03; + background-color: #fff3cd +} + + .list-group-item-warning.list-group-item-action:focus, .list-group-item-warning.list-group-item-action:hover { + color: #664d03; + background-color: #e6dbb9 + } + + .list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #664d03; + border-color: #664d03 + } + +.list-group-item-danger { + color: #842029; + background-color: #f8d7da +} + + .list-group-item-danger.list-group-item-action:focus, .list-group-item-danger.list-group-item-action:hover { + color: #842029; + background-color: #dfc2c4 + } + + .list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #842029; + border-color: #842029 + } + +.list-group-item-light { + color: #636464; + background-color: #fefefe +} + + .list-group-item-light.list-group-item-action:focus, .list-group-item-light.list-group-item-action:hover { + color: #636464; + background-color: #e5e5e5 + } + + .list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #636464; + border-color: #636464 + } + +.list-group-item-dark { + color: #141619; + background-color: #d3d3d4 +} + + .list-group-item-dark.list-group-item-action:focus, .list-group-item-dark.list-group-item-action:hover { + color: #141619; + background-color: #bebebf + } + + .list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #141619; + border-color: #141619 + } + +.btn-close { + box-sizing: content-box; + width: 1em; + height: 1em; + padding: .25em .25em; + color: #000; + background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; + border: 0; + border-radius: .25rem; + opacity: .5 +} + + .btn-close:hover { + color: #000; + text-decoration: none; + opacity: .75 + } + + .btn-close:focus { + outline: 0; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25); + opacity: 1 + } + + .btn-close.disabled, .btn-close:disabled { + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + opacity: .25 + } + +.btn-close-white { + filter: invert(1) grayscale(100%) brightness(200%) +} + +.toast { + width: 350px; + max-width: 100%; + font-size: .875rem; + pointer-events: auto; + background-color: rgba(255,255,255,.85); + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.1); + box-shadow: 0 .5rem 1rem rgba(0,0,0,.15); + border-radius: .25rem +} + + .toast.showing { + opacity: 0 + } + + .toast:not(.show) { + display: none + } + +.toast-container { + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 100%; + pointer-events: none +} + + .toast-container > :not(:last-child) { + margin-bottom: .75rem + } + +.toast-header { + display: flex; + align-items: center; + padding: .5rem .75rem; + color: #6c757d; + background-color: rgba(255,255,255,.85); + background-clip: padding-box; + border-bottom: 1px solid rgba(0,0,0,.05); + border-top-left-radius: calc(.25rem - 1px); + border-top-right-radius: calc(.25rem - 1px) +} + + .toast-header .btn-close { + margin-right: -.375rem; + margin-left: .75rem + } + +.toast-body { + padding: .75rem; + word-wrap: break-word +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1055; + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0 +} + +.modal-dialog { + position: relative; + width: auto; + margin: .5rem; + pointer-events: none +} + +.modal.fade .modal-dialog { + transition: transform .3s ease-out; + transform: translate(0,-50px) +} + +@media (prefers-reduced-motion:reduce) { + .modal.fade .modal-dialog { + transition: none + } +} + +.modal.show .modal-dialog { + transform: none +} + +.modal.modal-static .modal-dialog { + transform: scale(1.02) +} + +.modal-dialog-scrollable { + height: calc(100% - 1rem) +} + + .modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden + } + + .modal-dialog-scrollable .modal-body { + overflow-y: auto + } + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - 1rem) +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.2); + border-radius: .3rem; + outline: 0 +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + width: 100vw; + height: 100vh; + background-color: #000 +} + + .modal-backdrop.fade { + opacity: 0 + } + + .modal-backdrop.show { + opacity: .5 + } + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: calc(.3rem - 1px); + border-top-right-radius: calc(.3rem - 1px) +} + + .modal-header .btn-close { + padding: .5rem .5rem; + margin: -.5rem -.5rem -.5rem auto + } + +.modal-title { + margin-bottom: 0; + line-height: 1.5 +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: 1rem +} + +.modal-footer { + display: flex; + flex-wrap: wrap; + flex-shrink: 0; + align-items: center; + justify-content: flex-end; + padding: .75rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: calc(.3rem - 1px); + border-bottom-left-radius: calc(.3rem - 1px) +} + + .modal-footer > * { + margin: .25rem + } + +@media (min-width:576px) { + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto + } + + .modal-dialog-scrollable { + height: calc(100% - 3.5rem) + } + + .modal-dialog-centered { + min-height: calc(100% - 3.5rem) + } + + .modal-sm { + max-width: 300px + } +} + +@media (min-width:992px) { + .modal-lg, .modal-xl { + max-width: 800px + } +} + +@media (min-width:1200px) { + .modal-xl { + max-width: 1140px + } +} + +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 +} + + .modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen .modal-header { + border-radius: 0 + } + + .modal-fullscreen .modal-body { + overflow-y: auto + } + + .modal-fullscreen .modal-footer { + border-radius: 0 + } + +@media (max-width:575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 + } + + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen-sm-down .modal-header { + border-radius: 0 + } + + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto + } + + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0 + } +} + +@media (max-width:767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 + } + + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen-md-down .modal-header { + border-radius: 0 + } + + .modal-fullscreen-md-down .modal-body { + overflow-y: auto + } + + .modal-fullscreen-md-down .modal-footer { + border-radius: 0 + } +} + +@media (max-width:991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 + } + + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen-lg-down .modal-header { + border-radius: 0 + } + + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto + } + + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0 + } +} + +@media (max-width:1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 + } + + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen-xl-down .modal-header { + border-radius: 0 + } + + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto + } + + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0 + } +} + +@media (max-width:1399.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0 + } + + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0 + } + + .modal-fullscreen-xxl-down .modal-header { + border-radius: 0 + } + + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto + } + + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0 + } +} + +.tooltip { + position: absolute; + z-index: 1080; + display: block; + margin: 0; + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: .875rem; + word-wrap: break-word; + opacity: 0 +} + + .tooltip.show { + opacity: .9 + } + + .tooltip .tooltip-arrow { + position: absolute; + display: block; + width: .8rem; + height: .4rem + } + + .tooltip .tooltip-arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid + } + +.bs-tooltip-auto[data-popper-placement^=top], .bs-tooltip-top { + padding: .4rem 0 +} + + .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow, .bs-tooltip-top .tooltip-arrow { + bottom: 0 + } + + .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before, .bs-tooltip-top .tooltip-arrow::before { + top: -1px; + border-width: .4rem .4rem 0; + border-top-color: #000 + } + +.bs-tooltip-auto[data-popper-placement^=right], .bs-tooltip-end { + padding: 0 .4rem +} + + .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow, .bs-tooltip-end .tooltip-arrow { + left: 0; + width: .4rem; + height: .8rem + } + + .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before, .bs-tooltip-end .tooltip-arrow::before { + right: -1px; + border-width: .4rem .4rem .4rem 0; + border-right-color: #000 + } + +.bs-tooltip-auto[data-popper-placement^=bottom], .bs-tooltip-bottom { + padding: .4rem 0 +} + + .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow, .bs-tooltip-bottom .tooltip-arrow { + top: 0 + } + + .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before, .bs-tooltip-bottom .tooltip-arrow::before { + bottom: -1px; + border-width: 0 .4rem .4rem; + border-bottom-color: #000 + } + +.bs-tooltip-auto[data-popper-placement^=left], .bs-tooltip-start { + padding: 0 .4rem +} + + .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow, .bs-tooltip-start .tooltip-arrow { + right: 0; + width: .4rem; + height: .8rem + } + + .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before, .bs-tooltip-start .tooltip-arrow::before { + left: -1px; + border-width: .4rem 0 .4rem .4rem; + border-left-color: #000 + } + +.tooltip-inner { + max-width: 200px; + padding: .25rem .5rem; + color: #fff; + text-align: center; + background-color: #000; + border-radius: .25rem +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1070; + display: block; + max-width: 276px; + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: .875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.2); + border-radius: .3rem +} + + .popover .popover-arrow { + position: absolute; + display: block; + width: 1rem; + height: .5rem + } + + .popover .popover-arrow::after, .popover .popover-arrow::before { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid + } + +.bs-popover-auto[data-popper-placement^=top] > .popover-arrow, .bs-popover-top > .popover-arrow { + bottom: calc(-.5rem - 1px) +} + + .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::before { + bottom: 0; + border-width: .5rem .5rem 0; + border-top-color: rgba(0,0,0,.25) + } + + .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after, .bs-popover-top > .popover-arrow::after { + bottom: 1px; + border-width: .5rem .5rem 0; + border-top-color: #fff + } + +.bs-popover-auto[data-popper-placement^=right] > .popover-arrow, .bs-popover-end > .popover-arrow { + left: calc(-.5rem - 1px); + width: .5rem; + height: 1rem +} + + .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::before { + left: 0; + border-width: .5rem .5rem .5rem 0; + border-right-color: rgba(0,0,0,.25) + } + + .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after, .bs-popover-end > .popover-arrow::after { + left: 1px; + border-width: .5rem .5rem .5rem 0; + border-right-color: #fff + } + +.bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow, .bs-popover-bottom > .popover-arrow { + top: calc(-.5rem - 1px) +} + + .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::before { + top: 0; + border-width: 0 .5rem .5rem .5rem; + border-bottom-color: rgba(0,0,0,.25) + } + + .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after, .bs-popover-bottom > .popover-arrow::after { + top: 1px; + border-width: 0 .5rem .5rem .5rem; + border-bottom-color: #fff + } + +.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before, .bs-popover-bottom .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -.5rem; + content: ""; + border-bottom: 1px solid #f0f0f0 +} + +.bs-popover-auto[data-popper-placement^=left] > .popover-arrow, .bs-popover-start > .popover-arrow { + right: calc(-.5rem - 1px); + width: .5rem; + height: 1rem +} + + .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::before { + right: 0; + border-width: .5rem 0 .5rem .5rem; + border-left-color: rgba(0,0,0,.25) + } + + .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after, .bs-popover-start > .popover-arrow::after { + right: 1px; + border-width: .5rem 0 .5rem .5rem; + border-left-color: #fff + } + +.popover-header { + padding: .5rem 1rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #f0f0f0; + border-bottom: 1px solid rgba(0,0,0,.2); + border-top-left-radius: calc(.3rem - 1px); + border-top-right-radius: calc(.3rem - 1px) +} + + .popover-header:empty { + display: none + } + +.popover-body { + padding: 1rem 1rem; + color: #212529 +} + +.carousel { + position: relative +} + + .carousel.pointer-event { + touch-action: pan-y + } + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden +} + + .carousel-inner::after { + display: block; + clear: both; + content: "" + } + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: transform .6s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .carousel-item { + transition: none + } +} + +.carousel-item-next, .carousel-item-prev, .carousel-item.active { + display: block +} + + .active.carousel-item-end, .carousel-item-next:not(.carousel-item-start) { + transform: translateX(100%) + } + + .active.carousel-item-start, .carousel-item-prev:not(.carousel-item-end) { + transform: translateX(-100%) + } + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none +} + + .carousel-fade .carousel-item-next.carousel-item-start, .carousel-fade .carousel-item-prev.carousel-item-end, .carousel-fade .carousel-item.active { + z-index: 1; + opacity: 1 + } + +.carousel-fade .active.carousel-item-end, .carousel-fade .active.carousel-item-start { + z-index: 0; + opacity: 0; + transition: opacity 0s .6s +} + +@media (prefers-reduced-motion:reduce) { + .carousel-fade .active.carousel-item-end, .carousel-fade .active.carousel-item-start { + transition: none + } +} + +.carousel-control-next, .carousel-control-prev { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 15%; + padding: 0; + color: #fff; + text-align: center; + background: 0 0; + border: 0; + opacity: .5; + transition: opacity .15s ease +} + +@media (prefers-reduced-motion:reduce) { + .carousel-control-next, .carousel-control-prev { + transition: none + } +} + +.carousel-control-next:focus, .carousel-control-next:hover, .carousel-control-prev:focus, .carousel-control-prev:hover { + color: #fff; + text-decoration: none; + outline: 0; + opacity: .9 +} + +.carousel-control-prev { + left: 0 +} + +.carousel-control-next { + right: 0 +} + +.carousel-control-next-icon, .carousel-control-prev-icon { + display: inline-block; + width: 2rem; + height: 2rem; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100% +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e") +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + margin-right: 15%; + margin-bottom: 1rem; + margin-left: 15%; + list-style: none +} + + .carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: .5; + transition: opacity .6s ease + } + +@media (prefers-reduced-motion:reduce) { + .carousel-indicators [data-bs-target] { + transition: none + } +} + +.carousel-indicators .active { + opacity: 1 +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 1.25rem; + left: 15%; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + color: #fff; + text-align: center +} + +.carousel-dark .carousel-control-next-icon, .carousel-dark .carousel-control-prev-icon { + filter: invert(1) grayscale(100) +} + +.carousel-dark .carousel-indicators [data-bs-target] { + background-color: #000 +} + +.carousel-dark .carousel-caption { + color: #000 +} + +@-webkit-keyframes spinner-border { + to { + transform: rotate(360deg) + } +} + +@keyframes spinner-border { + to { + transform: rotate(360deg) + } +} + +.spinner-border { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: -.125em; + border: .25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + -webkit-animation: .75s linear infinite spinner-border; + animation: .75s linear infinite spinner-border +} + +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: .2em +} + +@-webkit-keyframes spinner-grow { + 0% { + transform: scale(0) + } + + 50% { + opacity: 1; + transform: none + } +} + +@keyframes spinner-grow { + 0% { + transform: scale(0) + } + + 50% { + opacity: 1; + transform: none + } +} + +.spinner-grow { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: -.125em; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + -webkit-animation: .75s linear infinite spinner-grow; + animation: .75s linear infinite spinner-grow +} + +.spinner-grow-sm { + width: 1rem; + height: 1rem +} + +@media (prefers-reduced-motion:reduce) { + .spinner-border, .spinner-grow { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s + } +} + +.offcanvas { + position: fixed; + bottom: 0; + z-index: 1045; + display: flex; + flex-direction: column; + max-width: 100%; + visibility: hidden; + background-color: #fff; + background-clip: padding-box; + outline: 0; + transition: transform .3s ease-in-out +} + +@media (prefers-reduced-motion:reduce) { + .offcanvas { + transition: none + } +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000 +} + + .offcanvas-backdrop.fade { + opacity: 0 + } + + .offcanvas-backdrop.show { + opacity: .5 + } + +.offcanvas-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1rem +} + + .offcanvas-header .btn-close { + padding: .5rem .5rem; + margin-top: -.5rem; + margin-right: -.5rem; + margin-bottom: -.5rem + } + +.offcanvas-title { + margin-bottom: 0; + line-height: 1.5 +} + +.offcanvas-body { + flex-grow: 1; + padding: 1rem 1rem; + overflow-y: auto +} + +.offcanvas-start { + top: 0; + left: 0; + width: 400px; + border-right: 1px solid rgba(0,0,0,.2); + transform: translateX(-100%) +} + +.offcanvas-end { + top: 0; + right: 0; + width: 400px; + border-left: 1px solid rgba(0,0,0,.2); + transform: translateX(100%) +} + +.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: 30vh; + max-height: 100%; + border-bottom: 1px solid rgba(0,0,0,.2); + transform: translateY(-100%) +} + +.offcanvas-bottom { + right: 0; + left: 0; + height: 30vh; + max-height: 100%; + border-top: 1px solid rgba(0,0,0,.2); + transform: translateY(100%) +} + +.offcanvas.show { + transform: none +} + +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentColor; + opacity: .5 +} + + .placeholder.btn::before { + display: inline-block; + content: "" + } + +.placeholder-xs { + min-height: .6em +} + +.placeholder-sm { + min-height: .8em +} + +.placeholder-lg { + min-height: 1.2em +} + +.placeholder-glow .placeholder { + -webkit-animation: placeholder-glow 2s ease-in-out infinite; + animation: placeholder-glow 2s ease-in-out infinite +} + +@-webkit-keyframes placeholder-glow { + 50% { + opacity: .2 + } +} + +@keyframes placeholder-glow { + 50% { + opacity: .2 + } +} + +.placeholder-wave { + -webkit-mask-image: linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%); + mask-image: linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%); + -webkit-mask-size: 200% 100%; + mask-size: 200% 100%; + -webkit-animation: placeholder-wave 2s linear infinite; + animation: placeholder-wave 2s linear infinite +} + +@-webkit-keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0% + } +} + +@keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0% + } +} + +.clearfix::after { + display: block; + clear: both; + content: "" +} + +.link-primary { + color: #0d6efd +} + + .link-primary:focus, .link-primary:hover { + color: #0a58ca + } + +.link-secondary { + color: #6c757d +} + + .link-secondary:focus, .link-secondary:hover { + color: #565e64 + } + +.link-success { + color: #198754 +} + + .link-success:focus, .link-success:hover { + color: #146c43 + } + +.link-info { + color: #0dcaf0 +} + + .link-info:focus, .link-info:hover { + color: #3dd5f3 + } + +.link-warning { + color: #ffc107 +} + + .link-warning:focus, .link-warning:hover { + color: #ffcd39 + } + +.link-danger { + color: #dc3545 +} + + .link-danger:focus, .link-danger:hover { + color: #b02a37 + } + +.link-light { + color: #f8f9fa +} + + .link-light:focus, .link-light:hover { + color: #f9fafb + } + +.link-dark { + color: #212529 +} + + .link-dark:focus, .link-dark:hover { + color: #1a1e21 + } + +.ratio { + position: relative; + width: 100% +} + + .ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: "" + } + + .ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100% + } + +.ratio-1x1 { + --bs-aspect-ratio: 100% +} + +.ratio-4x3 { + --bs-aspect-ratio: calc(3 / 4 * 100%) +} + +.ratio-16x9 { + --bs-aspect-ratio: calc(9 / 16 * 100%) +} + +.ratio-21x9 { + --bs-aspect-ratio: calc(9 / 21 * 100%) +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030 +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030 +} + +.sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 +} + +@media (min-width:576px) { + .sticky-sm-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 + } +} + +@media (min-width:768px) { + .sticky-md-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 + } +} + +@media (min-width:992px) { + .sticky-lg-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 + } +} + +@media (min-width:1200px) { + .sticky-xl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 + } +} + +@media (min-width:1400px) { + .sticky-xxl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020 + } +} + +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch +} + +.visually-hidden, .visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0,0,0,0) !important; + white-space: nowrap !important; + border: 0 !important +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: "" +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentColor; + opacity: .25 +} + +.align-baseline { + vertical-align: baseline !important +} + +.align-top { + vertical-align: top !important +} + +.align-middle { + vertical-align: middle !important +} + +.align-bottom { + vertical-align: bottom !important +} + +.align-text-bottom { + vertical-align: text-bottom !important +} + +.align-text-top { + vertical-align: text-top !important +} + +.float-start { + float: left !important +} + +.float-end { + float: right !important +} + +.float-none { + float: none !important +} + +.opacity-0 { + opacity: 0 !important +} + +.opacity-25 { + opacity: .25 !important +} + +.opacity-50 { + opacity: .5 !important +} + +.opacity-75 { + opacity: .75 !important +} + +.opacity-100 { + opacity: 1 !important +} + +.overflow-auto { + overflow: auto !important +} + +.overflow-hidden { + overflow: hidden !important +} + +.overflow-visible { + overflow: visible !important +} + +.overflow-scroll { + overflow: scroll !important +} + +.d-inline { + display: inline !important +} + +.d-inline-block { + display: inline-block !important +} + +.d-block { + display: block !important +} + +.d-grid { + display: grid !important +} + +.d-table { + display: table !important +} + +.d-table-row { + display: table-row !important +} + +.d-table-cell { + display: table-cell !important +} + +.d-flex { + display: flex !important +} + +.d-inline-flex { + display: inline-flex !important +} + +.d-none { + display: none !important +} + +.shadow { + box-shadow: 0 .5rem 1rem rgba(0,0,0,.15) !important +} + +.shadow-sm { + box-shadow: 0 .125rem .25rem rgba(0,0,0,.075) !important +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0,0,0,.175) !important +} + +.shadow-none { + box-shadow: none !important +} + +.position-static { + position: static !important +} + +.position-relative { + position: relative !important +} + +.position-absolute { + position: absolute !important +} + +.position-fixed { + position: fixed !important +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important +} + +.top-0 { + top: 0 !important +} + +.top-50 { + top: 50% !important +} + +.top-100 { + top: 100% !important +} + +.bottom-0 { + bottom: 0 !important +} + +.bottom-50 { + bottom: 50% !important +} + +.bottom-100 { + bottom: 100% !important +} + +.start-0 { + left: 0 !important +} + +.start-50 { + left: 50% !important +} + +.start-100 { + left: 100% !important +} + +.end-0 { + right: 0 !important +} + +.end-50 { + right: 50% !important +} + +.end-100 { + right: 100% !important +} + +.translate-middle { + transform: translate(-50%,-50%) !important +} + +.translate-middle-x { + transform: translateX(-50%) !important +} + +.translate-middle-y { + transform: translateY(-50%) !important +} + +.border { + border: 1px solid #dee2e6 !important +} + +.border-0 { + border: 0 !important +} + +.border-top { + border-top: 1px solid #dee2e6 !important +} + +.border-top-0 { + border-top: 0 !important +} + +.border-end { + border-right: 1px solid #dee2e6 !important +} + +.border-end-0 { + border-right: 0 !important +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important +} + +.border-bottom-0 { + border-bottom: 0 !important +} + +.border-start { + border-left: 1px solid #dee2e6 !important +} + +.border-start-0 { + border-left: 0 !important +} + +.border-primary { + border-color: #0d6efd !important +} + +.border-secondary { + border-color: #6c757d !important +} + +.border-success { + border-color: #198754 !important +} + +.border-info { + border-color: #0dcaf0 !important +} + +.border-warning { + border-color: #ffc107 !important +} + +.border-danger { + border-color: #dc3545 !important +} + +.border-light { + border-color: #f8f9fa !important +} + +.border-dark { + border-color: #212529 !important +} + +.border-white { + border-color: #fff !important +} + +.border-1 { + border-width: 1px !important +} + +.border-2 { + border-width: 2px !important +} + +.border-3 { + border-width: 3px !important +} + +.border-4 { + border-width: 4px !important +} + +.border-5 { + border-width: 5px !important +} + +.w-25 { + width: 25% !important +} + +.w-50 { + width: 50% !important +} + +.w-75 { + width: 75% !important +} + +.w-100 { + width: 100% !important +} + +.w-auto { + width: auto !important +} + +.mw-100 { + max-width: 100% !important +} + +.vw-100 { + width: 100vw !important +} + +.min-vw-100 { + min-width: 100vw !important +} + +.h-25 { + height: 25% !important +} + +.h-50 { + height: 50% !important +} + +.h-75 { + height: 75% !important +} + +.h-100 { + height: 100% !important +} + +.h-auto { + height: auto !important +} + +.mh-100 { + max-height: 100% !important +} + +.vh-100 { + height: 100vh !important +} + +.min-vh-100 { + min-height: 100vh !important +} + +.flex-fill { + flex: 1 1 auto !important +} + +.flex-row { + flex-direction: row !important +} + +.flex-column { + flex-direction: column !important +} + +.flex-row-reverse { + flex-direction: row-reverse !important +} + +.flex-column-reverse { + flex-direction: column-reverse !important +} + +.flex-grow-0 { + flex-grow: 0 !important +} + +.flex-grow-1 { + flex-grow: 1 !important +} + +.flex-shrink-0 { + flex-shrink: 0 !important +} + +.flex-shrink-1 { + flex-shrink: 1 !important +} + +.flex-wrap { + flex-wrap: wrap !important +} + +.flex-nowrap { + flex-wrap: nowrap !important +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important +} + +.gap-0 { + gap: 0 !important +} + +.gap-1 { + gap: .25rem !important +} + +.gap-2 { + gap: .5rem !important +} + +.gap-3 { + gap: 1rem !important +} + +.gap-4 { + gap: 1.5rem !important +} + +.gap-5 { + gap: 3rem !important +} + +.justify-content-start { + justify-content: flex-start !important +} + +.justify-content-end { + justify-content: flex-end !important +} + +.justify-content-center { + justify-content: center !important +} + +.justify-content-between { + justify-content: space-between !important +} + +.justify-content-around { + justify-content: space-around !important +} + +.justify-content-evenly { + justify-content: space-evenly !important +} + +.align-items-start { + align-items: flex-start !important +} + +.align-items-end { + align-items: flex-end !important +} + +.align-items-center { + align-items: center !important +} + +.align-items-baseline { + align-items: baseline !important +} + +.align-items-stretch { + align-items: stretch !important +} + +.align-content-start { + align-content: flex-start !important +} + +.align-content-end { + align-content: flex-end !important +} + +.align-content-center { + align-content: center !important +} + +.align-content-between { + align-content: space-between !important +} + +.align-content-around { + align-content: space-around !important +} + +.align-content-stretch { + align-content: stretch !important +} + +.align-self-auto { + align-self: auto !important +} + +.align-self-start { + align-self: flex-start !important +} + +.align-self-end { + align-self: flex-end !important +} + +.align-self-center { + align-self: center !important +} + +.align-self-baseline { + align-self: baseline !important +} + +.align-self-stretch { + align-self: stretch !important +} + +.order-first { + order: -1 !important +} + +.order-0 { + order: 0 !important +} + +.order-1 { + order: 1 !important +} + +.order-2 { + order: 2 !important +} + +.order-3 { + order: 3 !important +} + +.order-4 { + order: 4 !important +} + +.order-5 { + order: 5 !important +} + +.order-last { + order: 6 !important +} + +.m-0 { + margin: 0 !important +} + +.m-1 { + margin: .25rem !important +} + +.m-2 { + margin: .5rem !important +} + +.m-3 { + margin: 1rem !important +} + +.m-4 { + margin: 1.5rem !important +} + +.m-5 { + margin: 3rem !important +} + +.m-auto { + margin: auto !important +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important +} + +.mx-1 { + margin-right: .25rem !important; + margin-left: .25rem !important +} + +.mx-2 { + margin-right: .5rem !important; + margin-left: .5rem !important +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important +} + +.my-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important +} + +.my-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important +} + +.mt-0 { + margin-top: 0 !important +} + +.mt-1 { + margin-top: .25rem !important +} + +.mt-2 { + margin-top: .5rem !important +} + +.mt-3 { + margin-top: 1rem !important +} + +.mt-4 { + margin-top: 1.5rem !important +} + +.mt-5 { + margin-top: 3rem !important +} + +.mt-auto { + margin-top: auto !important +} + +.me-0 { + margin-right: 0 !important +} + +.me-1 { + margin-right: .25rem !important +} + +.me-2 { + margin-right: .5rem !important +} + +.me-3 { + margin-right: 1rem !important +} + +.me-4 { + margin-right: 1.5rem !important +} + +.me-5 { + margin-right: 3rem !important +} + +.me-auto { + margin-right: auto !important +} + +.mb-0 { + margin-bottom: 0 !important +} + +.mb-1 { + margin-bottom: .25rem !important +} + +.mb-2 { + margin-bottom: .5rem !important +} + +.mb-3 { + margin-bottom: 1rem !important +} + +.mb-4 { + margin-bottom: 1.5rem !important +} + +.mb-5 { + margin-bottom: 3rem !important +} + +.mb-auto { + margin-bottom: auto !important +} + +.ms-0 { + margin-left: 0 !important +} + +.ms-1 { + margin-left: .25rem !important +} + +.ms-2 { + margin-left: .5rem !important +} + +.ms-3 { + margin-left: 1rem !important +} + +.ms-4 { + margin-left: 1.5rem !important +} + +.ms-5 { + margin-left: 3rem !important +} + +.ms-auto { + margin-left: auto !important +} + +.p-0 { + padding: 0 !important +} + +.p-1 { + padding: .25rem !important +} + +.p-2 { + padding: .5rem !important +} + +.p-3 { + padding: 1rem !important +} + +.p-4 { + padding: 1.5rem !important +} + +.p-5 { + padding: 3rem !important +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important +} + +.px-1 { + padding-right: .25rem !important; + padding-left: .25rem !important +} + +.px-2 { + padding-right: .5rem !important; + padding-left: .5rem !important +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important +} + +.py-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important +} + +.py-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important +} + +.pt-0 { + padding-top: 0 !important +} + +.pt-1 { + padding-top: .25rem !important +} + +.pt-2 { + padding-top: .5rem !important +} + +.pt-3 { + padding-top: 1rem !important +} + +.pt-4 { + padding-top: 1.5rem !important +} + +.pt-5 { + padding-top: 3rem !important +} + +.pe-0 { + padding-right: 0 !important +} + +.pe-1 { + padding-right: .25rem !important +} + +.pe-2 { + padding-right: .5rem !important +} + +.pe-3 { + padding-right: 1rem !important +} + +.pe-4 { + padding-right: 1.5rem !important +} + +.pe-5 { + padding-right: 3rem !important +} + +.pb-0 { + padding-bottom: 0 !important +} + +.pb-1 { + padding-bottom: .25rem !important +} + +.pb-2 { + padding-bottom: .5rem !important +} + +.pb-3 { + padding-bottom: 1rem !important +} + +.pb-4 { + padding-bottom: 1.5rem !important +} + +.pb-5 { + padding-bottom: 3rem !important +} + +.ps-0 { + padding-left: 0 !important +} + +.ps-1 { + padding-left: .25rem !important +} + +.ps-2 { + padding-left: .5rem !important +} + +.ps-3 { + padding-left: 1rem !important +} + +.ps-4 { + padding-left: 1.5rem !important +} + +.ps-5 { + padding-left: 3rem !important +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important +} + +.fs-1 { + font-size: calc(1.375rem + 1.5vw) !important +} + +.fs-2 { + font-size: calc(1.325rem + .9vw) !important +} + +.fs-3 { + font-size: calc(1.3rem + .6vw) !important +} + +.fs-4 { + font-size: calc(1.275rem + .3vw) !important +} + +.fs-5 { + font-size: 1.25rem !important +} + +.fs-6 { + font-size: 1rem !important +} + +.fst-italic { + font-style: italic !important +} + +.fst-normal { + font-style: normal !important +} + +.fw-light { + font-weight: 300 !important +} + +.fw-lighter { + font-weight: lighter !important +} + +.fw-normal { + font-weight: 400 !important +} + +.fw-bold { + font-weight: 700 !important +} + +.fw-bolder { + font-weight: bolder !important +} + +.lh-1 { + line-height: 1 !important +} + +.lh-sm { + line-height: 1.25 !important +} + +.lh-base { + line-height: 1.5 !important +} + +.lh-lg { + line-height: 2 !important +} + +.text-start { + text-align: left !important +} + +.text-end { + text-align: right !important +} + +.text-center { + text-align: center !important +} + +.text-decoration-none { + text-decoration: none !important +} + +.text-decoration-underline { + text-decoration: underline !important +} + +.text-decoration-line-through { + text-decoration: line-through !important +} + +.text-lowercase { + text-transform: lowercase !important +} + +.text-uppercase { + text-transform: uppercase !important +} + +.text-capitalize { + text-transform: capitalize !important +} + +.text-wrap { + white-space: normal !important +} + +.text-nowrap { + white-space: nowrap !important +} + +.text-break { + word-wrap: break-word !important; + word-break: break-word !important +} + +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb),var(--bs-text-opacity)) !important +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb),var(--bs-text-opacity)) !important +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb),var(--bs-text-opacity)) !important +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb),var(--bs-text-opacity)) !important +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb),var(--bs-text-opacity)) !important +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb),var(--bs-text-opacity)) !important +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb),var(--bs-text-opacity)) !important +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb),var(--bs-text-opacity)) !important +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb),var(--bs-text-opacity)) !important +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb),var(--bs-text-opacity)) !important +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-rgb),var(--bs-text-opacity)) !important +} + +.text-muted { + --bs-text-opacity: 1; + color: #6c757d !important +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0,0,0,.5) !important +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255,255,255,.5) !important +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important +} + +.text-opacity-25 { + --bs-text-opacity: 0.25 +} + +.text-opacity-50 { + --bs-text-opacity: 0.5 +} + +.text-opacity-75 { + --bs-text-opacity: 0.75 +} + +.text-opacity-100 { + --bs-text-opacity: 1 +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb),var(--bs-bg-opacity)) !important +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity)) !important +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb),var(--bs-bg-opacity)) !important +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb),var(--bs-bg-opacity)) !important +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb),var(--bs-bg-opacity)) !important +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb),var(--bs-bg-opacity)) !important +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb),var(--bs-bg-opacity)) !important +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb),var(--bs-bg-opacity)) !important +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb),var(--bs-bg-opacity)) !important +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb),var(--bs-bg-opacity)) !important +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-rgb),var(--bs-bg-opacity)) !important +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1 +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25 +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5 +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75 +} + +.bg-opacity-100 { + --bs-bg-opacity: 1 +} + +.bg-gradient { + background-image: var(--bs-gradient) !important +} + +.user-select-all { + -webkit-user-select: all !important; + -moz-user-select: all !important; + user-select: all !important +} + +.user-select-auto { + -webkit-user-select: auto !important; + -moz-user-select: auto !important; + user-select: auto !important +} + +.user-select-none { + -webkit-user-select: none !important; + -moz-user-select: none !important; + user-select: none !important +} + +.pe-none { + pointer-events: none !important +} + +.pe-auto { + pointer-events: auto !important +} + +.rounded { + border-radius: .25rem !important +} + +.rounded-0 { + border-radius: 0 !important +} + +.rounded-1 { + border-radius: .2rem !important +} + +.rounded-2 { + border-radius: .25rem !important +} + +.rounded-3 { + border-radius: .3rem !important +} + +.rounded-circle { + border-radius: 50% !important +} + +.rounded-pill { + border-radius: 50rem !important +} + +.rounded-top { + border-top-left-radius: .25rem !important; + border-top-right-radius: .25rem !important +} + +.rounded-end { + border-top-right-radius: .25rem !important; + border-bottom-right-radius: .25rem !important +} + +.rounded-bottom { + border-bottom-right-radius: .25rem !important; + border-bottom-left-radius: .25rem !important +} + +.rounded-start { + border-bottom-left-radius: .25rem !important; + border-top-left-radius: .25rem !important +} + +.visible { + visibility: visible !important +} + +.invisible { + visibility: hidden !important +} + +@media (min-width:576px) { + .float-sm-start { + float: left !important + } + + .float-sm-end { + float: right !important + } + + .float-sm-none { + float: none !important + } + + .d-sm-inline { + display: inline !important + } + + .d-sm-inline-block { + display: inline-block !important + } + + .d-sm-block { + display: block !important + } + + .d-sm-grid { + display: grid !important + } + + .d-sm-table { + display: table !important + } + + .d-sm-table-row { + display: table-row !important + } + + .d-sm-table-cell { + display: table-cell !important + } + + .d-sm-flex { + display: flex !important + } + + .d-sm-inline-flex { + display: inline-flex !important + } + + .d-sm-none { + display: none !important + } + + .flex-sm-fill { + flex: 1 1 auto !important + } + + .flex-sm-row { + flex-direction: row !important + } + + .flex-sm-column { + flex-direction: column !important + } + + .flex-sm-row-reverse { + flex-direction: row-reverse !important + } + + .flex-sm-column-reverse { + flex-direction: column-reverse !important + } + + .flex-sm-grow-0 { + flex-grow: 0 !important + } + + .flex-sm-grow-1 { + flex-grow: 1 !important + } + + .flex-sm-shrink-0 { + flex-shrink: 0 !important + } + + .flex-sm-shrink-1 { + flex-shrink: 1 !important + } + + .flex-sm-wrap { + flex-wrap: wrap !important + } + + .flex-sm-nowrap { + flex-wrap: nowrap !important + } + + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important + } + + .gap-sm-0 { + gap: 0 !important + } + + .gap-sm-1 { + gap: .25rem !important + } + + .gap-sm-2 { + gap: .5rem !important + } + + .gap-sm-3 { + gap: 1rem !important + } + + .gap-sm-4 { + gap: 1.5rem !important + } + + .gap-sm-5 { + gap: 3rem !important + } + + .justify-content-sm-start { + justify-content: flex-start !important + } + + .justify-content-sm-end { + justify-content: flex-end !important + } + + .justify-content-sm-center { + justify-content: center !important + } + + .justify-content-sm-between { + justify-content: space-between !important + } + + .justify-content-sm-around { + justify-content: space-around !important + } + + .justify-content-sm-evenly { + justify-content: space-evenly !important + } + + .align-items-sm-start { + align-items: flex-start !important + } + + .align-items-sm-end { + align-items: flex-end !important + } + + .align-items-sm-center { + align-items: center !important + } + + .align-items-sm-baseline { + align-items: baseline !important + } + + .align-items-sm-stretch { + align-items: stretch !important + } + + .align-content-sm-start { + align-content: flex-start !important + } + + .align-content-sm-end { + align-content: flex-end !important + } + + .align-content-sm-center { + align-content: center !important + } + + .align-content-sm-between { + align-content: space-between !important + } + + .align-content-sm-around { + align-content: space-around !important + } + + .align-content-sm-stretch { + align-content: stretch !important + } + + .align-self-sm-auto { + align-self: auto !important + } + + .align-self-sm-start { + align-self: flex-start !important + } + + .align-self-sm-end { + align-self: flex-end !important + } + + .align-self-sm-center { + align-self: center !important + } + + .align-self-sm-baseline { + align-self: baseline !important + } + + .align-self-sm-stretch { + align-self: stretch !important + } + + .order-sm-first { + order: -1 !important + } + + .order-sm-0 { + order: 0 !important + } + + .order-sm-1 { + order: 1 !important + } + + .order-sm-2 { + order: 2 !important + } + + .order-sm-3 { + order: 3 !important + } + + .order-sm-4 { + order: 4 !important + } + + .order-sm-5 { + order: 5 !important + } + + .order-sm-last { + order: 6 !important + } + + .m-sm-0 { + margin: 0 !important + } + + .m-sm-1 { + margin: .25rem !important + } + + .m-sm-2 { + margin: .5rem !important + } + + .m-sm-3 { + margin: 1rem !important + } + + .m-sm-4 { + margin: 1.5rem !important + } + + .m-sm-5 { + margin: 3rem !important + } + + .m-sm-auto { + margin: auto !important + } + + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + + .mx-sm-1 { + margin-right: .25rem !important; + margin-left: .25rem !important + } + + .mx-sm-2 { + margin-right: .5rem !important; + margin-left: .5rem !important + } + + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important + } + + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important + } + + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important + } + + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important + } + + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + + .my-sm-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important + } + + .my-sm-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important + } + + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important + } + + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important + } + + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important + } + + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important + } + + .mt-sm-0 { + margin-top: 0 !important + } + + .mt-sm-1 { + margin-top: .25rem !important + } + + .mt-sm-2 { + margin-top: .5rem !important + } + + .mt-sm-3 { + margin-top: 1rem !important + } + + .mt-sm-4 { + margin-top: 1.5rem !important + } + + .mt-sm-5 { + margin-top: 3rem !important + } + + .mt-sm-auto { + margin-top: auto !important + } + + .me-sm-0 { + margin-right: 0 !important + } + + .me-sm-1 { + margin-right: .25rem !important + } + + .me-sm-2 { + margin-right: .5rem !important + } + + .me-sm-3 { + margin-right: 1rem !important + } + + .me-sm-4 { + margin-right: 1.5rem !important + } + + .me-sm-5 { + margin-right: 3rem !important + } + + .me-sm-auto { + margin-right: auto !important + } + + .mb-sm-0 { + margin-bottom: 0 !important + } + + .mb-sm-1 { + margin-bottom: .25rem !important + } + + .mb-sm-2 { + margin-bottom: .5rem !important + } + + .mb-sm-3 { + margin-bottom: 1rem !important + } + + .mb-sm-4 { + margin-bottom: 1.5rem !important + } + + .mb-sm-5 { + margin-bottom: 3rem !important + } + + .mb-sm-auto { + margin-bottom: auto !important + } + + .ms-sm-0 { + margin-left: 0 !important + } + + .ms-sm-1 { + margin-left: .25rem !important + } + + .ms-sm-2 { + margin-left: .5rem !important + } + + .ms-sm-3 { + margin-left: 1rem !important + } + + .ms-sm-4 { + margin-left: 1.5rem !important + } + + .ms-sm-5 { + margin-left: 3rem !important + } + + .ms-sm-auto { + margin-left: auto !important + } + + .p-sm-0 { + padding: 0 !important + } + + .p-sm-1 { + padding: .25rem !important + } + + .p-sm-2 { + padding: .5rem !important + } + + .p-sm-3 { + padding: 1rem !important + } + + .p-sm-4 { + padding: 1.5rem !important + } + + .p-sm-5 { + padding: 3rem !important + } + + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + + .px-sm-1 { + padding-right: .25rem !important; + padding-left: .25rem !important + } + + .px-sm-2 { + padding-right: .5rem !important; + padding-left: .5rem !important + } + + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important + } + + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important + } + + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important + } + + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + + .py-sm-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important + } + + .py-sm-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important + } + + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important + } + + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important + } + + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important + } + + .pt-sm-0 { + padding-top: 0 !important + } + + .pt-sm-1 { + padding-top: .25rem !important + } + + .pt-sm-2 { + padding-top: .5rem !important + } + + .pt-sm-3 { + padding-top: 1rem !important + } + + .pt-sm-4 { + padding-top: 1.5rem !important + } + + .pt-sm-5 { + padding-top: 3rem !important + } + + .pe-sm-0 { + padding-right: 0 !important + } + + .pe-sm-1 { + padding-right: .25rem !important + } + + .pe-sm-2 { + padding-right: .5rem !important + } + + .pe-sm-3 { + padding-right: 1rem !important + } + + .pe-sm-4 { + padding-right: 1.5rem !important + } + + .pe-sm-5 { + padding-right: 3rem !important + } + + .pb-sm-0 { + padding-bottom: 0 !important + } + + .pb-sm-1 { + padding-bottom: .25rem !important + } + + .pb-sm-2 { + padding-bottom: .5rem !important + } + + .pb-sm-3 { + padding-bottom: 1rem !important + } + + .pb-sm-4 { + padding-bottom: 1.5rem !important + } + + .pb-sm-5 { + padding-bottom: 3rem !important + } + + .ps-sm-0 { + padding-left: 0 !important + } + + .ps-sm-1 { + padding-left: .25rem !important + } + + .ps-sm-2 { + padding-left: .5rem !important + } + + .ps-sm-3 { + padding-left: 1rem !important + } + + .ps-sm-4 { + padding-left: 1.5rem !important + } + + .ps-sm-5 { + padding-left: 3rem !important + } + + .text-sm-start { + text-align: left !important + } + + .text-sm-end { + text-align: right !important + } + + .text-sm-center { + text-align: center !important + } +} + +@media (min-width:768px) { + .float-md-start { + float: left !important + } + + .float-md-end { + float: right !important + } + + .float-md-none { + float: none !important + } + + .d-md-inline { + display: inline !important + } + + .d-md-inline-block { + display: inline-block !important + } + + .d-md-block { + display: block !important + } + + .d-md-grid { + display: grid !important + } + + .d-md-table { + display: table !important + } + + .d-md-table-row { + display: table-row !important + } + + .d-md-table-cell { + display: table-cell !important + } + + .d-md-flex { + display: flex !important + } + + .d-md-inline-flex { + display: inline-flex !important + } + + .d-md-none { + display: none !important + } + + .flex-md-fill { + flex: 1 1 auto !important + } + + .flex-md-row { + flex-direction: row !important + } + + .flex-md-column { + flex-direction: column !important + } + + .flex-md-row-reverse { + flex-direction: row-reverse !important + } + + .flex-md-column-reverse { + flex-direction: column-reverse !important + } + + .flex-md-grow-0 { + flex-grow: 0 !important + } + + .flex-md-grow-1 { + flex-grow: 1 !important + } + + .flex-md-shrink-0 { + flex-shrink: 0 !important + } + + .flex-md-shrink-1 { + flex-shrink: 1 !important + } + + .flex-md-wrap { + flex-wrap: wrap !important + } + + .flex-md-nowrap { + flex-wrap: nowrap !important + } + + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important + } + + .gap-md-0 { + gap: 0 !important + } + + .gap-md-1 { + gap: .25rem !important + } + + .gap-md-2 { + gap: .5rem !important + } + + .gap-md-3 { + gap: 1rem !important + } + + .gap-md-4 { + gap: 1.5rem !important + } + + .gap-md-5 { + gap: 3rem !important + } + + .justify-content-md-start { + justify-content: flex-start !important + } + + .justify-content-md-end { + justify-content: flex-end !important + } + + .justify-content-md-center { + justify-content: center !important + } + + .justify-content-md-between { + justify-content: space-between !important + } + + .justify-content-md-around { + justify-content: space-around !important + } + + .justify-content-md-evenly { + justify-content: space-evenly !important + } + + .align-items-md-start { + align-items: flex-start !important + } + + .align-items-md-end { + align-items: flex-end !important + } + + .align-items-md-center { + align-items: center !important + } + + .align-items-md-baseline { + align-items: baseline !important + } + + .align-items-md-stretch { + align-items: stretch !important + } + + .align-content-md-start { + align-content: flex-start !important + } + + .align-content-md-end { + align-content: flex-end !important + } + + .align-content-md-center { + align-content: center !important + } + + .align-content-md-between { + align-content: space-between !important + } + + .align-content-md-around { + align-content: space-around !important + } + + .align-content-md-stretch { + align-content: stretch !important + } + + .align-self-md-auto { + align-self: auto !important + } + + .align-self-md-start { + align-self: flex-start !important + } + + .align-self-md-end { + align-self: flex-end !important + } + + .align-self-md-center { + align-self: center !important + } + + .align-self-md-baseline { + align-self: baseline !important + } + + .align-self-md-stretch { + align-self: stretch !important + } + + .order-md-first { + order: -1 !important + } + + .order-md-0 { + order: 0 !important + } + + .order-md-1 { + order: 1 !important + } + + .order-md-2 { + order: 2 !important + } + + .order-md-3 { + order: 3 !important + } + + .order-md-4 { + order: 4 !important + } + + .order-md-5 { + order: 5 !important + } + + .order-md-last { + order: 6 !important + } + + .m-md-0 { + margin: 0 !important + } + + .m-md-1 { + margin: .25rem !important + } + + .m-md-2 { + margin: .5rem !important + } + + .m-md-3 { + margin: 1rem !important + } + + .m-md-4 { + margin: 1.5rem !important + } + + .m-md-5 { + margin: 3rem !important + } + + .m-md-auto { + margin: auto !important + } + + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + + .mx-md-1 { + margin-right: .25rem !important; + margin-left: .25rem !important + } + + .mx-md-2 { + margin-right: .5rem !important; + margin-left: .5rem !important + } + + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important + } + + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important + } + + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important + } + + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important + } + + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + + .my-md-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important + } + + .my-md-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important + } + + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important + } + + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important + } + + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important + } + + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important + } + + .mt-md-0 { + margin-top: 0 !important + } + + .mt-md-1 { + margin-top: .25rem !important + } + + .mt-md-2 { + margin-top: .5rem !important + } + + .mt-md-3 { + margin-top: 1rem !important + } + + .mt-md-4 { + margin-top: 1.5rem !important + } + + .mt-md-5 { + margin-top: 3rem !important + } + + .mt-md-auto { + margin-top: auto !important + } + + .me-md-0 { + margin-right: 0 !important + } + + .me-md-1 { + margin-right: .25rem !important + } + + .me-md-2 { + margin-right: .5rem !important + } + + .me-md-3 { + margin-right: 1rem !important + } + + .me-md-4 { + margin-right: 1.5rem !important + } + + .me-md-5 { + margin-right: 3rem !important + } + + .me-md-auto { + margin-right: auto !important + } + + .mb-md-0 { + margin-bottom: 0 !important + } + + .mb-md-1 { + margin-bottom: .25rem !important + } + + .mb-md-2 { + margin-bottom: .5rem !important + } + + .mb-md-3 { + margin-bottom: 1rem !important + } + + .mb-md-4 { + margin-bottom: 1.5rem !important + } + + .mb-md-5 { + margin-bottom: 3rem !important + } + + .mb-md-auto { + margin-bottom: auto !important + } + + .ms-md-0 { + margin-left: 0 !important + } + + .ms-md-1 { + margin-left: .25rem !important + } + + .ms-md-2 { + margin-left: .5rem !important + } + + .ms-md-3 { + margin-left: 1rem !important + } + + .ms-md-4 { + margin-left: 1.5rem !important + } + + .ms-md-5 { + margin-left: 3rem !important + } + + .ms-md-auto { + margin-left: auto !important + } + + .p-md-0 { + padding: 0 !important + } + + .p-md-1 { + padding: .25rem !important + } + + .p-md-2 { + padding: .5rem !important + } + + .p-md-3 { + padding: 1rem !important + } + + .p-md-4 { + padding: 1.5rem !important + } + + .p-md-5 { + padding: 3rem !important + } + + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + + .px-md-1 { + padding-right: .25rem !important; + padding-left: .25rem !important + } + + .px-md-2 { + padding-right: .5rem !important; + padding-left: .5rem !important + } + + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important + } + + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important + } + + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important + } + + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + + .py-md-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important + } + + .py-md-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important + } + + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important + } + + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important + } + + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important + } + + .pt-md-0 { + padding-top: 0 !important + } + + .pt-md-1 { + padding-top: .25rem !important + } + + .pt-md-2 { + padding-top: .5rem !important + } + + .pt-md-3 { + padding-top: 1rem !important + } + + .pt-md-4 { + padding-top: 1.5rem !important + } + + .pt-md-5 { + padding-top: 3rem !important + } + + .pe-md-0 { + padding-right: 0 !important + } + + .pe-md-1 { + padding-right: .25rem !important + } + + .pe-md-2 { + padding-right: .5rem !important + } + + .pe-md-3 { + padding-right: 1rem !important + } + + .pe-md-4 { + padding-right: 1.5rem !important + } + + .pe-md-5 { + padding-right: 3rem !important + } + + .pb-md-0 { + padding-bottom: 0 !important + } + + .pb-md-1 { + padding-bottom: .25rem !important + } + + .pb-md-2 { + padding-bottom: .5rem !important + } + + .pb-md-3 { + padding-bottom: 1rem !important + } + + .pb-md-4 { + padding-bottom: 1.5rem !important + } + + .pb-md-5 { + padding-bottom: 3rem !important + } + + .ps-md-0 { + padding-left: 0 !important + } + + .ps-md-1 { + padding-left: .25rem !important + } + + .ps-md-2 { + padding-left: .5rem !important + } + + .ps-md-3 { + padding-left: 1rem !important + } + + .ps-md-4 { + padding-left: 1.5rem !important + } + + .ps-md-5 { + padding-left: 3rem !important + } + + .text-md-start { + text-align: left !important + } + + .text-md-end { + text-align: right !important + } + + .text-md-center { + text-align: center !important + } +} + +@media (min-width:992px) { + .float-lg-start { + float: left !important + } + + .float-lg-end { + float: right !important + } + + .float-lg-none { + float: none !important + } + + .d-lg-inline { + display: inline !important + } + + .d-lg-inline-block { + display: inline-block !important + } + + .d-lg-block { + display: block !important + } + + .d-lg-grid { + display: grid !important + } + + .d-lg-table { + display: table !important + } + + .d-lg-table-row { + display: table-row !important + } + + .d-lg-table-cell { + display: table-cell !important + } + + .d-lg-flex { + display: flex !important + } + + .d-lg-inline-flex { + display: inline-flex !important + } + + .d-lg-none { + display: none !important + } + + .flex-lg-fill { + flex: 1 1 auto !important + } + + .flex-lg-row { + flex-direction: row !important + } + + .flex-lg-column { + flex-direction: column !important + } + + .flex-lg-row-reverse { + flex-direction: row-reverse !important + } + + .flex-lg-column-reverse { + flex-direction: column-reverse !important + } + + .flex-lg-grow-0 { + flex-grow: 0 !important + } + + .flex-lg-grow-1 { + flex-grow: 1 !important + } + + .flex-lg-shrink-0 { + flex-shrink: 0 !important + } + + .flex-lg-shrink-1 { + flex-shrink: 1 !important + } + + .flex-lg-wrap { + flex-wrap: wrap !important + } + + .flex-lg-nowrap { + flex-wrap: nowrap !important + } + + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important + } + + .gap-lg-0 { + gap: 0 !important + } + + .gap-lg-1 { + gap: .25rem !important + } + + .gap-lg-2 { + gap: .5rem !important + } + + .gap-lg-3 { + gap: 1rem !important + } + + .gap-lg-4 { + gap: 1.5rem !important + } + + .gap-lg-5 { + gap: 3rem !important + } + + .justify-content-lg-start { + justify-content: flex-start !important + } + + .justify-content-lg-end { + justify-content: flex-end !important + } + + .justify-content-lg-center { + justify-content: center !important + } + + .justify-content-lg-between { + justify-content: space-between !important + } + + .justify-content-lg-around { + justify-content: space-around !important + } + + .justify-content-lg-evenly { + justify-content: space-evenly !important + } + + .align-items-lg-start { + align-items: flex-start !important + } + + .align-items-lg-end { + align-items: flex-end !important + } + + .align-items-lg-center { + align-items: center !important + } + + .align-items-lg-baseline { + align-items: baseline !important + } + + .align-items-lg-stretch { + align-items: stretch !important + } + + .align-content-lg-start { + align-content: flex-start !important + } + + .align-content-lg-end { + align-content: flex-end !important + } + + .align-content-lg-center { + align-content: center !important + } + + .align-content-lg-between { + align-content: space-between !important + } + + .align-content-lg-around { + align-content: space-around !important + } + + .align-content-lg-stretch { + align-content: stretch !important + } + + .align-self-lg-auto { + align-self: auto !important + } + + .align-self-lg-start { + align-self: flex-start !important + } + + .align-self-lg-end { + align-self: flex-end !important + } + + .align-self-lg-center { + align-self: center !important + } + + .align-self-lg-baseline { + align-self: baseline !important + } + + .align-self-lg-stretch { + align-self: stretch !important + } + + .order-lg-first { + order: -1 !important + } + + .order-lg-0 { + order: 0 !important + } + + .order-lg-1 { + order: 1 !important + } + + .order-lg-2 { + order: 2 !important + } + + .order-lg-3 { + order: 3 !important + } + + .order-lg-4 { + order: 4 !important + } + + .order-lg-5 { + order: 5 !important + } + + .order-lg-last { + order: 6 !important + } + + .m-lg-0 { + margin: 0 !important + } + + .m-lg-1 { + margin: .25rem !important + } + + .m-lg-2 { + margin: .5rem !important + } + + .m-lg-3 { + margin: 1rem !important + } + + .m-lg-4 { + margin: 1.5rem !important + } + + .m-lg-5 { + margin: 3rem !important + } + + .m-lg-auto { + margin: auto !important + } + + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + + .mx-lg-1 { + margin-right: .25rem !important; + margin-left: .25rem !important + } + + .mx-lg-2 { + margin-right: .5rem !important; + margin-left: .5rem !important + } + + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important + } + + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important + } + + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important + } + + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important + } + + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + + .my-lg-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important + } + + .my-lg-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important + } + + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important + } + + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important + } + + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important + } + + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important + } + + .mt-lg-0 { + margin-top: 0 !important + } + + .mt-lg-1 { + margin-top: .25rem !important + } + + .mt-lg-2 { + margin-top: .5rem !important + } + + .mt-lg-3 { + margin-top: 1rem !important + } + + .mt-lg-4 { + margin-top: 1.5rem !important + } + + .mt-lg-5 { + margin-top: 3rem !important + } + + .mt-lg-auto { + margin-top: auto !important + } + + .me-lg-0 { + margin-right: 0 !important + } + + .me-lg-1 { + margin-right: .25rem !important + } + + .me-lg-2 { + margin-right: .5rem !important + } + + .me-lg-3 { + margin-right: 1rem !important + } + + .me-lg-4 { + margin-right: 1.5rem !important + } + + .me-lg-5 { + margin-right: 3rem !important + } + + .me-lg-auto { + margin-right: auto !important + } + + .mb-lg-0 { + margin-bottom: 0 !important + } + + .mb-lg-1 { + margin-bottom: .25rem !important + } + + .mb-lg-2 { + margin-bottom: .5rem !important + } + + .mb-lg-3 { + margin-bottom: 1rem !important + } + + .mb-lg-4 { + margin-bottom: 1.5rem !important + } + + .mb-lg-5 { + margin-bottom: 3rem !important + } + + .mb-lg-auto { + margin-bottom: auto !important + } + + .ms-lg-0 { + margin-left: 0 !important + } + + .ms-lg-1 { + margin-left: .25rem !important + } + + .ms-lg-2 { + margin-left: .5rem !important + } + + .ms-lg-3 { + margin-left: 1rem !important + } + + .ms-lg-4 { + margin-left: 1.5rem !important + } + + .ms-lg-5 { + margin-left: 3rem !important + } + + .ms-lg-auto { + margin-left: auto !important + } + + .p-lg-0 { + padding: 0 !important + } + + .p-lg-1 { + padding: .25rem !important + } + + .p-lg-2 { + padding: .5rem !important + } + + .p-lg-3 { + padding: 1rem !important + } + + .p-lg-4 { + padding: 1.5rem !important + } + + .p-lg-5 { + padding: 3rem !important + } + + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + + .px-lg-1 { + padding-right: .25rem !important; + padding-left: .25rem !important + } + + .px-lg-2 { + padding-right: .5rem !important; + padding-left: .5rem !important + } + + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important + } + + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important + } + + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important + } + + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + + .py-lg-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important + } + + .py-lg-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important + } + + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important + } + + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important + } + + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important + } + + .pt-lg-0 { + padding-top: 0 !important + } + + .pt-lg-1 { + padding-top: .25rem !important + } + + .pt-lg-2 { + padding-top: .5rem !important + } + + .pt-lg-3 { + padding-top: 1rem !important + } + + .pt-lg-4 { + padding-top: 1.5rem !important + } + + .pt-lg-5 { + padding-top: 3rem !important + } + + .pe-lg-0 { + padding-right: 0 !important + } + + .pe-lg-1 { + padding-right: .25rem !important + } + + .pe-lg-2 { + padding-right: .5rem !important + } + + .pe-lg-3 { + padding-right: 1rem !important + } + + .pe-lg-4 { + padding-right: 1.5rem !important + } + + .pe-lg-5 { + padding-right: 3rem !important + } + + .pb-lg-0 { + padding-bottom: 0 !important + } + + .pb-lg-1 { + padding-bottom: .25rem !important + } + + .pb-lg-2 { + padding-bottom: .5rem !important + } + + .pb-lg-3 { + padding-bottom: 1rem !important + } + + .pb-lg-4 { + padding-bottom: 1.5rem !important + } + + .pb-lg-5 { + padding-bottom: 3rem !important + } + + .ps-lg-0 { + padding-left: 0 !important + } + + .ps-lg-1 { + padding-left: .25rem !important + } + + .ps-lg-2 { + padding-left: .5rem !important + } + + .ps-lg-3 { + padding-left: 1rem !important + } + + .ps-lg-4 { + padding-left: 1.5rem !important + } + + .ps-lg-5 { + padding-left: 3rem !important + } + + .text-lg-start { + text-align: left !important + } + + .text-lg-end { + text-align: right !important + } + + .text-lg-center { + text-align: center !important + } +} + +@media (min-width:1200px) { + .float-xl-start { + float: left !important + } + + .float-xl-end { + float: right !important + } + + .float-xl-none { + float: none !important + } + + .d-xl-inline { + display: inline !important + } + + .d-xl-inline-block { + display: inline-block !important + } + + .d-xl-block { + display: block !important + } + + .d-xl-grid { + display: grid !important + } + + .d-xl-table { + display: table !important + } + + .d-xl-table-row { + display: table-row !important + } + + .d-xl-table-cell { + display: table-cell !important + } + + .d-xl-flex { + display: flex !important + } + + .d-xl-inline-flex { + display: inline-flex !important + } + + .d-xl-none { + display: none !important + } + + .flex-xl-fill { + flex: 1 1 auto !important + } + + .flex-xl-row { + flex-direction: row !important + } + + .flex-xl-column { + flex-direction: column !important + } + + .flex-xl-row-reverse { + flex-direction: row-reverse !important + } + + .flex-xl-column-reverse { + flex-direction: column-reverse !important + } + + .flex-xl-grow-0 { + flex-grow: 0 !important + } + + .flex-xl-grow-1 { + flex-grow: 1 !important + } + + .flex-xl-shrink-0 { + flex-shrink: 0 !important + } + + .flex-xl-shrink-1 { + flex-shrink: 1 !important + } + + .flex-xl-wrap { + flex-wrap: wrap !important + } + + .flex-xl-nowrap { + flex-wrap: nowrap !important + } + + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important + } + + .gap-xl-0 { + gap: 0 !important + } + + .gap-xl-1 { + gap: .25rem !important + } + + .gap-xl-2 { + gap: .5rem !important + } + + .gap-xl-3 { + gap: 1rem !important + } + + .gap-xl-4 { + gap: 1.5rem !important + } + + .gap-xl-5 { + gap: 3rem !important + } + + .justify-content-xl-start { + justify-content: flex-start !important + } + + .justify-content-xl-end { + justify-content: flex-end !important + } + + .justify-content-xl-center { + justify-content: center !important + } + + .justify-content-xl-between { + justify-content: space-between !important + } + + .justify-content-xl-around { + justify-content: space-around !important + } + + .justify-content-xl-evenly { + justify-content: space-evenly !important + } + + .align-items-xl-start { + align-items: flex-start !important + } + + .align-items-xl-end { + align-items: flex-end !important + } + + .align-items-xl-center { + align-items: center !important + } + + .align-items-xl-baseline { + align-items: baseline !important + } + + .align-items-xl-stretch { + align-items: stretch !important + } + + .align-content-xl-start { + align-content: flex-start !important + } + + .align-content-xl-end { + align-content: flex-end !important + } + + .align-content-xl-center { + align-content: center !important + } + + .align-content-xl-between { + align-content: space-between !important + } + + .align-content-xl-around { + align-content: space-around !important + } + + .align-content-xl-stretch { + align-content: stretch !important + } + + .align-self-xl-auto { + align-self: auto !important + } + + .align-self-xl-start { + align-self: flex-start !important + } + + .align-self-xl-end { + align-self: flex-end !important + } + + .align-self-xl-center { + align-self: center !important + } + + .align-self-xl-baseline { + align-self: baseline !important + } + + .align-self-xl-stretch { + align-self: stretch !important + } + + .order-xl-first { + order: -1 !important + } + + .order-xl-0 { + order: 0 !important + } + + .order-xl-1 { + order: 1 !important + } + + .order-xl-2 { + order: 2 !important + } + + .order-xl-3 { + order: 3 !important + } + + .order-xl-4 { + order: 4 !important + } + + .order-xl-5 { + order: 5 !important + } + + .order-xl-last { + order: 6 !important + } + + .m-xl-0 { + margin: 0 !important + } + + .m-xl-1 { + margin: .25rem !important + } + + .m-xl-2 { + margin: .5rem !important + } + + .m-xl-3 { + margin: 1rem !important + } + + .m-xl-4 { + margin: 1.5rem !important + } + + .m-xl-5 { + margin: 3rem !important + } + + .m-xl-auto { + margin: auto !important + } + + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + + .mx-xl-1 { + margin-right: .25rem !important; + margin-left: .25rem !important + } + + .mx-xl-2 { + margin-right: .5rem !important; + margin-left: .5rem !important + } + + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important + } + + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important + } + + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important + } + + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important + } + + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + + .my-xl-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important + } + + .my-xl-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important + } + + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important + } + + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important + } + + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important + } + + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important + } + + .mt-xl-0 { + margin-top: 0 !important + } + + .mt-xl-1 { + margin-top: .25rem !important + } + + .mt-xl-2 { + margin-top: .5rem !important + } + + .mt-xl-3 { + margin-top: 1rem !important + } + + .mt-xl-4 { + margin-top: 1.5rem !important + } + + .mt-xl-5 { + margin-top: 3rem !important + } + + .mt-xl-auto { + margin-top: auto !important + } + + .me-xl-0 { + margin-right: 0 !important + } + + .me-xl-1 { + margin-right: .25rem !important + } + + .me-xl-2 { + margin-right: .5rem !important + } + + .me-xl-3 { + margin-right: 1rem !important + } + + .me-xl-4 { + margin-right: 1.5rem !important + } + + .me-xl-5 { + margin-right: 3rem !important + } + + .me-xl-auto { + margin-right: auto !important + } + + .mb-xl-0 { + margin-bottom: 0 !important + } + + .mb-xl-1 { + margin-bottom: .25rem !important + } + + .mb-xl-2 { + margin-bottom: .5rem !important + } + + .mb-xl-3 { + margin-bottom: 1rem !important + } + + .mb-xl-4 { + margin-bottom: 1.5rem !important + } + + .mb-xl-5 { + margin-bottom: 3rem !important + } + + .mb-xl-auto { + margin-bottom: auto !important + } + + .ms-xl-0 { + margin-left: 0 !important + } + + .ms-xl-1 { + margin-left: .25rem !important + } + + .ms-xl-2 { + margin-left: .5rem !important + } + + .ms-xl-3 { + margin-left: 1rem !important + } + + .ms-xl-4 { + margin-left: 1.5rem !important + } + + .ms-xl-5 { + margin-left: 3rem !important + } + + .ms-xl-auto { + margin-left: auto !important + } + + .p-xl-0 { + padding: 0 !important + } + + .p-xl-1 { + padding: .25rem !important + } + + .p-xl-2 { + padding: .5rem !important + } + + .p-xl-3 { + padding: 1rem !important + } + + .p-xl-4 { + padding: 1.5rem !important + } + + .p-xl-5 { + padding: 3rem !important + } + + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + + .px-xl-1 { + padding-right: .25rem !important; + padding-left: .25rem !important + } + + .px-xl-2 { + padding-right: .5rem !important; + padding-left: .5rem !important + } + + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important + } + + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important + } + + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important + } + + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + + .py-xl-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important + } + + .py-xl-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important + } + + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important + } + + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important + } + + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important + } + + .pt-xl-0 { + padding-top: 0 !important + } + + .pt-xl-1 { + padding-top: .25rem !important + } + + .pt-xl-2 { + padding-top: .5rem !important + } + + .pt-xl-3 { + padding-top: 1rem !important + } + + .pt-xl-4 { + padding-top: 1.5rem !important + } + + .pt-xl-5 { + padding-top: 3rem !important + } + + .pe-xl-0 { + padding-right: 0 !important + } + + .pe-xl-1 { + padding-right: .25rem !important + } + + .pe-xl-2 { + padding-right: .5rem !important + } + + .pe-xl-3 { + padding-right: 1rem !important + } + + .pe-xl-4 { + padding-right: 1.5rem !important + } + + .pe-xl-5 { + padding-right: 3rem !important + } + + .pb-xl-0 { + padding-bottom: 0 !important + } + + .pb-xl-1 { + padding-bottom: .25rem !important + } + + .pb-xl-2 { + padding-bottom: .5rem !important + } + + .pb-xl-3 { + padding-bottom: 1rem !important + } + + .pb-xl-4 { + padding-bottom: 1.5rem !important + } + + .pb-xl-5 { + padding-bottom: 3rem !important + } + + .ps-xl-0 { + padding-left: 0 !important + } + + .ps-xl-1 { + padding-left: .25rem !important + } + + .ps-xl-2 { + padding-left: .5rem !important + } + + .ps-xl-3 { + padding-left: 1rem !important + } + + .ps-xl-4 { + padding-left: 1.5rem !important + } + + .ps-xl-5 { + padding-left: 3rem !important + } + + .text-xl-start { + text-align: left !important + } + + .text-xl-end { + text-align: right !important + } + + .text-xl-center { + text-align: center !important + } +} + +@media (min-width:1400px) { + .float-xxl-start { + float: left !important + } + + .float-xxl-end { + float: right !important + } + + .float-xxl-none { + float: none !important + } + + .d-xxl-inline { + display: inline !important + } + + .d-xxl-inline-block { + display: inline-block !important + } + + .d-xxl-block { + display: block !important + } + + .d-xxl-grid { + display: grid !important + } + + .d-xxl-table { + display: table !important + } + + .d-xxl-table-row { + display: table-row !important + } + + .d-xxl-table-cell { + display: table-cell !important + } + + .d-xxl-flex { + display: flex !important + } + + .d-xxl-inline-flex { + display: inline-flex !important + } + + .d-xxl-none { + display: none !important + } + + .flex-xxl-fill { + flex: 1 1 auto !important + } + + .flex-xxl-row { + flex-direction: row !important + } + + .flex-xxl-column { + flex-direction: column !important + } + + .flex-xxl-row-reverse { + flex-direction: row-reverse !important + } + + .flex-xxl-column-reverse { + flex-direction: column-reverse !important + } + + .flex-xxl-grow-0 { + flex-grow: 0 !important + } + + .flex-xxl-grow-1 { + flex-grow: 1 !important + } + + .flex-xxl-shrink-0 { + flex-shrink: 0 !important + } + + .flex-xxl-shrink-1 { + flex-shrink: 1 !important + } + + .flex-xxl-wrap { + flex-wrap: wrap !important + } + + .flex-xxl-nowrap { + flex-wrap: nowrap !important + } + + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important + } + + .gap-xxl-0 { + gap: 0 !important + } + + .gap-xxl-1 { + gap: .25rem !important + } + + .gap-xxl-2 { + gap: .5rem !important + } + + .gap-xxl-3 { + gap: 1rem !important + } + + .gap-xxl-4 { + gap: 1.5rem !important + } + + .gap-xxl-5 { + gap: 3rem !important + } + + .justify-content-xxl-start { + justify-content: flex-start !important + } + + .justify-content-xxl-end { + justify-content: flex-end !important + } + + .justify-content-xxl-center { + justify-content: center !important + } + + .justify-content-xxl-between { + justify-content: space-between !important + } + + .justify-content-xxl-around { + justify-content: space-around !important + } + + .justify-content-xxl-evenly { + justify-content: space-evenly !important + } + + .align-items-xxl-start { + align-items: flex-start !important + } + + .align-items-xxl-end { + align-items: flex-end !important + } + + .align-items-xxl-center { + align-items: center !important + } + + .align-items-xxl-baseline { + align-items: baseline !important + } + + .align-items-xxl-stretch { + align-items: stretch !important + } + + .align-content-xxl-start { + align-content: flex-start !important + } + + .align-content-xxl-end { + align-content: flex-end !important + } + + .align-content-xxl-center { + align-content: center !important + } + + .align-content-xxl-between { + align-content: space-between !important + } + + .align-content-xxl-around { + align-content: space-around !important + } + + .align-content-xxl-stretch { + align-content: stretch !important + } + + .align-self-xxl-auto { + align-self: auto !important + } + + .align-self-xxl-start { + align-self: flex-start !important + } + + .align-self-xxl-end { + align-self: flex-end !important + } + + .align-self-xxl-center { + align-self: center !important + } + + .align-self-xxl-baseline { + align-self: baseline !important + } + + .align-self-xxl-stretch { + align-self: stretch !important + } + + .order-xxl-first { + order: -1 !important + } + + .order-xxl-0 { + order: 0 !important + } + + .order-xxl-1 { + order: 1 !important + } + + .order-xxl-2 { + order: 2 !important + } + + .order-xxl-3 { + order: 3 !important + } + + .order-xxl-4 { + order: 4 !important + } + + .order-xxl-5 { + order: 5 !important + } + + .order-xxl-last { + order: 6 !important + } + + .m-xxl-0 { + margin: 0 !important + } + + .m-xxl-1 { + margin: .25rem !important + } + + .m-xxl-2 { + margin: .5rem !important + } + + .m-xxl-3 { + margin: 1rem !important + } + + .m-xxl-4 { + margin: 1.5rem !important + } + + .m-xxl-5 { + margin: 3rem !important + } + + .m-xxl-auto { + margin: auto !important + } + + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important + } + + .mx-xxl-1 { + margin-right: .25rem !important; + margin-left: .25rem !important + } + + .mx-xxl-2 { + margin-right: .5rem !important; + margin-left: .5rem !important + } + + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important + } + + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important + } + + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important + } + + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important + } + + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important + } + + .my-xxl-1 { + margin-top: .25rem !important; + margin-bottom: .25rem !important + } + + .my-xxl-2 { + margin-top: .5rem !important; + margin-bottom: .5rem !important + } + + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important + } + + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important + } + + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important + } + + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important + } + + .mt-xxl-0 { + margin-top: 0 !important + } + + .mt-xxl-1 { + margin-top: .25rem !important + } + + .mt-xxl-2 { + margin-top: .5rem !important + } + + .mt-xxl-3 { + margin-top: 1rem !important + } + + .mt-xxl-4 { + margin-top: 1.5rem !important + } + + .mt-xxl-5 { + margin-top: 3rem !important + } + + .mt-xxl-auto { + margin-top: auto !important + } + + .me-xxl-0 { + margin-right: 0 !important + } + + .me-xxl-1 { + margin-right: .25rem !important + } + + .me-xxl-2 { + margin-right: .5rem !important + } + + .me-xxl-3 { + margin-right: 1rem !important + } + + .me-xxl-4 { + margin-right: 1.5rem !important + } + + .me-xxl-5 { + margin-right: 3rem !important + } + + .me-xxl-auto { + margin-right: auto !important + } + + .mb-xxl-0 { + margin-bottom: 0 !important + } + + .mb-xxl-1 { + margin-bottom: .25rem !important + } + + .mb-xxl-2 { + margin-bottom: .5rem !important + } + + .mb-xxl-3 { + margin-bottom: 1rem !important + } + + .mb-xxl-4 { + margin-bottom: 1.5rem !important + } + + .mb-xxl-5 { + margin-bottom: 3rem !important + } + + .mb-xxl-auto { + margin-bottom: auto !important + } + + .ms-xxl-0 { + margin-left: 0 !important + } + + .ms-xxl-1 { + margin-left: .25rem !important + } + + .ms-xxl-2 { + margin-left: .5rem !important + } + + .ms-xxl-3 { + margin-left: 1rem !important + } + + .ms-xxl-4 { + margin-left: 1.5rem !important + } + + .ms-xxl-5 { + margin-left: 3rem !important + } + + .ms-xxl-auto { + margin-left: auto !important + } + + .p-xxl-0 { + padding: 0 !important + } + + .p-xxl-1 { + padding: .25rem !important + } + + .p-xxl-2 { + padding: .5rem !important + } + + .p-xxl-3 { + padding: 1rem !important + } + + .p-xxl-4 { + padding: 1.5rem !important + } + + .p-xxl-5 { + padding: 3rem !important + } + + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important + } + + .px-xxl-1 { + padding-right: .25rem !important; + padding-left: .25rem !important + } + + .px-xxl-2 { + padding-right: .5rem !important; + padding-left: .5rem !important + } + + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important + } + + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important + } + + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important + } + + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important + } + + .py-xxl-1 { + padding-top: .25rem !important; + padding-bottom: .25rem !important + } + + .py-xxl-2 { + padding-top: .5rem !important; + padding-bottom: .5rem !important + } + + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important + } + + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important + } + + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important + } + + .pt-xxl-0 { + padding-top: 0 !important + } + + .pt-xxl-1 { + padding-top: .25rem !important + } + + .pt-xxl-2 { + padding-top: .5rem !important + } + + .pt-xxl-3 { + padding-top: 1rem !important + } + + .pt-xxl-4 { + padding-top: 1.5rem !important + } + + .pt-xxl-5 { + padding-top: 3rem !important + } + + .pe-xxl-0 { + padding-right: 0 !important + } + + .pe-xxl-1 { + padding-right: .25rem !important + } + + .pe-xxl-2 { + padding-right: .5rem !important + } + + .pe-xxl-3 { + padding-right: 1rem !important + } + + .pe-xxl-4 { + padding-right: 1.5rem !important + } + + .pe-xxl-5 { + padding-right: 3rem !important + } + + .pb-xxl-0 { + padding-bottom: 0 !important + } + + .pb-xxl-1 { + padding-bottom: .25rem !important + } + + .pb-xxl-2 { + padding-bottom: .5rem !important + } + + .pb-xxl-3 { + padding-bottom: 1rem !important + } + + .pb-xxl-4 { + padding-bottom: 1.5rem !important + } + + .pb-xxl-5 { + padding-bottom: 3rem !important + } + + .ps-xxl-0 { + padding-left: 0 !important + } + + .ps-xxl-1 { + padding-left: .25rem !important + } + + .ps-xxl-2 { + padding-left: .5rem !important + } + + .ps-xxl-3 { + padding-left: 1rem !important + } + + .ps-xxl-4 { + padding-left: 1.5rem !important + } + + .ps-xxl-5 { + padding-left: 3rem !important + } + + .text-xxl-start { + text-align: left !important + } + + .text-xxl-end { + text-align: right !important + } + + .text-xxl-center { + text-align: center !important + } +} + +@media (min-width:1200px) { + .fs-1 { + font-size: 2.5rem !important + } + + .fs-2 { + font-size: 2rem !important + } + + .fs-3 { + font-size: 1.75rem !important + } + + .fs-4 { + font-size: 1.5rem !important + } +} + +@media print { + .d-print-inline { + display: inline !important + } + + .d-print-inline-block { + display: inline-block !important + } + + .d-print-block { + display: block !important + } + + .d-print-grid { + display: grid !important + } + + .d-print-table { + display: table !important + } + + .d-print-table-row { + display: table-row !important + } + + .d-print-table-cell { + display: table-cell !important + } + + .d-print-flex { + display: flex !important + } + + .d-print-inline-flex { + display: inline-flex !important + } + + .d-print-none { + display: none !important + } +} +/*# sourceMappingURL=bootstrap.min.css.map */ diff --git a/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css.map b/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css.map new file mode 100644 index 0000000..8c41293 --- /dev/null +++ b/MasaBlazorApp3/wwwroot/css/bootstrap/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Bootstrap v5.1.0 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors\n * Copyright 2011-2021 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n\n// scss-docs-start import-stack\n// Configuration\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"utilities\";\n\n// Layout & components\n@import \"root\";\n@import \"reboot\";\n@import \"type\";\n@import \"images\";\n@import \"containers\";\n@import \"grid\";\n@import \"tables\";\n@import \"forms\";\n@import \"buttons\";\n@import \"transitions\";\n@import \"dropdown\";\n@import \"button-group\";\n@import \"nav\";\n@import \"navbar\";\n@import \"card\";\n@import \"accordion\";\n@import \"breadcrumb\";\n@import \"pagination\";\n@import \"badge\";\n@import \"alert\";\n@import \"progress\";\n@import \"list-group\";\n@import \"close\";\n@import \"toasts\";\n@import \"modal\";\n@import \"tooltip\";\n@import \"popover\";\n@import \"carousel\";\n@import \"spinners\";\n@import \"offcanvas\";\n@import \"placeholders\";\n\n// Helpers\n@import \"helpers\";\n\n// Utilities\n@import \"utilities/api\";\n// scss-docs-end import-stack\n",":root {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$variable-prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$variable-prefix}#{$color}-rgb: #{$value};\n }\n\n --#{$variable-prefix}white-rgb: #{to-rgb($white)};\n --#{$variable-prefix}black-rgb: #{to-rgb($black)};\n --#{$variable-prefix}body-rgb: #{to-rgb($body-color)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$variable-prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$variable-prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$variable-prefix}gradient: #{$gradient};\n\n // Root and body\n // stylelint-disable custom-property-empty-line-before\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$variable-prefix}root-font-size: #{$font-size-root};\n }\n --#{$variable-prefix}body-font-family: #{$font-family-base};\n --#{$variable-prefix}body-font-size: #{$font-size-base};\n --#{$variable-prefix}body-font-weight: #{$font-weight-base};\n --#{$variable-prefix}body-line-height: #{$line-height-base};\n --#{$variable-prefix}body-color: #{$body-color};\n @if $body-text-align != null {\n --#{$variable-prefix}body-text-align: #{$body-text-align};\n }\n --#{$variable-prefix}body-bg: #{$body-bg};\n // scss-docs-end root-body-variables\n // stylelint-enable custom-property-empty-line-before\n}\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n font-size: var(--#{$variable-prefix}-root-font-size);\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$variable-prefix}body-font-family);\n @include font-size(var(--#{$variable-prefix}body-font-size));\n font-weight: var(--#{$variable-prefix}body-font-weight);\n line-height: var(--#{$variable-prefix}body-line-height);\n color: var(--#{$variable-prefix}body-color);\n text-align: var(--#{$variable-prefix}body-text-align);\n background-color: var(--#{$variable-prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n background-color: currentColor;\n border: 0;\n opacity: $hr-opacity;\n}\n\nhr:not([size]) {\n height: $hr-height; // 2\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-`