using System;
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 - 仅包含核心必需函数
// 1.14.1 初始化
[DllImport("HeaSecReadInfo.dll", EntryPoint = "Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 Init(string pInitInfo, StringBuilder pErrMsg);
// 1.14.2 读社保卡基本信息
[DllImport("HeaSecReadInfo.dll", EntryPoint = "ReadCardBas", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 ReadCardBas(StringBuilder pCardInfo, StringBuilder pBusiCardInfo);
// 1.14.3 检验PIN码
[DllImport("HeaSecReadInfo.dll", EntryPoint = "VerifyPIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 VerifyPIN(StringBuilder pOutBuff);
// 1.14.4 修改PIN码
[DllImport("HeaSecReadInfo.dll", EntryPoint = "ChangePIN", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 ChangePIN(StringBuilder pOutBuff);
// 1.14.8 四合一介质获得个人信息
[DllImport("HeaSecReadInfo.dll", EntryPoint = "GetPersonInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private extern static Int32 GetPersonInfo(string pInData, StringBuilder pOutData);
// 注意:已移除不存在的Close函数和其他非核心函数
// 如需要其他功能,可根据实际DLL文件情况后续添加
#endregion
#region 配置和状态
private static bool isInitialized = false;
private static JiangSuConfig currentConfig = null;
public class JiangSuConfig
{
public string IP { get; set; } = "192.168.100.100";
public int PORT { get; set; } = 8080;
public int TIMEOUT { get; set; } = 120;
public string LOG_PATH { get; set; } = "C:\\logs\\jiangsu\\";
public string CARD_PASSTYPE { get; set; } = "1";
public string EC_URL { get; set; } = "https://fuwu-test.nhsa.gov.cn/localcfc/api/hsecfc/localQrCodeQuery";
public string API_NAME { get; set; } = "api-powersi-test-pri";
public string API_VERSION { get; set; } = "1.0.0";
public string ACCESS_KEY { get; set; } = "";
public string SECRETKEY { get; set; } = "";
public string ORG_ID { get; set; } = "";
public string AREA_CODE { get; set; } = "320100";
public string EXT { get; set; } = "";
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.None);
}
}
#endregion
#region 核心业务方法
///
/// 初始化江苏医保社保卡读取系统
/// 参考华视读卡器的初始化流程
///
public static JObject Initialize(JiangSuConfig config = null)
{
var result = new JObject();
try
{
// 使用默认配置或传入的配置
if (config == null)
{
config = new JiangSuConfig();
}
// 构造初始化JSON参数
string initJson = config.ToJson();
StringBuilder errMsg = new StringBuilder(2048);
// 调用DLL初始化函数
int initResult = Init(initJson, errMsg);
if (initResult == 0)
{
isInitialized = true;
currentConfig = config;
result["code"] = 200;
result["message"] = "江苏医保社保卡系统初始化成功";
result["device"] = "江苏医保社保卡读卡器";
result["config"] = JObject.FromObject(config);
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
string errorMsg = errMsg.ToString();
result["code"] = 1000 + initResult;
result["message"] = $"江苏医保系统初始化失败: {errorMsg}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = initResult;
}
}
catch (Exception ex)
{
result["code"] = 1001;
result["message"] = $"江苏医保系统初始化异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 读取社保卡基本信息
/// 返回标准38号文格式数据
///
public static JObject ReadSocialCard(bool autoVerifyPIN = false)
{
var result = new JObject();
try
{
// 检查初始化状态
if (!isInitialized)
{
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化,请先调用初始化接口";
result["device"] = "江苏医保社保卡读卡器";
return result;
}
// 如果需要自动验证PIN码
if (autoVerifyPIN)
{
var pinResult = VerifyCardPIN();
if ((int)pinResult["code"] != 200)
{
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["code"] = 200;
result["message"] = "社保卡读取成功";
result["device"] = "江苏医保社保卡读卡器";
result["data"] = parsedData;
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
result["code"] = 2000 + readResult;
result["message"] = $"社保卡读取失败,错误码: {readResult}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = readResult;
}
}
catch (Exception ex)
{
result["code"] = 2001;
result["message"] = $"社保卡读取异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
result["exception"] = ex.GetType().Name;
}
return result;
}
///
/// 验证社保卡PIN码
///
public static JObject VerifyCardPIN()
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
StringBuilder outBuff = new StringBuilder(1024);
int pinResult = VerifyPIN(outBuff);
if (pinResult == 0)
{
result["code"] = 200;
result["message"] = "PIN码验证成功";
result["device"] = "江苏医保社保卡读卡器";
}
else
{
string errorMsg = outBuff.ToString();
result["code"] = 3000 + pinResult;
result["message"] = $"PIN码验证失败: {errorMsg}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = pinResult;
}
}
catch (Exception ex)
{
result["code"] = 3001;
result["message"] = $"PIN码验证异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
}
return result;
}
///
/// 修改社保卡PIN码
///
public static JObject ChangeCardPIN()
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
StringBuilder outBuff = new StringBuilder(1024);
int changeResult = ChangePIN(outBuff);
if (changeResult == 0)
{
result["code"] = 200;
result["message"] = "PIN码修改成功";
result["device"] = "江苏医保社保卡读卡器";
}
else
{
string errorMsg = outBuff.ToString();
result["code"] = 4000 + changeResult;
result["message"] = $"PIN码修改失败: {errorMsg}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = changeResult;
}
}
catch (Exception ex)
{
result["code"] = 4001;
result["message"] = $"PIN码修改异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
}
return result;
}
///
/// 四合一介质支持 - 获取个人信息
/// 按照官方规范1.14.8实现,支持:社保卡、电子凭证、电子社保卡、身份证
///
public static JObject GetPersonInfo(string mediaType = "socialcard", string inputData = "")
{
var result = new JObject();
try
{
if (!isInitialized)
{
result["code"] = 1002;
result["message"] = "江苏医保系统未初始化";
return result;
}
// 按照官方规范1.14.8.4构造输入参数JSON
string jsonInput = "";
if (!string.IsNullOrEmpty(inputData))
{
// 使用提供的输入数据
jsonInput = inputData;
}
else
{
// 构造默认的输入参数
var defaultInput = new JObject
{
["data"] = new JObject
{
["orgId"] = currentConfig?.ORG_ID ?? "",
["businessType"] = "01101", // 默认:医院挂号
["operatorId"] = "test001",
["operatorName"] = "操作员",
["officeId"] = "32760",
["officeName"] = "医保科"
},
["transType"] = "ec.query",
["orgId"] = currentConfig?.ORG_ID ?? ""
};
jsonInput = defaultInput.ToString(Formatting.None);
}
StringBuilder outData = new StringBuilder(8192);
int getResult = GetPersonInfo(jsonInput, outData);
if (getResult == 0)
{
string responseData = outData.ToString();
result["code"] = 200;
result["message"] = "个人信息获取成功";
result["device"] = "江苏医保社保卡读卡器";
result["mediaType"] = mediaType;
result["data"] = ParsePersonInfo(responseData, mediaType);
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
result["code"] = 5000 + getResult;
result["message"] = $"个人信息获取失败,错误码: {getResult}";
result["device"] = "江苏医保社保卡读卡器";
result["errorCode"] = getResult;
}
}
catch (Exception ex)
{
result["code"] = 5001;
result["message"] = $"个人信息获取异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
}
return result;
}
///
/// 获取设备状态
///
public static JObject GetDeviceStatus()
{
var result = new JObject();
try
{
result["code"] = 200;
result["message"] = "设备状态正常";
result["device"] = "江苏医保社保卡读卡器";
result["status"] = new JObject
{
["initialized"] = isInitialized,
["config"] = currentConfig != null ? JObject.FromObject(currentConfig) : null,
["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
}
catch (Exception ex)
{
result["code"] = 7001;
result["message"] = $"获取设备状态异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
}
return result;
}
///
/// 重置系统内部状态
/// 注意:江苏医保接口规范中没有Close函数,此方法仅重置本地缓存的状态信息
///
public static JObject ResetSystemState()
{
var result = new JObject();
try
{
// 江苏医保接口规范中没有Close函数,仅重置内部状态
// 这里不调用任何DLL函数,只是清理本地状态
isInitialized = false;
currentConfig = null;
result["code"] = 200;
result["message"] = "江苏医保系统内部状态已重置";
result["device"] = "江苏医保社保卡读卡器";
result["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
result["note"] = "此操作仅重置本地状态缓存,不调用DLL关闭函数(规范中不存在)";
}
catch (Exception ex)
{
result["code"] = 6001;
result["message"] = $"状态重置异常: {ex.Message}";
result["device"] = "江苏医保社保卡读卡器";
}
return result;
}
#endregion
#region 数据解析方法
///
/// 解析38号文格式数据
/// 格式:发卡地区|社保号|卡号|卡识别码|姓名|复位信息|版本|发卡日期|有效期|终端机号|设备号|
///
private static JObject Parse38DocumentFormat(string cardData, string busiData)
{
var result = new JObject();
try
{
if (string.IsNullOrEmpty(cardData))
{
result["error"] = "卡片数据为空";
return result;
}
string[] parts = cardData.Split('|');
if (parts.Length >= 11)
{
result["region"] = "JiangSu";
result["issueArea"] = parts[0]; // 发卡地区
result["socialSecurityNumber"] = parts[1]; // 社保号
result["cardNumber"] = parts[2]; // 卡号
result["cardIdentifier"] = parts[3]; // 卡识别码
result["name"] = parts[4]; // 姓名
result["resetInfo"] = parts[5]; // 复位信息
result["version"] = parts[6]; // 版本
result["issueDate"] = FormatDate(parts[7]); // 发卡日期
result["validDate"] = FormatDate(parts[8]); // 有效期
result["terminalId"] = parts[9]; // 终端机号
result["deviceId"] = parts[10]; // 设备号
// 业务数据
result["busiCardInfo"] = busiData;
result["rawData"] = cardData;
// 提取身份证号(如果可能)
result["idNumber"] = ExtractIdFromSSN(parts[1]);
}
else
{
result["error"] = $"数据格式不正确,期望11个字段,实际{parts.Length}个字段";
result["rawData"] = cardData;
}
}
catch (Exception ex)
{
result["error"] = $"数据解析异常: {ex.Message}";
result["rawData"] = cardData;
}
return result;
}
///
/// 解析个人信息数据
/// 按照官方规范1.14.8不同介质的输出格式解析
///
private static JObject ParsePersonInfo(string responseData, string mediaType)
{
var result = new JObject();
try
{
// 首先尝试解析为JSON格式(官方规范要求的输出格式)
try
{
var jsonData = JObject.Parse(responseData);
// 检查是否有code字段表示成功
if (jsonData["code"] != null && jsonData["code"].Value() == 0)
{
var data = jsonData["data"];
if (data != null)
{
// 根据数据内容判断实际的介质类型
if (data["CardInfo"] != null && data["BusiCardInfo"] != null)
{
// 社保卡格式:包含CardInfo和BusiCardInfo
result = Parse38DocumentFormat(data["CardInfo"].ToString(), data["BusiCardInfo"].ToString());
result["mediaType"] = "社保卡";
}
else if (data["idNo"] != null && data["ecToken"] != null)
{
// 电子凭证格式:包含idNo和ecToken
result["mediaType"] = "电子凭证";
result["idNo"] = data["idNo"];
result["userName"] = data["userName"];
result["idType"] = data["idType"];
result["ecToken"] = data["ecToken"];
result["insuOrg"] = data["insuOrg"];
result["ecIndexNo"] = data["ecIndexNo"];
result["gender"] = data["gender"];
result["birthday"] = data["birthday"];
result["nationality"] = data["nationality"];
result["email"] = data["email"];
result["extra"] = data["extra"];
}
else if (data["si_no"] != null && data["ecCardToken"] != null)
{
// 电子社保卡格式:包含si_no和ecCardToken
result["mediaType"] = "电子社保卡";
result["si_no"] = data["si_no"];
result["si_card_no"] = data["si_card_no"];
result["si_card_issue_area"] = data["si_card_issue_area"];
result["name"] = data["name"];
result["gender"] = data["gender"];
result["id_type"] = data["id_type"];
result["id_no"] = data["id_no"];
result["ecCardToken"] = data["ecCardToken"];
}
else if (data["SFZInfo"] != null && data["BusiSFZInfo"] != null)
{
// 身份证格式:包含SFZInfo和BusiSFZInfo
result["mediaType"] = "身份证";
result["SFZInfo"] = data["SFZInfo"];
result["BusiSFZInfo"] = data["BusiSFZInfo"];
// 解析身份证信息字符串
string[] sfzParts = data["SFZInfo"].ToString().Split('|');
if (sfzParts.Length >= 9)
{
result["idNumber"] = sfzParts[0];
result["name"] = sfzParts[1];
result["gender"] = sfzParts[2];
result["nation"] = sfzParts[3];
result["birthday"] = FormatDate(sfzParts[4]);
result["address"] = sfzParts[5];
result["issueOrg"] = sfzParts[6];
result["validFrom"] = FormatDate(sfzParts[7]);
result["validTo"] = FormatDate(sfzParts[8]);
}
}
else
{
// 未知格式,保存原始数据
result["mediaType"] = "未知";
result["data"] = data;
}
}
result["code"] = jsonData["code"];
result["message"] = jsonData["message"];
}
else
{
// DLL返回错误
result["error"] = jsonData["message"]?.ToString() ?? "获取个人信息失败";
result["code"] = jsonData["code"];
}
}
catch (JsonException)
{
// 不是JSON格式,按照传统字符串格式处理
switch (mediaType.ToLower())
{
case "socialcard":
result = Parse38DocumentFormat(responseData, "");
result["mediaType"] = "社保卡";
break;
default:
result["mediaType"] = mediaType;
result["rawData"] = responseData;
break;
}
}
result["rawData"] = responseData;
}
catch (Exception ex)
{
result["error"] = $"个人信息解析异常: {ex.Message}";
result["mediaType"] = mediaType;
result["rawData"] = responseData;
}
return result;
}
///
/// 从社保号提取身份证号
///
private static string ExtractIdFromSSN(string ssn)
{
if (string.IsNullOrEmpty(ssn) || ssn.Length < 18)
return "";
// 简单假设:如果社保号是18位,可能就是身份证号
if (ssn.Length == 18)
return ssn;
return "";
}
///
/// 格式化日期 YYYYMMDD -> YYYY-MM-DD
///
private static string FormatDate(string dateStr)
{
if (string.IsNullOrEmpty(dateStr) || dateStr.Length != 8)
return dateStr;
try
{
return $"{dateStr.Substring(0, 4)}-{dateStr.Substring(4, 2)}-{dateStr.Substring(6, 2)}";
}
catch
{
return dateStr;
}
}
#endregion
}
}