基于ASP.NET Core的医院输血审核系统设计与实现

基于ASP.NET Core的医院输血审核系统设计与实现

一、项目概述

医院输血审核系统是针对医疗场景中的输血申请进行分级审批的Web应用系统。该系统实现了诊疗组长、科主任、医务部三级审核流程,确保输血申请的安全性和合规性。系统同时支持移动端(钉钉小程序)和Web端访问,采用多数据库架构整合医院现有的HIS系统、输血系统等多个数据源。

1.1 技术栈

层级 技术选型
框架 ASP.NET Core 3.1/5.0
数据库 MSSQL (SIHIS)、Oracle (HIS3)、MySQL (QASystem)
前端 Layui + HTML
移动端 钉钉小程序 (DingTalk Mini App)
日志 Microsoft.Extensions.Logging

1.2 审核流程图

复制代码
输血申请提交
     │
     ▼
┌─────────────────┐
│  诊疗组长审核   │ ← ApplyLevel = "1"
│  (Superior)     │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   科主任审核    │ ← ApplyLevel = "2"
│  (Professor)    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   医务部审核    │ ← ApplyLevel = "3"
│   (Med)         │
└─────────────────┘

二、核心模型设计

2.1 输血申请审核模型

csharp 复制代码
public class BloodApplyApproveModel
{
    public string ApplyNo { get; set; }        // 申请单号
    public string ItemNo { get; set; }         // 项目编号
    public bool SuperiorApproveFlag { get; set; }    // 诊疗组长审核标志
    public string SuperiorApproveUser { get; set; }  // 诊疗组长审核人
    public string SuperiorApproveTime { get; set; }  // 诊疗组长审核时间
    public bool ProfessorApproveFlag { get; set; }   // 科主任审核标志
    public string ProfessorApproveUser { get; set; }  // 科主任审核人
    public string ProfessorApproveTime { get; set; }  // 科主任审核时间
    public bool MedApproveFlag { get; set; }          // 医务部审核标志
    public string MedApproveUser { get; set; }         // 医务部审核人
    public string MedApproveTime { get; set; }         // 医务部审核时间
    public int ApproveStatus { get; set; }             // 审核状态
}

2.2 审核请求模型

csharp 复制代码
public class BloodPmsModel
{
    public string ApplyNo { get; set; }     // 申请单号
    public string ApplyLevel { get; set; } // 申请类别 (1-诊疗组长, 2-科主任, 3-医务部)
    public string EmpNo { get; set; }      // 员工编号
}

2.3 输血系统更新模型

csharp 复制代码
public class BloodInfoModel
{
    public string ITEMNO { get; set; }         // 项目编号
    public string SHANGJIYS { get; set; }      // 上级医生
    public string SHANGJISHSJ { get; set; }    // 上级审核时间
    public string KEZHUREN { get; set; }       // 科主任
    public string KEZHURENSHSJ { get; set; }    // 科主任审核时间
    public string YWB { get; set; }            // 医务部
    public string YWBSHSJ { get; set; }         // 医务部审核时间
}

三、控制器核心实现

3.1 构造函数与依赖注入

csharp 复制代码
public class BloodTransAuditController : Controller
{
    private readonly string _qasystem;
    private readonly string _harmfulevent;
    private readonly string _deepthroat;
    private readonly string _his3;
    private readonly string _sihis;
    private readonly IMysqlService _mysqlService;
    private readonly IOracleService _oracleService;
    private readonly IMssqlService _mssqlService;

    public BloodTransAuditController(
        ILogger<BloodTransAuditController> logger,
        IConfiguration configuration,
        IMysqlService mysqlService,
        IOracleService oracleService,
        IMssqlService mssqlService)
    {
        _qasystem = configuration.GetConnectionString("qasystem");
        _his3 = configuration.GetConnectionString("his3");
        _sihis = configuration.GetConnectionString("sihis");
        _mysqlService = mysqlService;
        _oracleService = oracleService;
        _mssqlService = mssqlService;
    }
}

设计亮点:通过配置文件管理多数据库连接字符串,便于部署切换不同环境。

3.2 分级审核逻辑实现

审核核心逻辑根据ApplyLevel参数执行不同的审核流程:

csharp 复制代码
if (model.ApplyLevel == "1") // 诊疗组长
{
    if (isSuperiorApprove(model.ApplyNo) == false)
    {
        // 更新审核状态
        sql = @"update BloodApplyApprove 
                set SuperiorApproveFlag=@SuperiorApproveFlag,
                    SuperiorApproveUser=@SuperiorApproveUser,
                    SuperiorApproveTime=@SuperiorApproveTime,
                    ApproveStatus = @ApproveStatus,
                    IsMobile=1 
                where ApplyNo=@ApplyNo";
        BackStaus = _mssqlService.DBExecute(_sihis, sql, 
            new BloodApplyApproveModel { 
                SuperiorApproveFlag = true, 
                SuperiorApproveUser = model.EmpNo, 
                SuperiorApproveTime = dateTime, 
                ApproveStatus = 1, 
                ApplyNo = model.ApplyNo 
            });

        // 同步更新输血系统
        usql = @"UPDATE xueye.xy_xd_bloodinfo 
                 SET SHANGJIYS=:SHANGJIYS,
                     SHANGJISHSJ=to_date(:SHANGJISHSJ,'yyyy-MM-dd hh24:mi:ss') 
                 where ITEMNO=:ITEMNO";
        _oracleService.DBExecute(_his3, usql, 
            new BloodInfoModel { SHANGJIYS = model.EmpNo, SHANGJISHSJ = dateTime, ITEMNO = ItemNo });
    }
}

3.3 审核状态检查方法

csharp 复制代码
private bool isSuperiorApprove(string ApplyNo)
{
    string sql = "select * from BloodApplyApprove where ApplyNo=@ApplyNo";
    BloodApplyApproveModel bloodApplyApprove = 
        _mssqlService.DBFind<BloodApplyApproveModel>(_sihis, sql, 
            new BloodApplyApproveModel { ApplyNo = ApplyNo });
    return bloodApplyApprove == null ? false : bloodApplyApprove.SuperiorApproveFlag;
}

private bool isProfessorApprove(string ApplyNo)
{
    string sql = "select * from BloodApplyApprove where ApplyNo=@ApplyNo";
    BloodApplyApproveModel bloodApplyApprove = 
        _mssqlService.DBFind<BloodApplyApproveModel>(_sihis, sql, 
            new BloodApplyApproveModel { ApplyNo = ApplyNo });
    return bloodApplyApprove == null ? false : bloodApplyApprove.ProfessorApproveFlag;
}

private bool isMedApprove(string ApplyNo)
{
    string sql = "select * from BloodApplyApprove where ApplyNo=@ApplyNo";
    BloodApplyApproveModel bloodApplyApprove = 
        _mssqlService.DBFind<BloodApplyApproveModel>(_sihis, sql, 
            new BloodApplyApproveModel { ApplyNo = ApplyNo });
    return bloodApplyApprove == null ? false : bloodApplyApprove.MedApproveFlag;
}

四、多数据库架构设计

4.1 数据库职责划分

数据库 类型 用途
SIHIS MSSQL 审核主数据存储
HIS3 Oracle 输血系统数据同步
QASystem MySQL 系统业务数据

4.2 数据同步策略

系统采用双写策略:当审核通过时,同时更新MSSQL审核库和Oracle输血库,确保数据一致性:

csharp 复制代码
// 1. 更新审核数据库 (MSSQL)
BackStaus = _mssqlService.DBExecute(_sihis, sql, approveModel);

// 2. 同步更新输血系统 (Oracle)
_oracleService.DBExecute(_his3, usql, bloodInfoModel);

五、双端适配实现

5.1 Web端审核 (HTTP GET)

csharp 复制代码
[HttpGet]
public IActionResult Index(string ApplyNo, string ApplyLevel, string EmpNo)
{
    // 审核逻辑...
    if (BackStaus > 0)
    {
        return Redirect("dingtalk://dingtalkclient/action/open_mini_app?miniAppId=5000000004689541&page=pages%2Fsuccess%2Fsuccess%3Fx%3D%25E4%25B8%25AD%25E6%2596%2587");
    }
    else
    {
        return Redirect("dingtalk://dingtalkclient/action/open_mini_app?miniAppId=5000000004689541&page=pages%2Ffail%2Ffail%3Fx%3D%25E4%25B8%25AD%25E6%2596%2587");
    }
}

5.2 移动端审核 (HTTP POST)

csharp 复制代码
[HttpPost]
public JsonResult Audit(BloodPmsModel model)
{
    MsgModel msgObj = null;
    try
    {
        // 审核逻辑...
        if (BackStaus > 0)
        {
            msgObj = new MsgModel { code = 1, msg = "输血审核成功" };
        }
        else
        {
            msgObj = new MsgModel { code = 0, msg = "输血审核失败" };
        }
    }
    catch (Exception ex)
    {
        msgObj = new MsgModel { code = 0, data = ex.Message, msg = "输血审核失败" };
    }
    return Json(msgObj);
}

5.3 钉钉小程序跳转协议

csharp 复制代码
// 成功跳转
"dingtalk://dingtalkclient/action/open_mini_app?miniAppId=5000000004689541&page=pages%2Fsuccess%2Fsuccess"

// 失败跳转
"dingtalk://dingtalkclient/action/open_mini_app?miniAppId=5000000004689541&page=pages%2Ffail%2Ffail"

六、钉钉消息推送机制

6.1 消息推送架构

系统实现了智能化的钉钉消息推送机制,当有新的输血申请需要审核时,自动根据血量和科室规则计算审核人并推送钉钉消息:

csharp 复制代码
[Route("JdrmyyCloud/sendDingTalkMessageOfBloodApply")]
[HttpPost]
public string sendDingTalkMessageOfBloodApply(DingTalkMsgModel model)
{
    string title = "输血申请";
    string ItemName = getItemNameByItemNo(model.ItemNo);
    decimal ApplyQty = totalApplyQty(model.VisitNo).ToString("#.####");

    List<BloodApplyerModel> bloodApplyers = getEmpCodes(model);
    foreach (BloodApplyerModel bloodApplyer in bloodApplyers)
    {
        string ApplyClass = string.Empty;
        if (bloodApplyer.ApplyLevel == "1")
            ApplyClass = "上级医生审核";
        else if (bloodApplyer.ApplyLevel == "2")
            ApplyClass = "科主任审核";
        else if (bloodApplyer.ApplyLevel == "3")
            ApplyClass = "医务部审核";

        string content = $"**输血申请审核提醒:** \n\n ------ \n\n **审核类别:** {ApplyClass}   \n\n **病历号:** {model.ChartNo}  \n\n **病人姓名:** {getPatientByChartNo(model.ChartNo)} \n\n **当日累计:** {ApplyQty}ml \n\n  **申请内容:** {ItemName}  \n\n **申请时间:** {DateTime.Now.ToString("yyyy-MM-dd HH:mm")}";

        string EmpNo = getEmployeeByEmpCode(bloodApplyer.EmpCode);
        string EnCodeUrl = HttpUtility.UrlEncode($"pages/index/index?ApplyLevel={bloodApplyer.ApplyLevel}&ApplyNo={model.ApplyNo}&EmpNo={EmpNo}");
        string SingleUrl = $"dingtalk://dingtalkclient/action/open_mini_app?miniAppId=5000000004689541&page={EnCodeUrl}";
        string msg = SendBloodAuditMsg(title, content, bloodApplyer.EmpCode, "点击审核", SingleUrl);
    }
    return model.ApplyNo;
}

6.2 智能审核路由算法

系统根据《医疗机构临床用血管理办法》实现了智能审核路由,根据当日累计用血量自动判定需要哪些级别的审核:

csharp 复制代码
private List<BloodApplyerModel> getEmpCodes(DingTalkMsgModel model)
{
    decimal ApplyQty = totalApplyQty(model.VisitNo);
    DataTable dt = DBFactory.SIHealthCareObject.ExecuteDataTable(
        "select * from BloodApplyApprove where ApplyNo=@ApplyNo", 
        new SqlParameter("@ApplyNo", model.ApplyNo));

    List<BloodApplyerModel> BloodApplyers = new List<BloodApplyerModel>();

    if (dt.Rows.Count > 0)
    {
        // 规则1: 当日累计 < 800ml → 诊疗组长审核
        if (ApplyQty < 800)
        {
            if (dt.Rows[0]["SuperiorApproveFlag"].ToString() == "False")
            {
                if ((model.deptId == "10091") || (model.deptId == "10093"))
                    BloodApplyers.Add(new BloodApplyerModel { EmpCode = getEmergencySuperiorerEmp(model.deptId), ApplyLevel = "1" });
                else
                    BloodApplyers.Add(new BloodApplyerModel { EmpCode = getMedicalGroupEmp(model.VisitNo), ApplyLevel = "1" });
            }
        }
        // 规则2: 800ml ≤ 当日累计 < 1600ml → 诊疗组长 + 科主任
        else if (ApplyQty >= 800 && ApplyQty < 1600)
        {
            if (dt.Rows[0]["SuperiorApproveFlag"].ToString() == "False")
            {
                BloodApplyers.Add(new BloodApplyerModel { EmpCode = getMedicalGroupEmp(model.VisitNo), ApplyLevel = "1" });
            }
            if (dt.Rows[0]["ProfessorApproveFlag"].ToString() == "False")
            {
                BloodApplyers.Add(new BloodApplyerModel { EmpCode = getDeptHeader(model.deptId), ApplyLevel = "2" });
            }
        }
        // 规则3: 当日累计 ≥ 1600ml → 科主任 + 医务部
        else if (ApplyQty >= 1600)
        {
            if (dt.Rows[0]["ProfessorApproveFlag"].ToString() == "False")
            {
                BloodApplyers.Add(new BloodApplyerModel { EmpCode = getDeptHeader(model.deptId), ApplyLevel = "2" });
            }
            if (dt.Rows[0]["MedApproveFlag"].ToString() == "False")
            {
                BloodApplyers.Add(new BloodApplyerModel { EmpCode = getDeptHeader("10168"), ApplyLevel = "3" });
            }
        }
    }
    return BloodApplyers;
}

6.3 用血量计算规则

csharp 复制代码
private decimal totalApplyQty(string VisitNo)
{
    string sql = @"select sum(a.ApplyQty) as ApplyQty 
                   from BloodApplyApprove a, MedItem b 
                   where a.ItemNo = b.ItemNo 
                   and a.VisitNo=@VisitNo 
                   and CONVERT(varchar(100), a.ApplyTime, 112) = CONVERT(varchar(100), GETDATE(), 112) 
                   and a.IsDel=0 
                   and b.TreatStatus not in ('9', 'C')";
    object ApplyQty = DBFactory.SIHealthCareObject.ExecuteScalar(sql, new SqlParameter("@VisitNo", VisitNo));
    return ApplyQty == null ? 0 : Convert.ToDecimal(ApplyQty);
}

6.4 审核人获取逻辑

科室类型 审核级别 获取方式
急诊内科/外科 诊疗组长 getEmergencySuperiorerEmp(deptId) - 查询急诊科上级医生表
普通科室 诊疗组长 getMedicalGroupEmp(VisitNo) - 查询诊疗组与角色关联表
全科室 科主任 getDeptHeader(deptId) - 查询科室主任表
全科室 医务部 getDeptHeader("10168") - 固定医务部科室编码
csharp 复制代码
private string getMedicalGroupEmp(string VisitNo)
{
    string sql = @"select * from Employee where EmpNo in (
        select a.EmpNo from EmpUserRole a, MedicalGroupRef b 
        where a.EmpNo = b.EmpNo and a.RoleNo='870410' 
        and b.MedicalGroupNo in (select MedicalGroupNo from InPatient where VisitNo = @VisitNo))";
    DataTable dt = DBFactory.SIHealthCareObject.ExecuteDataTable(sql, new SqlParameter("@VisitNo", VisitNo));
    return dt.Rows.Count == 0 ? "" : dt.Rows[0]["EmpCode"].ToString();
}

private string getDeptHeader(string deptId)
{
    string sql = "select * from Employee where EmpNo in (select EmpNo from Blood_DeptHeader where DeptNo=@DeptNo)";
    DataTable dt = DBFactory.SIHealthCareObject.ExecuteDataTable(sql, new SqlParameter("@DeptNo", deptId));
    return dt.Rows.Count == 0 ? "" : dt.Rows[0]["EmpCode"].ToString();
}

6.5 钉钉消息发送实现

csharp 复制代码
private string SendBloodAuditMsg(string title, string content, string empCode, string SingleTitle, string SingleUrl)
{
    string Appkey = "dingbwxvrnfnjq0qzahn";
    string Appsecret = "KAdjZGc81SeSyH_HJYki-_WaAirvYP7D54ThGRD8BQRsh6hqnJU4CFZepXXI9oiE";
    long AgentId = 757344095L;

    // 获取AccessToken
    IDingTalkClient client1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
    OapiGettokenRequest req1 = new OapiGettokenRequest();
    req1.Appkey = Appkey;
    req1.Appsecret = Appsecret;
    OapiGettokenResponse rsp1 = client1.Execute(req1);
    RequestTokenModel requestToken = JsonConvert.DeserializeObject<RequestTokenModel>(rsp1.Body);

    if (requestToken.errcode == 0)
    {
        // 根据工号获取手机号
        string mobile = getMobileByEmpCode(empCode);

        // 通过手机号获取userId
        IDingTalkClient client2 = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get_by_mobile");
        OapiUserGetByMobileRequest req2 = new OapiUserGetByMobileRequest();
        req2.Mobile = mobile;
        OapiUserGetByMobileResponse rsp2 = client2.Execute(req2, requestToken.access_token);
        RequestUserIdModel requestUserId = JsonConvert.DeserializeObject<RequestUserIdModel>(rsp2.Body);

        if (requestUserId.errcode == 0)
        {
            // 发送ActionCard类型消息
            IDingTalkClient client3 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
            OapiMessageCorpconversationAsyncsendV2Request req3 = new OapiMessageCorpconversationAsyncsendV2Request();
            req3.AgentId = AgentId;
            req3.UseridList = requestUserId.userid;

            OapiMessageCorpconversationAsyncsendV2Request.MsgDomain msg = new OapiMessageCorpconversationAsyncsendV2Request.MsgDomain();
            msg.Msgtype = "action_card";

            OapiMessageCorpconversationAsyncsendV2Request.ActionCardDomain actionCard = new OapiMessageCorpconversationAsyncsendV2Request.ActionCardDomain();
            actionCard.Title = title;
            actionCard.Markdown = content;
            actionCard.SingleTitle = SingleTitle;
            actionCard.SingleUrl = SingleUrl;

            msg.ActionCard = actionCard;
            req3.Msg_ = msg;

            OapiMessageCorpconversationAsyncsendV2Response rsp3 = client3.Execute(req3, requestToken.access_token);
            return JsonConvert.DeserializeObject<RequestMessageModel>(rsp3.Body).request_id;
        }
    }
    return "发送失败";
}

6.6 消息推送时序图

复制代码
┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   HIS系统   │     │  消息服务   │     │  钉钉API    │     │   审核人    │
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘     └──────┬──────┘
       │                  │                  │                  │
       │ 1.提交输血申请    │                  │                  │
       │─────────────────>│                  │                  │
       │                  │ 2.计算当日用血量  │                  │
       │                  │──────┐           │                  │
       │                  │      │           │                  │
       │                  │<─────┘           │                  │
       │                  │                  │                  │
       │                  │ 3.查询审核路由    │                  │
       │                  │──────┐           │                  │
       │                  │      │           │                  │
       │                  │<─────┘           │                  │
       │                  │                  │                  │
       │                  │ 4.获取AccessToken│                  │
       │                  │─────────────────>│                  │
       │                  │<─────────────────│                  │
       │                  │                  │                  │
       │                  │ 5.通过手机号获取userId              │
       │                  │─────────────────>│                  │
       │                  │<─────────────────│                  │
       │                  │                  │                  │
       │                  │ 6.发送ActionCard消息               │
       │                  │─────────────────>│                  │
       │                  │                  │    7.收到推送     │
       │                  │                  │─────────────────>│

七、日志与异常处理

7.1 操作日志记录

csharp 复制代码
_logger.LogInformation("***********************************************************************************");
_logger.LogInformation($"输血申请单号:{model.ApplyNo};申请类别:{model.ApplyLevel};医生ID:{model.EmpNo}");
_logger.LogInformation("***********************************************************************************");
_logger.LogInformation($"审核类别:诊疗组长,输血申请单号:{model.ApplyNo},操作人ID:{model.EmpNo}");

7.2 异常捕获机制

csharp 复制代码
catch (Exception ex)
{
    msgObj = new MsgModel { code = 0, data = ex.Message, msg = "输血审核失败" };
    _logger.LogInformation($"审核抛异常了({ex.Message}):输血申请单号:{model.ApplyNo};申请类别:{model.ApplyLevel};医生ID:{model.EmpNo}");
}

八、系统架构图

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        客户端层                                  │
├──────────────────────┬──────────────────────┬───────────────────┤
│    钉钉小程序        │     Web浏览器        │    移动端H5       │
└──────────┬───────────┴──────────┬───────────┴─────────┬─────────┘
           │                      │                      │
           ▼                      ▼                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                      ASP.NET Core Web API                        │
│  ┌──────────────────────────┐  ┌────────────────────────────┐ │
│  │ BloodTransAuditController │  │   DingTalkController       │ │
│  │  - Audit (POST)           │  │  - sendDingTalkMessage... │ │
│  │  - Index (GET)            │  │  - SendBloodAuditMsg      │ │
│  └──────────────────────────┘  └────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
           │                            │
           ▼                            ▼
┌──────────────────┐     ┌──────────────────────────────┐
│      MSSQL        │     │        钉钉开放平台           │
│     (SIHIS)       │     │  - AccessToken获取           │
│                   │     │  - userId查询                │
│ BloodApplyApprove │     │  - ActionCard消息推送       │
└────────┬──────────┘     └──────────────────────────────┘
         │                            │
         ▼                            │
┌──────────────────┐                 │
│      Oracle      │                 │
│      (HIS3)      │                 │
│                  │                 │
│ xy_xd_bloodinfo  │                 │
└──────────────────┘                 │
         │                            │
         ▼                            ▼
┌─────────────────────────────────────────────────────────────────┐
│                      钉钉小程序 (审核页面)                        │
│  pages/index/index?ApplyLevel=&ApplyNo=&EmpNo=                  │
└─────────────────────────────────────────────────────────────────┘

九、代码优化建议

9.1 重复代码提取

当前AuditIndex方法存在大量重复逻辑,建议抽取为私有方法:

csharp 复制代码
private int ExecuteAudit(string applyNo, string applyLevel, string empNo)
{
    string sql = string.Empty;
    string usql = string.Empty;
    string dateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    int backStatus = 0;
    string itemNo = getItemNoByApplyNo(applyNo);

    try
    {
        switch (applyLevel)
        {
            case "1": // 诊疗组长
                backStatus = ApproveBySuperior(applyNo, empNo, dateTime, itemNo);
                break;
            case "2": // 科主任
                backStatus = ApproveByProfessor(applyNo, empNo, dateTime, itemNo);
                break;
            case "3": // 医务部
                backStatus = ApproveByMed(applyNo, empNo, dateTime, itemNo);
                break;
        }
    }
    catch (Exception ex)
    {
        throw new AuditException($"审核失败: {ex.Message}", applyNo, applyLevel, empNo);
    }

    return backStatus;
}

9.2 事务管理优化

当前双写操作缺乏事务保证,建议引入分布式事务:

csharp 复制代码
using (var transaction = new TransactionScope())
{
    _mssqlService.DBExecute(_sihis, sql, approveModel);
    _oracleService.DBExecute(_his3, usql, bloodInfoModel);
    transaction.Complete();
}

9.3 审核状态机重构

使用状态模式替代多层if-else:

csharp 复制代码
public interface IAuditStrategy
{
    bool CanApprove(string applyNo);
    int Approve(string applyNo, string empNo, string dateTime);
    string GetAuditLevel();
}

public class SuperiorAuditStrategy : IAuditStrategy
{
    public bool CanApprove(string applyNo) => !_service.isSuperiorApprove(applyNo);
    public int Approve(string applyNo, string empNo, string dateTime) { /* ... */ }
}

十、总结

本文详细介绍了基于ASP.NET Core的医院输血审核系统设计与实现,该系统具有以下特点:

  1. 多数据库整合:同时连接MSSQL、Oracle、MySQL三种数据库,实现医院现有系统的数据打通
  2. 分级审核机制:支持诊疗组长、科主任、医务部三级审核流程
  3. 双端适配:同时支持Web端和移动端(钉钉小程序)访问
  4. 智能消息推送:根据用血量自动计算审核路由,钉钉消息一键直达审核页面
  5. 日志完善:全面的操作日志记录,便于审计追踪

10.1 关键技术亮点

功能模块 技术方案 业务价值
用血量阈值判断 800ml/1600ml双阈值 符合《医疗机构临床用血管理办法》
审核人路由 科室+角色+诊疗组多维度 确保审批层级正确
钉钉消息 ActionCard + DeepLink 点击消息直接进入审核页
跨库同步 MSSQL + Oracle双写 审核库与输血系统数据一致

系统可进一步优化的地方包括:审核逻辑抽象化、分布式事务引入、审核状态机重构、缓存机制添加等,以提升系统的可维护性和性能。

相关推荐
妙蛙种子3115 小时前
【Java设计模式 | 创建者模式】建造者模式
java·开发语言·后端·设计模式·建造者模式
zihao_tom5 小时前
Spring 简介
java·后端·spring
Java女侠_9年实战5 小时前
Spring框架“惯性思维”坑——@Transactional失效场景、Bean注入循环依赖
后端
Ares-Wang5 小时前
flask》》多线程并发数据安全问题 threading.local werkzeug.local.Local
后端·python·flask
覆东流5 小时前
第2天:Python变量与数据类型
开发语言·后端·python
Rust研习社6 小时前
Rust Default 特征详解:轻松实现类型默认值
开发语言·后端·rust
南囝coding6 小时前
零成本打造专业域名邮箱:Cloudflare + Gmail 终极配置保姆级全攻略
前端·后端
李二毛7 小时前
看到 done=true,就说明前面的写入都可见吗?
后端
Master_Azur7 小时前
JavaEE之Stream流
后端
暮年7 小时前
List并发实现-Vector
后端