using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ThCardReader
{
///
/// 江苏医保社保卡读取业务类
/// 基于HeaSecReadInfo.dll作为主DLL,严格按照江苏医保规范实现
///
public class JiangSuSocialCardBusiness
{
#region DLL导入声明
// 主DLL: HeaSecReadInfo.dll - 严格按照江苏医保规范v0.9.9.15实现
///
/// 1.14.1 初始化
///
/// JSON格式的初始化参数
/// 错误信息输出缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg);
///
/// 1.14.2 读社保卡基本信息
///
/// 社保卡基本信息输出缓冲区
/// 社保卡业务信息输出缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "ReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 ReadCardBas(StringBuilder pCardInfo, StringBuilder pBusiCardInfo);
///
/// 1.14.3 检验PIN码
///
/// 输出信息缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "VerifyPIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 VerifyPIN(StringBuilder pOutBuff);
///
/// 1.14.4 修改PIN码
///
/// 输出信息缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "ChangePIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 ChangePIN(StringBuilder pOutBuff);
///
/// 1.14.6 电子凭证解码
///
/// 输入数据(JSON格式)
/// 输出数据缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "EcQuery", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 EcQuery(string pInData, StringBuilder pOutData);
///
/// 1.14.8 四合一介质获得个人信息
///
/// 输入数据
/// 输出数据缓冲区
/// 0-成功,其他-失败
[DllImport("HeaSecReadInfo.dll", EntryPoint = "GetPersonInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 GetPersonInfo(string pInData, StringBuilder pOutData);
#endregion
#region 江苏医保刷脸DLL导入声明 (与泰和完全一致)
///
/// 江苏医保刷脸功能:使用NationECCode.dll与泰和完全一致
/// 唯一区别:URL参数格式为jiangsu_face_${biztype}
///
/// 业务请求地址
/// 交易请求数据
/// 交易返回数据
/// 返回字符串指针
[DllImport("FaceNationECCode.dll", EntryPoint = "NationEcTrans", CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private extern static IntPtr NationEcTrans(string strUrl, string InData, ref byte OutData);
#endregion
#region 江苏人社标准接口DLL导入声明 (按照官方规范v2.1.1)
///
/// 江苏人社标准接口:读基本信息
/// 按照江苏省人社一体化接口规范说明书标准实现
/// 语法:long iReadCardBas(int iType, char *pOutInfo)
///
/// 操作卡的类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先
/// 输出信息缓冲区,成功时返回卡信息,失败时返回错误描述
/// 0-成功,非0-失败
[DllImport("SSCardDriver.dll", EntryPoint = "iReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static long iReadCardBas(int iType, StringBuilder pOutInfo);
#endregion
#region 江苏人社标准接口业务方法
///
/// 江苏人社标准接口:读取社保卡基本信息
/// 按照江苏省人社一体化接口规范说明书标准实现
/// 使用相同的初始化方法,但接口规范不同
///
/// 卡类型:1-接触式,2-非接触式,3-自动寻卡接触式优先,4-自动寻卡非接触式优先
/// 读卡结果
public static JObject ReadSocialCardByStandard(int cardType = 3)
{
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["interface"] = "江苏人社标准接口 v2.1.1";
return result;
}
}
// 按照规范要求分配1024字节缓冲区
StringBuilder outInfo = new StringBuilder(1024);
// 调用江苏人社标准接口
long readResult = iReadCardBas(cardType, outInfo);
if (readResult == 0)
{
string rawData = outInfo.ToString();
// 解析标准格式的社保卡信息(以|分割的格式)
var parsedData = ParseStandardCardInfo(rawData);
result["success"] = true;
result["code"] = 200;
result["message"] = "江苏人社标准接口读卡成功";
result["device"] = "江苏人社标准社保卡读卡器";
result["data"] = parsedData;
result["cardType"] = GetCardTypeName(cardType);
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
result["rawData"] = rawData; // 原始数据
result["interface"] = "江苏人社标准接口 v2.1.1";
result["interfaceType"] = "standard"; // 标记为标准接口
// 添加原始读卡数据字段(与医保接口保持一致)
result["rawCardData"] = rawData;
result["rawBusiData"] = ""; // 人社标准接口只返回一个数据流
}
else
{
string errorInfo = outInfo.ToString();
result["success"] = false;
result["code"] = 3000 + (int)readResult;
result["message"] = $"江苏人社标准接口读卡失败,错误码: {readResult}";
result["device"] = "江苏人社标准社保卡读卡器";
result["errorCode"] = readResult;
result["cardType"] = GetCardTypeName(cardType);
result["rawErrorInfo"] = errorInfo; // DLL返回的原始错误信息
result["interface"] = "江苏人社标准接口 v2.1.1";
result["interfaceType"] = "standard"; // 标记为标准接口
result["dllErrorMsg"] = errorInfo; // 与医保接口保持一致的字段名
// 添加原始读卡数据字段(失败时为空)
result["rawCardData"] = errorInfo;
result["rawBusiData"] = "";
// 根据错误码提供建议
result["suggestion"] = GetErrorSuggestion(readResult);
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 3001;
result["message"] = $"江苏人社标准接口读卡异常: {ex.Message}";
result["device"] = "江苏人社标准社保卡读卡器";
result["exception"] = ex.GetType().Name;
result["interface"] = "江苏人社标准接口 v2.1.1";
result["interfaceType"] = "standard"; // 标记为标准接口
result["dllErrorMsg"] = $"系统异常: {ex.Message}"; // 与医保接口保持一致
// 添加原始读卡数据字段(异常时为空)
result["rawCardData"] = "";
result["rawBusiData"] = "";
}
return result;
}
///
/// 解析江苏人社标准格式的社保卡信息
///
/// 原始数据(以|分割)
/// 解析后的结构化数据
private static JObject ParseStandardCardInfo(string rawData)
{
var result = new JObject();
try
{
if (string.IsNullOrEmpty(rawData))
{
result["error"] = "原始数据为空";
return result;
}
// 按照规范:发卡地区行政区划代码、社会保障号码、卡号、卡识别码、姓名、卡复位信息、规范版本、发卡日期、卡有效期、终端机编号、终端设备号、省人员识别号
string[] fields = rawData.Split('|');
if (fields.Length >= 12)
{
result["areaCode"] = fields[0]; // 发卡地区行政区划代码
result["socialSecurityNumber"] = fields[1]; // 社会保障号码
result["cardNumber"] = fields[2]; // 卡号
result["cardId"] = fields[3]; // 卡识别码
result["name"] = fields[4]; // 姓名
result["cardResetInfo"] = fields[5]; // 卡复位信息
result["specVersion"] = fields[6]; // 规范版本
result["issueDate"] = FormatDate(fields[7]); // 发卡日期
result["expireDate"] = FormatDate(fields[8]); // 卡有效期
result["terminalNumber"] = fields[9]; // 终端机编号
result["terminalDevice"] = fields[10]; // 终端设备号
result["provincePersonId"] = fields[11]; // 省人员识别号
result["parseStatus"] = "success";
result["fieldCount"] = fields.Length;
}
else
{
result["error"] = $"数据字段不足,期望12个字段,实际{fields.Length}个";
result["rawFields"] = new JArray(fields);
result["parseStatus"] = "partial";
}
}
catch (Exception ex)
{
result["error"] = $"解析异常: {ex.Message}";
result["parseStatus"] = "failed";
}
return result;
}
///
/// 获取卡类型名称
///
/// 卡类型代码
/// 卡类型名称
private static string GetCardTypeName(int cardType)
{
switch (cardType)
{
case 1: return "接触式操作卡";
case 2: return "非接触式操作卡";
case 3: return "自动寻卡(接触式优先)";
case 4: return "自动寻卡(非接触式优先)";
default: return $"未知类型({cardType})";
}
}
///
/// 根据错误码获取建议
///
/// 错误码
/// 错误建议
private static string GetErrorSuggestion(long errorCode)
{
switch (errorCode)
{
case -11:
return "请检查社保卡是否正确插入读卡器,确保卡片与读卡器接触良好";
case -1:
return "读卡器硬件可能未正确连接或驱动问题,请检查设备连接";
case -2:
return "卡片认证失败,请确认卡片为有效的社保卡";
case -3:
return "PSAM卡认证失败,请检查PSAM卡是否正确安装";
default:
return $"未知错误码 {errorCode},请联系技术支持";
}
}
#endregion
#region 配置和状态管理
///
/// 刷脸认证数据结构 - 与泰和保持一致
///
public class FaceAuthData
{
public string authNo { get; set; }
}
private static bool isInitialized = false;
private static JiangSuConfig currentConfig = null;
///
/// 江苏医保配置类 - 严格按照规范v0.9.9.15定义的13个必需参数(全部大写)
/// 注意:这里写死了测试参数,生产环境请修改为实际值
///
public class JiangSuConfig
{
///
/// 1. 服务端IP地址 - 写死测试值
///
public string IP { get; set; } = "10.61.165.3";
///
/// 2. 服务端端口 - 写死测试值
///
public int PORT { get; set; } = 8086;
///
/// 3. 超时时间(单位秒) - 写死测试值
///
public int TIMEOUT { get; set; } = 30;
///
/// 4. 动态库日志目录 - 写死测试值,确保目录存在
///
public string LOG_PATH { get; set; } = "E:\\huaihaiProject\\readCard\\ThCardReader\\logs\\";
///
/// 5. 电子凭证中台URL - 写死测试值
///
// public string EC_URL { get; set; } = "http://10.61.165.3:8086/localcfc/api/hsecfc/localQrCodeQuery";
public string EC_URL { get; set; } = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery";
///
/// 6. 社保卡验证密码方式(1:验证卡pin,2:验证数据库密码) - 写死测试值
/// 医院不需要输入密码,使用2:验证数据库密码
///
public string CARD_PASSTYPE { get; set; } = "2";
///
/// 7. CSB的_api_name - 写死测试值,请替换为实际申请的值
///
public string API_NAME { get; set; } = "hssServives";
///
/// 8. CSB的_api_version - 写死测试值
///
public string API_VERSION { get; set; } = "1.0.0";
///
/// 9. CSB的_api_access_key - 写死测试值,请替换为实际申请的值
///
public string ACCESS_KEY { get; set; } = "090ea4c914324ee38b6978365df46a80";
///
/// 10. CSB的secretKey - 写死测试值,请替换为实际申请的值
///
public string SECRETKEY { get; set; } = "CMgTEMfftMP0EMMoliOs65wZmv8=";
///
/// 11. 定点编号 - 写死测试值,请替换为医院实际编号
///
public string ORG_ID { get; set; } = "H32132200561";
///
/// 12. JSON对象字符串(预留) - 写死测试值
///
public string EXT { get; set; } = "{}";
///
/// 13. 定点所属行政区划代码 - 写死测试值(江苏宿迁沭阳)
///
public string AREA_CODE { get; set; } = "321322";
///
/// 江苏医保刷脸专用:写死的服务地址 - 与泰和完全一致的配置
///
public string FACE_SERVICE_URL { get; set; } = "http://10.58.33.207:10086/localcfc/api/hsecfc/localQrCodeQuery";
///
/// 江苏医保刷脸专用:写死的机构编号 - 与泰和完全一致的配置
///
public string FACE_ORG_ID { get; set; } = "H32132200561";
///
/// 转换为JSON字符串(严格按照规范大写参数名格式)
///
public string ToJson()
{
var configObject = 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(configObject, Formatting.None);
}
}
#endregion
#region 核心业务方法
///
/// 初始化江苏医保社保卡读取系统
///
/// 配置参数
/// 初始化结果
public static JObject Initialize(JiangSuConfig config = null)
{
var result = new JObject();
try
{
// 先检查DLL文件并确保其在正确位置
var dllCheckResult = EnsureDllExists();
if (!(bool)dllCheckResult["success"])
{
// 如果DLL检查失败,直接返回错误
return dllCheckResult;
}
// 使用默认配置或传入的配置
if (config == null)
{
config = new JiangSuConfig();
}
// 确保日志目录存在
if (!Directory.Exists(config.LOG_PATH))
{
Directory.CreateDirectory(config.LOG_PATH);
}
// 构造初始化JSON参数
string initJson = config.ToJson();
StringBuilder errMsg = new StringBuilder(2048);
// 调用DLL初始化函数
int initResult = Init(initJson, errMsg);
if (initResult == 0)
{
isInitialized = true;
currentConfig = config;
result["success"] = true;
result["code"] = 200;
result["message"] = "江苏医保社保卡系统初始化成功";
result["device"] = "江苏医保社保卡读卡器";
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
result["dllErrorMsg"] = ""; // 成功时错误信息为空
result["errMsgErrorMsg"] = errMsg.ToString(); // 输出参数pErrMsg初始化错误时候返回错误信息,成功时候返回空。
result["initJsonMsg"] = initJson; // 初始化JSON参数
result["initResultMsg"] = initResult; // 0表示成功;非0表示失败。
}
else
{
string errorMsg = errMsg.ToString();
result["success"] = false;
result["code"] = 1000 + initResult;
result["message"] = $"江苏医保系统初始化失败: {errorMsg}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = initResult;
result["dllErrorMsg"] = errorMsg; // 原始DLL错误信息
result["errMsgErrorMsg"] = errMsg.ToString(); // 输出参数pErrMsg初始化错误时候返回错误信息,成功时候返回空。
result["initJsonMsg"] = initJson; // 初始化JSON参数
result["initResultMsg"] = initResult; // 0表示成功;非0表示失败。
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 1001;
result["message"] = $"江苏医保系统初始化异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
result["dllErrorMsg"] = $"系统异常: {ex.Message}"; // 异常时的错误信息
}
return result;
}
///
/// 读取社保卡基本信息
/// 返回标准38号文格式数据
///
/// 是否自动验证PIN码
/// 是否自动初始化(默认false保持向后兼容)
/// 读卡结果
public static JObject ReadSocialCard(bool autoVerifyPIN = false, bool autoInit = false)
{
var result = new JObject();
try
{
// 检查初始化状态
if (!isInitialized)
{
if (autoInit)
{
// 智能初始化模式:自动使用默认配置初始化
var autoInitResult = Initialize();
if (!(bool)autoInitResult["success"])
{
result["success"] = false;
result["code"] = 1002;
result["message"] = "江苏医保系统自动初始化失败,请检查设备连接";
result["device"] = "江苏医保社保卡读卡器";
result["autoInitError"] = autoInitResult["message"];
result["interface"] = "江苏医保接口 v0.9.9.15";
result["interfaceType"] = "medical";
result["initMode"] = "auto";
return result;
}
else
{
// 自动初始化成功,记录日志
result["autoInitSuccess"] = true;
result["initMode"] = "auto";
}
}
else
{
// 严格模式:保持原有行为,要求用户先初始化
result["success"] = false;
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化,请先调用初始化接口";
result["device"] = "江苏医保社保卡读卡器";
result["interface"] = "江苏医保接口 v0.9.9.15";
result["interfaceType"] = "medical";
result["initMode"] = "strict";
result["suggestion"] = "请先调用 Initialize() 方法或设置 autoInit=true 启用自动初始化";
return result;
}
}
// 如果需要自动验证PIN码
if (autoVerifyPIN)
{
var pinResult = VerifyCardPIN();
if (!(bool)pinResult["success"])
{
return pinResult; // 返回PIN验证失败结果
}
}
// 读取社保卡信息 - 按规范要求分配内存
StringBuilder cardInfo = new StringBuilder(2048); // 基本信息缓冲区
StringBuilder busiCardInfo = new StringBuilder(8192); // 业务信息缓冲区
int readResult = ReadCardBas(cardInfo, busiCardInfo);
if (readResult == 0)
{
string rawCardData = cardInfo.ToString();
string rawBusiData = busiCardInfo.ToString();
// 解析38号文格式数据
var parsedData = Parse38DocumentFormat(rawCardData, rawBusiData);
result["success"] = true;
result["code"] = 200;
result["message"] = "社保卡读取成功";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = parsedData;
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
result["interface"] = "江苏医保接口 v0.9.9.15";
result["interfaceType"] = "medical"; // 标记为医保接口
result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式
// 添加原始读卡数据
result["rawCardData"] = rawCardData;
result["rawBusiData"] = rawBusiData;
}
else
{
result["success"] = false;
result["code"] = 2000 + readResult;
result["message"] = $"社保卡读取失败,错误码: {readResult}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = readResult;
result["interface"] = "江苏医保接口 v0.9.9.15";
result["interfaceType"] = "medical"; // 标记为医保接口
result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式
// 读卡失败时也记录原始数据(可能为空)
result["rawCardData"] = cardInfo.ToString();
result["rawBusiData"] = busiCardInfo.ToString();
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 2001;
result["message"] = $"社保卡读取异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
result["interface"] = "江苏医保接口 v0.9.9.15";
result["interfaceType"] = "medical"; // 标记为医保接口
result["initMode"] = autoInit ? "auto" : "manual"; // 记录初始化模式
}
return result;
}
///
/// 验证社保卡PIN码
///
/// 验证结果
public static JObject VerifyCardPIN()
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["success"] = false;
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
StringBuilder outBuff = new StringBuilder(1024);
int verifyResult = VerifyPIN(outBuff);
if (verifyResult == 0)
{
result["success"] = true;
result["code"] = 200;
result["message"] = "PIN码验证成功";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = outBuff.ToString();
}
else
{
result["success"] = false;
result["code"] = 3000 + verifyResult;
result["message"] = $"PIN码验证失败,错误码: {verifyResult}";
result["errorCode"] = verifyResult;
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 3001;
result["message"] = $"PIN码验证异常: {ex.Message}";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 修改社保卡PIN码
///
/// 修改结果
public static JObject ChangeCardPIN()
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["success"] = false;
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
StringBuilder outBuff = new StringBuilder(1024);
int changeResult = ChangePIN(outBuff);
if (changeResult == 0)
{
result["success"] = true;
result["code"] = 200;
result["message"] = "PIN码修改成功";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = outBuff.ToString();
}
else
{
result["success"] = false;
result["code"] = 4000 + changeResult;
result["message"] = $"PIN码修改失败,错误码: {changeResult}";
result["errorCode"] = changeResult;
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 4001;
result["message"] = $"PIN码修改异常: {ex.Message}";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 四合一介质获取个人信息
/// 支持社保卡、电子凭证、电子社保卡、身份证
///
/// 介质类型
/// 输入数据
/// 个人信息
public static JObject GetPersonInfo(string mediaType = "socialcard", string inputData = "")
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["success"] = false;
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
// 构造输入参数JSON
var inputObject = new
{
mediaType = mediaType,
inputData = inputData
};
string inputJson = JsonConvert.SerializeObject(inputObject);
StringBuilder outData = new StringBuilder(8192);
int getResult = GetPersonInfo(inputJson, outData);
if (getResult == 0)
{
string responseData = outData.ToString();
var parsedInfo = ParsePersonInfo(responseData, mediaType);
result["success"] = true;
result["code"] = 200;
result["message"] = "个人信息获取成功";
result["device"] = "江苏医保社保卡读卡器";
result["mediaType"] = mediaType;
result["data"] = parsedInfo;
}
else
{
result["success"] = false;
result["code"] = 5000 + getResult;
result["message"] = $"个人信息获取失败,错误码: {getResult}";
result["errorCode"] = getResult;
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 5001;
result["message"] = $"个人信息获取异常: {ex.Message}";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 获取设备状态
///
/// 设备状态信息
public static JObject GetDeviceStatus()
{
var result = new JObject();
try
{
result["success"] = true;
result["code"] = 200;
result["message"] = "设备状态获取成功";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = new JObject
{
["initialized"] = isInitialized,
["configLoaded"] = currentConfig != null,
["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 7001;
result["message"] = $"设备状态获取异常: {ex.Message}";
}
return result;
}
///
/// 重置系统内部状态
///
/// 重置结果
public static JObject ResetSystemState()
{
var result = new JObject();
try
{
// 重置内部状态(不调用DLL函数)
isInitialized = false;
currentConfig = null;
result["success"] = true;
result["code"] = 200;
result["message"] = "系统状态重置成功";
result["device"] = "江苏医保社保卡读卡器";
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 8001;
result["message"] = $"系统状态重置异常: {ex.Message}";
}
return result;
}
///
/// 确保DLL文件在正确位置
///
/// 操作结果
private static JObject EnsureDllExists()
{
var result = new JObject();
try
{
string programDir = AppDomain.CurrentDomain.BaseDirectory;
string targetDllPath = Path.Combine(programDir, "HeaSecReadInfo.dll");
// 如果目标位置已经有DLL文件,直接返回成功
if (File.Exists(targetDllPath))
{
result["success"] = true;
result["code"] = 200;
result["message"] = "HeaSecReadInfo.dll文件已就绪";
result["device"] = "江苏医保社保卡读卡器";
return result;
}
// 尝试从可能的位置复制DLL文件
string[] possiblePaths = {
// 当前目录及其子目录
Path.Combine(programDir, "HeaSecReadInfo.dll"),
Path.Combine(programDir, "bin", "Debug", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "bin", "Release", "HeaSecReadInfo.dll"),
// 上级目录搜索
Path.Combine(programDir, "..", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "..", "bin", "Debug", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "..", "bin", "Release", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "..", "..", "bin", "Debug", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "..", "..", "bin", "Release", "HeaSecReadInfo.dll"),
// ThCardReader项目目录
Path.Combine(programDir, "..", "..", "ThCardReader", "bin", "Debug", "HeaSecReadInfo.dll"),
Path.Combine(programDir, "..", "..", "ThCardReader", "bin", "Release", "HeaSecReadInfo.dll"),
// 当前工作目录
Path.Combine(Directory.GetCurrentDirectory(), "HeaSecReadInfo.dll"),
Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "HeaSecReadInfo.dll"),
Path.Combine(Directory.GetCurrentDirectory(), "bin", "Release", "HeaSecReadInfo.dll"),
// 绝对路径搜索(根据错误信息中的路径)
@"E:\huaihaiProject\readCard\ThCardReader\ThCardReader\bin\Debug\HeaSecReadInfo.dll",
@"E:\huaihaiProject\readCard\ThCardReader\bin\Debug\HeaSecReadInfo.dll"
};
string sourcePath = null;
foreach (string path in possiblePaths)
{
if (File.Exists(path))
{
sourcePath = path;
break;
}
}
if (sourcePath != null)
{
// 复制DLL文件到程序目录
File.Copy(sourcePath, targetDllPath, true);
result["success"] = true;
result["code"] = 200;
result["message"] = "HeaSecReadInfo.dll文件已复制到位";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = new JObject
{
["sourcePath"] = sourcePath,
["targetPath"] = targetDllPath
};
}
else
{
result["success"] = false;
result["code"] = 8001;
result["message"] = "找不到HeaSecReadInfo.dll文件";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = new JObject
{
["searchedPaths"] = string.Join("; ", possiblePaths),
["programDirectory"] = programDir,
["suggestion"] = "请确保HeaSecReadInfo.dll文件在程序目录或bin/Debug目录中"
};
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 8002;
result["message"] = $"DLL文件检查异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 检查DLL文件是否存在并可访问
///
/// 检查结果
public static JObject CheckDllExists()
{
var result = new JObject();
try
{
// 检查程序目录下的DLL文件
string programDir = AppDomain.CurrentDomain.BaseDirectory;
string dllPath = Path.Combine(programDir, "HeaSecReadInfo.dll");
if (File.Exists(dllPath))
{
FileInfo fileInfo = new FileInfo(dllPath);
result["success"] = true;
result["code"] = 200;
result["message"] = "HeaSecReadInfo.dll文件检查通过";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = new JObject
{
["dllPath"] = dllPath,
["fileSize"] = fileInfo.Length,
["lastModified"] = fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"),
["programDirectory"] = programDir
};
}
else
{
result["success"] = false;
result["code"] = 8001;
result["message"] = "HeaSecReadInfo.dll文件不存在";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = new JObject
{
["expectedPath"] = dllPath,
["programDirectory"] = programDir,
["suggestion"] = "请将HeaSecReadInfo.dll文件复制到程序目录"
};
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 8002;
result["message"] = $"DLL文件检查异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 诊断读卡器硬件和社保卡状态
///
/// 诊断结果
public static JObject DiagnoseCardReader()
{
var result = new JObject();
try
{
result["device"] = "江苏医保社保卡读卡器";
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var diagnostics = new JObject();
// 1. 检查DLL状态
var dllCheck = CheckDllExists();
diagnostics["dllStatus"] = dllCheck;
// 2. 检查初始化状态
diagnostics["initStatus"] = new JObject
{
["isInitialized"] = isInitialized,
["hasConfig"] = currentConfig != null,
["configDetails"] = currentConfig?.ToJson() ?? "未配置"
};
// 3. 尝试不同的读卡配置
var cardTests = new JObject();
// 测试无PIN模式
try
{
var config = new JiangSuConfig();
config.CARD_PASSTYPE = "2"; // 验证数据库密码(跳过PIN)
var initResult = Initialize(config);
var readResult = ReadSocialCard(false); // 不验证PIN
cardTests["noPinTest"] = new JObject
{
["config"] = "CARD_PASSTYPE=2(跳过PIN验证)",
["initResult"] = initResult,
["readResult"] = readResult
};
}
catch (Exception ex)
{
cardTests["noPinTest"] = new JObject
{
["config"] = "CARD_PASSTYPE=2(跳过PIN验证)",
["error"] = ex.Message
};
}
// 测试PIN模式
try
{
var config = new JiangSuConfig();
config.CARD_PASSTYPE = "1"; // 验证卡PIN
var initResult = Initialize(config);
var readResult = ReadSocialCard(false); // 不自动验证PIN
cardTests["pinTest"] = new JObject
{
["config"] = "CARD_PASSTYPE=1(需要PIN验证)",
["initResult"] = initResult,
["readResult"] = readResult
};
}
catch (Exception ex)
{
cardTests["pinTest"] = new JObject
{
["config"] = "CARD_PASSTYPE=1(需要PIN验证)",
["error"] = ex.Message
};
}
diagnostics["cardTests"] = cardTests;
// 4. 分析结果
var analysis = new JObject();
analysis["recommendations"] = new JArray();
// 检查是否有成功的读卡
bool hasSuccessfulRead = false;
if (cardTests["noPinTest"] != null && cardTests["noPinTest"]["readResult"] != null)
{
var noPinResult = (JObject)cardTests["noPinTest"]["readResult"];
if (noPinResult["success"] != null && (bool)noPinResult["success"])
{
hasSuccessfulRead = true;
((JArray)analysis["recommendations"]).Add("✅ 使用CARD_PASSTYPE=2可以成功读卡");
}
else if (noPinResult["errorCode"] != null)
{
int errorCode = (int)noPinResult["errorCode"];
if (errorCode == -11)
{
((JArray)analysis["recommendations"]).Add("⚠️ 错误码-11:请检查社保卡是否正确插入并接触良好");
}
}
}
if (cardTests["pinTest"] != null && cardTests["pinTest"]["readResult"] != null)
{
var pinResult = (JObject)cardTests["pinTest"]["readResult"];
if (pinResult["success"] != null && (bool)pinResult["success"])
{
hasSuccessfulRead = true;
((JArray)analysis["recommendations"]).Add("✅ 使用CARD_PASSTYPE=1可以成功读卡");
}
}
if (!hasSuccessfulRead)
{
((JArray)analysis["recommendations"]).Add("❌ 两种模式都无法读卡,可能的原因:");
((JArray)analysis["recommendations"]).Add(" 1. 社保卡未正确插入或损坏");
((JArray)analysis["recommendations"]).Add(" 2. 读卡器硬件故障或驱动问题");
((JArray)analysis["recommendations"]).Add(" 3. 网络配置参数错误");
((JArray)analysis["recommendations"]).Add(" 4. DLL文件版本不匹配");
}
analysis["overallStatus"] = hasSuccessfulRead ? "正常" : "异常";
diagnostics["analysis"] = analysis;
result["success"] = true;
result["code"] = 200;
result["message"] = "读卡器诊断完成";
result["data"] = diagnostics;
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 9001;
result["message"] = $"读卡器诊断异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 离线模式读取社保卡(跳过网络验证,仅测试本地读卡功能)
///
/// 读卡结果
public static JObject ReadSocialCardOffline()
{
var result = new JObject();
try
{
// 使用最简配置进行本地测试
var offlineConfig = new JiangSuConfig();
offlineConfig.IP = "127.0.0.1"; // 本地IP
offlineConfig.PORT = 8080; // 本地端口
offlineConfig.EC_URL = ""; // 空URL跳过网络验证
offlineConfig.ACCESS_KEY = ""; // 空密钥
offlineConfig.SECRETKEY = ""; // 空密钥
// 构造最简初始化参数
var simpleConfig = new
{
IP = "127.0.0.1",
PORT = 8080,
TIMEOUT = 5,
LOG_PATH = offlineConfig.LOG_PATH,
CARD_PASSTYPE = "2", // 跳过PIN验证
EC_URL = "",
API_NAME = "",
API_VERSION = "",
ACCESS_KEY = "",
SECRETKEY = "",
ORG_ID = "",
EXT = "{}",
AREA_CODE = ""
};
string initJson = JsonConvert.SerializeObject(simpleConfig, Formatting.None);
StringBuilder errMsg = new StringBuilder(2048);
// 尝试离线初始化
int initResult = Init(initJson, errMsg);
if (initResult == 0)
{
// 初始化成功,尝试读卡
isInitialized = true;
currentConfig = offlineConfig;
StringBuilder cardInfo = new StringBuilder(2048);
StringBuilder busiCardInfo = new StringBuilder(8192);
int readResult = ReadCardBas(cardInfo, busiCardInfo);
if (readResult == 0)
{
string rawCardData = cardInfo.ToString();
string rawBusiData = busiCardInfo.ToString();
var parsedData = Parse38DocumentFormat(rawCardData, rawBusiData);
result["success"] = true;
result["code"] = 200;
result["message"] = "离线模式读卡成功";
result["device"] = "江苏医保社保卡读卡器(离线模式)";
result["data"] = parsedData;
result["mode"] = "offline";
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
result["dllErrorMsg"] = ""; // 成功时错误信息为空
// 添加原始读卡数据
result["rawCardData"] = rawCardData;
result["rawBusiData"] = rawBusiData;
}
else
{
result["success"] = false;
result["code"] = 2000 + readResult;
result["message"] = $"离线模式读卡失败,错误码: {readResult}";
result["device"] = "江苏医保社保卡读卡器(离线模式)";
result["mode"] = "offline";
result["errorCode"] = readResult;
result["dllErrorMsg"] = ""; // 读卡失败,但初始化成功
// 读卡失败时也记录原始数据(可能为空)
result["rawCardData"] = cardInfo.ToString();
result["rawBusiData"] = busiCardInfo.ToString();
if (readResult == -11)
{
result["suggestion"] = "请检查社保卡是否正确插入读卡器";
}
else if (readResult == -1)
{
result["suggestion"] = "读卡器硬件可能未正确连接或驱动问题";
}
}
}
else
{
string errorMsg = errMsg.ToString();
result["success"] = false;
result["code"] = 1000 + initResult;
result["message"] = $"离线模式初始化失败: {errorMsg}";
result["device"] = "江苏医保社保卡读卡器(离线模式)";
result["mode"] = "offline";
result["errorCode"] = initResult;
result["dllErrorMsg"] = errorMsg; // 原始DLL错误信息
}
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 9999;
result["message"] = $"离线模式异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器(离线模式)";
result["mode"] = "offline";
result["exception"] = ex.GetType().Name;
result["dllErrorMsg"] = $"离线模式异常: {ex.Message}"; // 异常时的错误信息
}
return result;
}
///
/// 测试不同网络配置对初始化的影响
///
/// 测试结果
public static JObject TestNetworkConfigurations()
{
var result = new JObject();
var tests = new JObject();
try
{
// 测试1:使用原始配置(10.61.165.3:8086)
var config1 = new JiangSuConfig();
config1.IP = "10.61.165.3";
config1.PORT = 8086;
config1.EC_URL = "http://10.61.165.3:8086/localcfc/api/hsecfc/localQrCodeQuery";
var test1 = TestSingleConfig(config1, "原始配置(10.61.165.3:8086)");
tests["originalConfig"] = test1;
// 测试2:使用HSM配置(10.79.157.29:8089)
var config2 = new JiangSuConfig();
config2.IP = "10.79.157.29";
config2.PORT = 8089;
config2.EC_URL = "http://10.79.157.29:8089/encryptionMachine/encryptionMachineBusiness";
var test2 = TestSingleConfig(config2, "HSM配置(10.79.157.29:8089)");
tests["hsmConfig"] = test2;
// 测试3:使用无效配置
var config3 = new JiangSuConfig();
config3.IP = "192.168.1.1";
config3.PORT = 9999;
config3.EC_URL = "http://192.168.1.1:9999/invalid";
var test3 = TestSingleConfig(config3, "无效配置(192.168.1.1:9999)");
tests["invalidConfig"] = test3;
// 测试4:空配置
var config4 = new JiangSuConfig();
config4.IP = "";
config4.PORT = 0;
config4.EC_URL = "";
config4.ACCESS_KEY = "";
config4.SECRETKEY = "";
var test4 = TestSingleConfig(config4, "空配置");
tests["emptyConfig"] = test4;
result["success"] = true;
result["code"] = 200;
result["message"] = "网络配置测试完成";
result["tests"] = tests;
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 分析结果
var analysis = new JArray();
foreach (var test in tests)
{
var testResult = (JObject)test.Value;
var errorCode = testResult["errorCode"]?.ToString() ?? "无";
var config = testResult["configName"]?.ToString() ?? "未知";
analysis.Add($"{config}: 错误码 {errorCode}");
}
result["analysis"] = analysis;
}
catch (Exception ex)
{
result["success"] = false;
result["code"] = 9001;
result["message"] = $"网络配置测试异常: {ex.Message}";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 测试单个配置
///
private static JObject TestSingleConfig(JiangSuConfig config, string configName)
{
var testResult = new JObject();
testResult["configName"] = configName;
testResult["config"] = JObject.Parse(config.ToJson());
try
{
string initJson = config.ToJson();
StringBuilder errMsg = new StringBuilder(2048);
int initResult = Init(initJson, errMsg);
testResult["initResult"] = initResult;
testResult["errorMessage"] = errMsg.ToString();
testResult["errorCode"] = initResult;
testResult["dllErrorMsg"] = errMsg.ToString(); // 原始DLL错误信息
if (initResult == 0)
{
testResult["status"] = "初始化成功";
// 如果初始化成功,尝试读卡
StringBuilder cardInfo = new StringBuilder(2048);
StringBuilder busiCardInfo = new StringBuilder(8192);
int readResult = ReadCardBas(cardInfo, busiCardInfo);
testResult["readResult"] = readResult;
testResult["readStatus"] = readResult == 0 ? "读卡成功" : $"读卡失败,错误码: {readResult}";
}
else
{
testResult["status"] = $"初始化失败,错误码: {initResult}";
}
}
catch (Exception ex)
{
testResult["status"] = "测试异常";
testResult["error"] = ex.Message;
testResult["errorCode"] = -999;
testResult["dllErrorMsg"] = $"测试异常: {ex.Message}"; // 异常时的错误信息
}
return testResult;
}
#endregion
#region 电子凭证解码功能 (按照江苏医保接口规范v0.9.9.15实现)
///
/// 江苏医保电子凭证解码
/// 严格按照《医疗保障信息平台定点基线版医药机构接口规范 v0.9.9.15》中的1.14.6电子凭证解码接口实现
///
/// 用码业务类型,如:01101-门诊挂号,01301-门诊结算,02121-药店购药
/// 收款员编号
/// 收款员姓名
/// 医保科室编号
/// 科室名称
/// 电子凭证解码结果
public static JObject ReadElectronicCertificate(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";
// 添加兼容字段(与前端保持一致,采用泰和医院格式)
result["readCardResult"] = JsonConvert.SerializeObject(dllResponseFormat);
}
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;
}
///
/// 根据业务场景获取科室名称
///
/// 业务类型代码
/// 科室名称
private static string GetDepartmentNameByBusinessType(string businessType)
{
switch (businessType)
{
case "01101": // 门诊挂号
return "挂号处";
case "01201": // 门诊问诊
case "01202": // 预约检查
case "01203": // 检查
case "01204": // 治疗
return "门诊科室";
case "01301": // 门诊结算
return "门诊收费处";
case "01302": // 取药
return "门诊药房";
case "01102": // 住院建档
case "01103": // 入院登记
case "01104": // 缴纳预缴金
return "住院处";
case "02121": // 药店购药
case "02122": // 下载外购处方
return "药店";
default:
return "医保科";
}
}
///
/// 获取EcQuery错误码对应的建议
///
/// 错误码
/// 错误建议
private static string GetEcQueryErrorSuggestion(int errorCode)
{
switch (errorCode)
{
case -1:
return "网络连接失败,请检查网络连接和医保平台服务状态";
case -2:
return "身份认证失败,请检查ACCESS_KEY和SECRET_KEY配置";
case -3:
return "参数格式错误,请检查业务类型和定点编号配置";
case -4:
return "电子凭证已过期,请提示患者刷新电子凭证";
case -5:
return "参保地不匹配,请确认患者参保地信息";
default:
return "电子凭证解码失败,请检查设备连接和配置信息";
}
}
///
/// 验证业务类型代码是否有效
///
/// 业务类型代码
/// 是否有效
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", // 结算、取药、取报告、打印票据和清单、病历材料复印
// 药店业务类型
"02121", "02122" // 药店购药、下载外购处方
};
return validTypes.Contains(businessType);
}
#endregion
#region 数据解析方法
///
/// 解析38号文格式的社保卡数据
///
/// 卡基本信息
/// 业务信息
/// 解析后的数据
private static JObject Parse38DocumentFormat(string cardData, string busiData)
{
var result = new JObject();
try
{
// 按照38号文格式解析,使用管道符"|"分隔
string[] cardFields = cardData.Split('|');
if (cardFields.Length >= 11)
{
result["areaCode"] = cardFields[0]; // 发卡地区行政区划代码
result["socialSecurityNumber"] = cardFields[1]; // 社会保障号码
result["cardNumber"] = cardFields[2]; // 卡号
result["cardId"] = cardFields[3]; // 卡识别码
result["name"] = cardFields[4]; // 姓名
result["cardResetInfo"] = cardFields[5]; // 卡复位信息
result["specVersion"] = cardFields[6]; // 规范版本
result["issueDate"] = FormatDate(cardFields[7]); // 发卡日期
result["expireDate"] = FormatDate(cardFields[8]); // 卡有效期
result["terminalNumber"] = cardFields[9]; // 终端机编号
result["terminalDevice"] = cardFields[10]; // 终端设备号
}
// 解析业务信息(如果有)
if (!string.IsNullOrEmpty(busiData))
{
result["businessInfo"] = busiData;
}
result["format"] = "38号文标准格式";
result["parseTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
catch (Exception ex)
{
result["error"] = $"数据解析失败: {ex.Message}";
}
return result;
}
///
/// 解析四合一介质的个人信息
///
/// 响应数据
/// 介质类型
/// 解析后的个人信息
private static JObject ParsePersonInfo(string responseData, string mediaType)
{
var result = new JObject();
try
{
// 尝试解析JSON格式的响应
if (responseData.StartsWith("{"))
{
var jsonData = JObject.Parse(responseData);
result = jsonData;
}
else
{
// 如果不是JSON,按不同介质类型解析
switch (mediaType.ToLower())
{
case "socialcard":
// 社保卡:按38号文格式解析
result = Parse38DocumentFormat(responseData, "");
break;
case "idcard":
// 身份证:按身份证格式解析
string[] idFields = responseData.Split('|');
if (idFields.Length >= 8)
{
result["idNumber"] = idFields[0];
result["name"] = idFields[1];
result["sex"] = idFields[2];
result["nation"] = idFields[3];
result["birthday"] = FormatDate(idFields[4]);
result["address"] = idFields[5];
result["issueDate"] = FormatDate(idFields[6]);
result["validDate"] = FormatDate(idFields[7]);
}
break;
case "electronic":
case "esocialcard":
// 电子凭证/电子社保卡:通常为JSON格式
result["rawData"] = responseData;
break;
default:
result["rawData"] = responseData;
break;
}
}
result["mediaType"] = mediaType;
result["parseTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
catch (Exception ex)
{
result["error"] = $"个人信息解析失败: {ex.Message}";
result["rawData"] = responseData;
}
return result;
}
///
/// 格式化日期字符串
///
/// 原始日期字符串
/// 格式化后的日期
private static string FormatDate(string dateStr)
{
if (string.IsNullOrEmpty(dateStr) || dateStr.Length < 8)
return dateStr;
// 尝试格式化YYYYMMDD为YYYY-MM-DD
if (dateStr.Length == 8 && dateStr.All(char.IsDigit))
{
return $"{dateStr.Substring(0, 4)}-{dateStr.Substring(4, 2)}-{dateStr.Substring(6, 2)}";
}
return dateStr;
}
#endregion
#region 江苏医保刷脸功能 (使用NationECCode.dll与泰和完全一致)
///
/// 江苏医保刷脸功能 - 使用NationECCode.dll与泰和完全一致
/// 完全相同的实现:相同的DLL、相同的URL、相同的逻辑、相同的参数格式
/// 唯一区别:使用写死的配置参数
///
/// 业务类型
/// 刷脸结果
public static JObject ReadFace(string biztype)
{
JObject result = new JObject();
try
{
// 使用写死的江苏医保刷脸配置参数
if (null == currentConfig)
{
currentConfig = new JiangSuConfig();
}
// 第一步:获取授权码(cn.nhsa.ec.auth)
// 补全所有参数,即使为空也带上
var data = new {
businessType = biztype,
deviceType = "",
orgId = currentConfig.FACE_ORG_ID,
outBizNo = "",
operatorId = "",
operatorName = "",
officeId = "",
officeName = ""
};
var authRequest = new {
data = data,
orgId = currentConfig.FACE_ORG_ID,
transType = "cn.nhsa.ec.auth"
};
string pindata = JsonConvert.SerializeObject(authRequest, Formatting.None);
byte[] outinfo = new byte[4096];
IntPtr retPtr = NationEcTrans(currentConfig.FACE_SERVICE_URL, pindata, ref outinfo[0]);
string businessResultCode = Marshal.PtrToStringAnsi(retPtr).Trim().Replace("\u0000", "");
string outstr = Encoding.Default.GetString(outinfo).Trim().Replace("\u0000", "");
// 检查DLL调用是否成功
if (businessResultCode != "0000")
{
result.Add("code", 1001);
result.Add("message", $"DLL调用失败,返回码: {businessResultCode}");
result.Add("type", "face");
result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)");
result.Add("businessType", biztype);
result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)");
result.Add("dllReturnCode", businessResultCode);
result.Add("dllRawResponse", outstr);
return result;
}
ReadCardResult tmp = Newtonsoft.Json.JsonConvert.DeserializeObject(outstr);
if (tmp.code == 0)
{
FaceAuthData authData = Newtonsoft.Json.JsonConvert.DeserializeObject(tmp.data.ToString());
return getUserInfoByAuthNo(biztype, authData.authNo);
}
else
{
result.Add("code", 1001);
result.Add("message", tmp.message ?? "刷脸授权获取失败");
result.Add("type", "face");
result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)");
result.Add("businessType", biztype);
result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)");
result.Add("dllReturnCode", businessResultCode);
result.Add("dllRawResponse", outstr);
result.Add("authStep", "第一步:获取授权码失败");
return result;
}
}
catch (Exception ex)
{
result.Add("code", 1001);
result.Add("message", $"江苏医保刷脸操作异常: {ex.Message}");
result.Add("type", "face");
result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)");
result.Add("businessType", biztype);
result.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
result.Add("interfaceVersion", "江苏医保刷脸v1.0(与泰和完全一致)");
result.Add("exception", ex.GetType().Name);
result.Add("exceptionMessage", ex.Message);
return result;
}
}
///
/// 根据authNo获取用户信息 - 使用NationECCode.dll与泰和完全一致
///
/// 业务类型
/// 认证号
/// 用户信息
private static JObject getUserInfoByAuthNo(string biztype, string authNo)
{
JObject result = new JObject();
try
{
// 使用写死的江苏医保刷脸配置参数
if (null == currentConfig)
{
currentConfig = new JiangSuConfig();
}
// 第二步:根据authNo获取医保身份(cn.nhsa.auth.check)
// 补全所有参数,即使为空也带上
var data = new {
businessType = biztype,
authNo = authNo,
deviceType = "",
orgId = currentConfig.FACE_ORG_ID,
outBizNo = "",
operatorId = "",
operatorName = "",
officeId = "",
officeName = ""
};
var checkRequest = new {
data = data,
orgId = currentConfig.FACE_ORG_ID,
transType = "cn.nhsa.auth.check"
};
string pindata = JsonConvert.SerializeObject(checkRequest, Formatting.None);
byte[] outinfo = new byte[4096];
IntPtr retPtr = NationEcTrans(currentConfig.FACE_SERVICE_URL, pindata, ref outinfo[0]);
string businessResultCode = Marshal.PtrToStringAnsi(retPtr).Trim().Replace("\u0000", "");
string outstr = Encoding.Default.GetString(outinfo).Trim().Replace("\u0000", "");
ReadCardResult tmp = Newtonsoft.Json.JsonConvert.DeserializeObject(outstr);
if (tmp.code == 0)
{
result.Add("code", 200);
result.Add("message", "刷脸获取医保身份成功。");
result.Add("type", "face");
result.Add("data", outstr);
result.Add("sign", null);
}
else
{
result.Add("code", 1001);
result.Add("message", tmp.message ?? "获取医保身份失败");
}
}
catch (Exception ex)
{
result.Add("code", 1001);
result.Add("message", $"获取医保身份异常: {ex.Message}");
}
return result;
}
#endregion
}
}