123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- using System;
- using System.Runtime.InteropServices;
- using System.Text;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- namespace JiangSuElectronicCertificate
- {
- /// <summary>
- /// 江苏医保电子凭证解码接口
- /// 基于江苏医保接口规范v0.9.9.15和HeaSecReadInfo.dll实现
- /// 符合国家医保电子凭证业务标准动态库交互规范2021-11-12
- /// </summary>
- public class JiangSuEcDecoder
- {
- #region DLL导入声明
- /// <summary>
- /// 1.14.1 初始化
- /// </summary>
- /// <param name="pInitInfo">JSON格式的初始化参数</param>
- /// <param name="pErrMsg">错误信息输出缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg);
- /// <summary>
- /// 1.14.6 电子凭证解码
- /// </summary>
- /// <param name="pInData">输入数据(JSON格式)</param>
- /// <param name="pOutData">输出数据缓冲区</param>
- /// <returns>0-成功,其他-失败</returns>
- [DllImport("HeaSecReadInfo.dll", EntryPoint = "EcQuery", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
- private extern static Int32 EcQuery(string pInData, StringBuilder pOutData);
- #endregion
- #region 配置类
- /// <summary>
- /// 江苏医保配置信息
- /// </summary>
- public class JiangSuConfig
- {
- /// <summary>
- /// 服务器IP地址(根据具体医院配置修改)
- /// </summary>
- public string IP { get; set; } = "10.61.165.3";
- /// <summary>
- /// 服务器端口号
- /// </summary>
- public int PORT { get; set; } = 8086;
- /// <summary>
- /// 超时时间(秒)
- /// </summary>
- public int TIMEOUT { get; set; } = 30;
- /// <summary>
- /// 日志路径(根据项目实际路径修改)
- /// </summary>
- public string LOG_PATH { get; set; } = "C:\\logs\\";
- /// <summary>
- /// 电子凭证解码URL(根据具体医院配置修改)
- /// </summary>
- public string EC_URL { get; set; } = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery";
- /// <summary>
- /// 卡片通道类型
- /// </summary>
- public string CARD_PASSTYPE { get; set; } = "2";
- /// <summary>
- /// API名称
- /// </summary>
- public string API_NAME { get; set; } = "hssServives";
- /// <summary>
- /// API版本
- /// </summary>
- public string API_VERSION { get; set; } = "1.0.0";
- /// <summary>
- /// 访问密钥(根据具体医院申请的密钥修改)
- /// </summary>
- public string ACCESS_KEY { get; set; } = "090ea4c914324ee38b6978365df46a80";
- /// <summary>
- /// 秘钥(根据具体医院申请的密钥修改)
- /// </summary>
- public string SECRETKEY { get; set; } = "CMgTEMfftMP0EMMoliOs65wZmv8=";
- /// <summary>
- /// 机构编号(根据具体医院的医保定点编号修改)
- /// </summary>
- public string ORG_ID { get; set; } = "H32132200561";
- /// <summary>
- /// 扩展参数
- /// </summary>
- public string EXT { get; set; } = "{}";
- /// <summary>
- /// 地区编码
- /// </summary>
- public string AREA_CODE { get; set; } = "321322";
- /// <summary>
- /// 转换为JSON格式
- /// </summary>
- /// <returns>JSON字符串</returns>
- public string ToJson()
- {
- var config = new
- {
- IP = this.IP,
- PORT = this.PORT,
- TIMEOUT = this.TIMEOUT,
- LOG_PATH = this.LOG_PATH,
- EC_URL = this.EC_URL,
- CARD_PASSTYPE = this.CARD_PASSTYPE,
- API_NAME = this.API_NAME,
- API_VERSION = this.API_VERSION,
- ACCESS_KEY = this.ACCESS_KEY,
- SECRETKEY = this.SECRETKEY,
- ORG_ID = this.ORG_ID,
- EXT = this.EXT,
- AREA_CODE = this.AREA_CODE
- };
- return JsonConvert.SerializeObject(config, Formatting.None);
- }
- }
- #endregion
- #region 私有变量
- private static bool isInitialized = false;
- private static JiangSuConfig currentConfig = null;
- #endregion
- #region 公共方法
- /// <summary>
- /// 初始化江苏医保系统
- /// </summary>
- /// <param name="config">配置信息,为null时使用默认配置</param>
- /// <returns>初始化结果</returns>
- public static JObject Initialize(JiangSuConfig config = null)
- {
- var result = new JObject();
- try
- {
- // 使用传入的配置或默认配置
- if (config == null)
- {
- config = new JiangSuConfig();
- }
- currentConfig = config;
- // 准备初始化参数
- string initParams = config.ToJson();
- // 准备错误信息缓冲区
- StringBuilder errorBuffer = new StringBuilder(1024);
- // 调用DLL初始化函数
- int initResult = Init(initParams, errorBuffer);
- if (initResult == 0)
- {
- isInitialized = true;
- result["success"] = true;
- result["code"] = 200;
- result["message"] = "江苏医保系统初始化成功";
- result["device"] = "江苏医保电子凭证解码器";
- result["config"] = JObject.Parse(initParams);
- result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- }
- else
- {
- isInitialized = false;
- string errorMessage = errorBuffer.ToString();
- result["success"] = false;
- result["code"] = 1000 + initResult;
- result["message"] = $"江苏医保系统初始化失败,错误码: {initResult}";
- result["device"] = "江苏医保电子凭证解码器";
- result["dllErrorCode"] = initResult;
- result["dllErrorMessage"] = errorMessage;
- }
- }
- catch (Exception ex)
- {
- isInitialized = false;
- result["success"] = false;
- result["code"] = 1001;
- result["message"] = $"江苏医保系统初始化异常: {ex.Message}";
- result["device"] = "江苏医保电子凭证解码器";
- result["exception"] = ex.GetType().Name;
- }
- return result;
- }
- /// <summary>
- /// 江苏医保电子凭证解码
- /// </summary>
- /// <param name="businessType">业务类型编码(默认01101门诊挂号)</param>
- /// <param name="operatorId">收款员编号</param>
- /// <param name="operatorName">收款员姓名</param>
- /// <param name="officeId">医保科室编号</param>
- /// <param name="officeName">科室名称</param>
- /// <returns>解码结果</returns>
- public static JObject DecodeElectronicCertificate(
- string businessType = "01101",
- string operatorId = "system001",
- string operatorName = "系统管理员",
- string officeId = "32760",
- string officeName = "医保科")
- {
- var result = new JObject();
- try
- {
- // 检查初始化状态
- if (!isInitialized)
- {
- // 自动初始化
- var autoInitResult = Initialize();
- if (!(bool)autoInitResult["success"])
- {
- result["success"] = false;
- result["code"] = 1002;
- result["message"] = "江苏医保系统未初始化,电子凭证解码失败";
- result["device"] = "江苏医保电子凭证解码器";
- result["autoInitError"] = autoInitResult["message"];
- result["type"] = "qrcode";
- return result;
- }
- }
- // 获取当前配置
- if (currentConfig == null)
- {
- result["success"] = false;
- result["code"] = 1003;
- result["message"] = "江苏医保配置信息为空";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- return result;
- }
- // 按照江苏医保接口规范1.14.6构造输入参数
- var inputData = new
- {
- data = new
- {
- orgId = currentConfig.ORG_ID, // 定点编号
- businessType = businessType, // 用码业务类型
- operatorId = operatorId, // 收款员编号
- operatorName = operatorName, // 收款员姓名
- officeId = officeId, // 医保科室编号
- officeName = officeName // 科室名称
- },
- transType = "ec.query", // 固定值:ec.query
- orgId = currentConfig.ORG_ID // 定点编号
- };
- // JSON序列化输入参数
- string jsonInput = JsonConvert.SerializeObject(inputData, Formatting.None);
- // 按照规范分配8192字节输出缓冲区
- StringBuilder outputBuffer = new StringBuilder(8192);
- // 调用江苏医保DLL的EcQuery函数
- int dllResult = EcQuery(jsonInput, outputBuffer);
- if (dllResult == 0)
- {
- // 解析DLL返回的JSON数据
- string responseJson = outputBuffer.ToString();
-
- if (string.IsNullOrEmpty(responseJson))
- {
- result["success"] = false;
- result["code"] = 1004;
- result["message"] = "电子凭证解码返回数据为空";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- return result;
- }
- // 解析江苏医保返回的JSON数据
- var jiangsuResponse = JObject.Parse(responseJson);
-
- // 检查江苏医保接口返回的code字段
- int responseCode = (int)(jiangsuResponse["code"] ?? -1);
-
- if (responseCode == 0)
- {
- // 成功:提取患者信息
- var patientData = jiangsuResponse["data"];
-
- if (patientData != null)
- {
- result["success"] = true;
- result["code"] = 200;
- result["message"] = "江苏医保电子凭证解码成功";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["originalType"] = "jiangsu_ec";
- result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
-
- // 按照文档规范提取患者信息
- var patientInfo = new
- {
- idNo = patientData["idNo"]?.ToString() ?? "", // 身份证号
- userName = patientData["userName"]?.ToString() ?? "", // 姓名
- idType = patientData["idType"]?.ToString() ?? "", // 证件类型
- ecToken = patientData["ecToken"]?.ToString() ?? "", // 令牌
- insuOrg = patientData["insuOrg"]?.ToString() ?? "", // 参保地区编码
- ecIndexNo = patientData["ecIndexNo"]?.ToString() ?? "", // 电子凭证索引号
- gender = patientData["gender"]?.ToString() ?? "", // 性别
- birthday = patientData["birthday"]?.ToString() ?? "", // 出生日期
- nationality = patientData["nationality"]?.ToString() ?? "", // 国籍
- email = patientData["email"]?.ToString() ?? "", // 邮箱
- extra = patientData["extra"]?.ToString() ?? "" // 扩展参数
- };
-
- // 按照泰和医院格式构造data字段(包含code/data/message结构)
- var dllResponseFormat = new
- {
- code = 0,
- data = patientInfo,
- message = "交易成功"
- };
- result["data"] = JsonConvert.SerializeObject(dllResponseFormat);
-
- // 保存原始江苏医保返回数据(用于调试和日志)
- result["jiangsuOriginalData"] = responseJson;
- result["businessType"] = businessType;
- result["interfaceVersion"] = "v0.9.9.15";
- }
- else
- {
- result["success"] = false;
- result["code"] = 1005;
- result["message"] = "电子凭证解码成功,但患者数据为空";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["jiangsuOriginalData"] = responseJson;
- }
- }
- else
- {
- // 江苏医保接口返回失败
- string errorMessage = jiangsuResponse["message"]?.ToString() ?? "电子凭证解码失败";
-
- result["success"] = false;
- result["code"] = 2000 + responseCode; // 使用2xxx系列表示江苏医保接口错误
- result["message"] = $"江苏医保电子凭证解码失败: {errorMessage}";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["jiangsuErrorCode"] = responseCode;
- result["jiangsuErrorMessage"] = errorMessage;
- result["jiangsuOriginalData"] = responseJson;
- result["businessType"] = businessType;
- }
- }
- else
- {
- // DLL函数调用失败
- string errorInfo = outputBuffer.ToString();
-
- result["success"] = false;
- result["code"] = 3000 + dllResult; // 使用3xxx系列表示DLL调用错误
- result["message"] = $"江苏医保DLL调用失败,错误码: {dllResult}";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["dllErrorCode"] = dllResult;
- result["dllErrorMessage"] = errorInfo;
- result["businessType"] = businessType;
- result["suggestion"] = GetEcQueryErrorSuggestion(dllResult);
- }
- }
- catch (JsonException jsonEx)
- {
- result["success"] = false;
- result["code"] = 1006;
- result["message"] = $"电子凭证解码数据解析异常: {jsonEx.Message}";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["exception"] = jsonEx.GetType().Name;
- result["businessType"] = businessType;
- }
- catch (Exception ex)
- {
- result["success"] = false;
- result["code"] = 1007;
- result["message"] = $"电子凭证解码系统异常: {ex.Message}";
- result["device"] = "江苏医保电子凭证解码器";
- result["type"] = "qrcode";
- result["exception"] = ex.GetType().Name;
- result["businessType"] = businessType;
- }
- return result;
- }
- /// <summary>
- /// 检查业务类型编码是否有效
- /// </summary>
- /// <param name="businessType">业务类型编码</param>
- /// <returns>是否有效</returns>
- public static bool IsValidBusinessType(string businessType)
- {
- if (string.IsNullOrEmpty(businessType) || businessType.Length != 5)
- return false;
- // 有效的业务类型列表(根据国家医保电子凭证业务标准)
- string[] validTypes = {
- "01101", // 医院-挂号
- "01102", // 医院-住院建档
- "01103", // 医院-入院登记
- "01104", // 医院-缴纳预缴金
- "01201", // 医院-问诊
- "01202", // 医院-预约检查
- "01203", // 医院-检查
- "01204", // 医院-治疗
- "01301", // 医院-结算
- "01302", // 医院-取药
- "01303", // 医院-取报告
- "01304", // 医院-打印票据和清单
- "01305", // 医院-病历材料复印
- "01306", // 医院-诊间核验身份
- "02121", // 药店-药店购药
- "02122", // 药店-下载外购处方
- "02123", // 药店-特殊门诊
- "02124", // 药店-药师审核处方
- "03131", // 医疗类APP-线上身份认证
- "03132", // 医疗类APP-线上结算
- "05101", // 柜台-线下修改密码
- "05151" // 柜台-医保业务办理
- };
- return Array.IndexOf(validTypes, businessType) >= 0;
- }
- #endregion
- #region 私有方法
- /// <summary>
- /// 获取电子凭证查询错误建议
- /// </summary>
- /// <param name="errorCode">错误码</param>
- /// <returns>错误建议</returns>
- private static string GetEcQueryErrorSuggestion(int errorCode)
- {
- switch (errorCode)
- {
- case -1:
- return "请检查网络连接和服务器配置";
- case -2:
- return "请检查输入参数是否正确";
- case -3:
- return "请求超时,请稍后重试";
- case -4:
- return "权限验证失败,请检查密钥配置";
- case -5:
- return "请求地址无效,请检查EC_URL配置";
- default:
- return "请联系技术支持或查看详细错误信息";
- }
- }
- #endregion
- }
- #region Web API控制器示例
- /// <summary>
- /// 江苏医保电子凭证Web API控制器示例
- /// 可以直接集成到ASP.NET Web API项目中
- /// </summary>
- public class JiangSuEcController : System.Web.Http.ApiController
- {
- /// <summary>
- /// 电子凭证解码接口
- /// POST /api/jiangsuec/decode
- /// </summary>
- /// <param name="request">请求参数</param>
- /// <returns>解码结果</returns>
- [System.Web.Http.HttpPost]
- [System.Web.Http.Route("api/jiangsuec/decode")]
- public JObject Decode([System.Web.Http.FromBody] dynamic request)
- {
- try
- {
- string businessType = request?.businessType ?? "01101";
- string operatorId = request?.operatorId ?? "system001";
- string operatorName = request?.operatorName ?? "系统管理员";
- string officeId = request?.officeId ?? "32760";
- string officeName = request?.officeName ?? "医保科";
- return JiangSuEcDecoder.DecodeElectronicCertificate(
- businessType, operatorId, operatorName, officeId, officeName);
- }
- catch (Exception ex)
- {
- var errorResult = new JObject();
- errorResult["success"] = false;
- errorResult["code"] = 9001;
- errorResult["message"] = $"接口调用异常: {ex.Message}";
- errorResult["device"] = "江苏医保电子凭证解码器";
- errorResult["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- return errorResult;
- }
- }
- /// <summary>
- /// 初始化接口
- /// POST /api/jiangsuec/init
- /// </summary>
- /// <param name="request">配置参数</param>
- /// <returns>初始化结果</returns>
- [System.Web.Http.HttpPost]
- [System.Web.Http.Route("api/jiangsuec/init")]
- public JObject Init([System.Web.Http.FromBody] dynamic request)
- {
- try
- {
- JiangSuEcDecoder.JiangSuConfig config = null;
- if (request?.config != null)
- {
- config = new JiangSuEcDecoder.JiangSuConfig();
- if (request.config.IP != null) config.IP = (string)request.config.IP;
- if (request.config.PORT != null) config.PORT = (int)request.config.PORT;
- if (request.config.ORG_ID != null) config.ORG_ID = (string)request.config.ORG_ID;
- if (request.config.ACCESS_KEY != null) config.ACCESS_KEY = (string)request.config.ACCESS_KEY;
- if (request.config.SECRETKEY != null) config.SECRETKEY = (string)request.config.SECRETKEY;
- if (request.config.EC_URL != null) config.EC_URL = (string)request.config.EC_URL;
- }
- return JiangSuEcDecoder.Initialize(config);
- }
- catch (Exception ex)
- {
- var errorResult = new JObject();
- errorResult["success"] = false;
- errorResult["code"] = 9002;
- errorResult["message"] = $"初始化接口异常: {ex.Message}";
- errorResult["device"] = "江苏医保电子凭证解码器";
- errorResult["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
- return errorResult;
- }
- }
- }
- #endregion
- }
- #region 使用示例
- /*
- // 使用示例1:基本调用
- public void Example1()
- {
- // 1. 初始化(可选,会自动初始化)
- var initResult = JiangSuEcDecoder.Initialize();
- Console.WriteLine($"初始化结果: {initResult}");
- // 2. 解码电子凭证(门诊挂号)
- var decodeResult = JiangSuEcDecoder.DecodeElectronicCertificate(
- businessType: "01101", // 门诊挂号
- operatorId: "OP001", // 操作员编号
- operatorName: "张医生", // 操作员姓名
- officeId: "32760", // 科室编号
- officeName: "内科" // 科室名称
- );
- Console.WriteLine($"解码结果: {decodeResult}");
- if ((bool)decodeResult["success"])
- {
- var patientData = decodeResult["data"];
- Console.WriteLine($"患者姓名: {patientData["userName"]}");
- Console.WriteLine($"身份证号: {patientData["idNo"]}");
- Console.WriteLine($"电子凭证令牌: {patientData["ecToken"]}");
- }
- }
- // 使用示例2:自定义配置
- public void Example2()
- {
- // 创建自定义配置
- var config = new JiangSuEcDecoder.JiangSuConfig
- {
- IP = "192.168.1.100", // 医院内网IP
- PORT = 8086, // 端口
- ORG_ID = "H32132200561", // 医保定点编号
- ACCESS_KEY = "your_access_key_here", // 申请的访问密钥
- SECRETKEY = "your_secret_key_here", // 申请的秘钥
- EC_URL = "http://your.hospital.com:10086/localcfc/api/hsecfc/localQrCodeQuery"
- };
- // 使用自定义配置初始化
- var initResult = JiangSuEcDecoder.Initialize(config);
- // 解码电子凭证
- var decodeResult = JiangSuEcDecoder.DecodeElectronicCertificate("01301"); // 门诊结算
- }
- // 使用示例3:Web API集成
- public class YourController : ApiController
- {
- [HttpPost]
- public JObject DecodeQRCode([FromBody] dynamic request)
- {
- string businessType = request?.type ?? "01101";
- return JiangSuEcDecoder.DecodeElectronicCertificate(businessType);
- }
- }
- // 使用示例4:JavaScript前端调用
- /*
- // 前端JavaScript调用示例
- $.ajax({
- url: "http://localhost:8321/api/jiangsuec/decode",
- type: "POST",
- contentType: "application/json",
- data: JSON.stringify({
- businessType: "01101", // 门诊挂号
- operatorId: "OP001", // 操作员编号
- operatorName: "张医生", // 操作员姓名
- officeId: "32760", // 科室编号
- officeName: "内科" // 科室名称
- }),
- success: function(result) {
- if (result.success) {
- console.log("解码成功:", result.data);
- alert("患者: " + result.data.userName + ", 身份证: " + result.data.idNo);
- } else {
- console.log("解码失败:", result.message);
- alert("解码失败: " + result.message);
- }
- },
- error: function(xhr, status, error) {
- console.log("请求失败:", error);
- alert("网络请求失败");
- }
- });
- */
- /*
- */
- #endregion
- </rewritten_file>
|