新增CA接口

1.增加北京数字认证的CA接口
2.修复团体登记界面的取消应用按钮的校验逻辑
dhzzyy
LiJiaWen 6 days ago
parent f7dd78b4dc
commit cf81bbc6fd
  1. 62
      PEIS/LoginForm.Designer.cs
  2. 119
      PEIS/LoginForm.cs
  3. 2
      PEIS/Model/Enrollment/EnrollmentOrgFeeItemModel.cs
  4. 12
      PEIS/Model/UserModel.cs
  5. 8
      PEIS/PEIS.csproj
  6. 168
      PEIS/Utils/CAHelper.cs
  7. 32
      PEIS/Utils/Global.cs
  8. 14
      PEIS/View/Enrollment/EnrollmentOrgForm.cs
  9. 96
      PEIS/View/Exam/TotalForm.cs
  10. 1
      PEIS/packages.config

@ -1,4 +1,4 @@
namespace PEIS
namespace PEIS
{
partial class LoginForm
{
@ -40,7 +40,12 @@
this.BtnOk = new System.Windows.Forms.Button();
this.label4 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.pbQrCode = new System.Windows.Forms.PictureBox();
this.labelQrCode = new System.Windows.Forms.Label();
this.btnRefreshQrCode = new System.Windows.Forms.Button();
this.labelQrStatus = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pbQrCode)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
@ -162,6 +167,52 @@
this.label5.Text = "Copyright @ 2023 云南新八达科技有限公司 All Rights Reserved";
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// pbQrCode
//
this.pbQrCode.BackColor = System.Drawing.Color.White;
this.pbQrCode.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.pbQrCode.Location = new System.Drawing.Point(580, 180);
this.pbQrCode.Name = "pbQrCode";
this.pbQrCode.Size = new System.Drawing.Size(200, 200);
this.pbQrCode.TabIndex = 11;
this.pbQrCode.TabStop = false;
//
// labelQrCode
//
this.labelQrCode.AutoSize = true;
this.labelQrCode.BackColor = System.Drawing.Color.Transparent;
this.labelQrCode.Font = new System.Drawing.Font("微软雅黑", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.labelQrCode.ForeColor = System.Drawing.Color.White;
this.labelQrCode.Location = new System.Drawing.Point(620, 140);
this.labelQrCode.Name = "labelQrCode";
this.labelQrCode.Size = new System.Drawing.Size(120, 31);
this.labelQrCode.TabIndex = 12;
this.labelQrCode.Text = "扫码登录";
//
// btnRefreshQrCode
//
this.btnRefreshQrCode.BackColor = System.Drawing.Color.Transparent;
this.btnRefreshQrCode.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnRefreshQrCode.ForeColor = System.Drawing.Color.White;
this.btnRefreshQrCode.Location = new System.Drawing.Point(630, 390);
this.btnRefreshQrCode.Name = "btnRefreshQrCode";
this.btnRefreshQrCode.Size = new System.Drawing.Size(100, 30);
this.btnRefreshQrCode.TabIndex = 13;
this.btnRefreshQrCode.Text = "刷新二维码";
this.btnRefreshQrCode.UseVisualStyleBackColor = false;
//
// labelQrStatus
//
this.labelQrStatus.AutoSize = true;
this.labelQrStatus.BackColor = System.Drawing.Color.Transparent;
this.labelQrStatus.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.labelQrStatus.ForeColor = System.Drawing.Color.White;
this.labelQrStatus.Location = new System.Drawing.Point(590, 430);
this.labelQrStatus.Name = "labelQrStatus";
this.labelQrStatus.Size = new System.Drawing.Size(180, 23);
this.labelQrStatus.TabIndex = 14;
this.labelQrStatus.Text = "请使用CA证书扫码";
//
// LoginForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
@ -176,6 +227,10 @@
this.Controls.Add(this.label1);
this.Controls.Add(this.TxtPsw);
this.Controls.Add(this.TxtCode);
this.Controls.Add(this.pbQrCode);
this.Controls.Add(this.labelQrCode);
this.Controls.Add(this.btnRefreshQrCode);
this.Controls.Add(this.labelQrStatus);
this.Controls.Add(this.pictureBox1);
this.Font = new System.Drawing.Font("微软雅黑", 10.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
@ -185,6 +240,7 @@
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "健康体检系统";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pbQrCode)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@ -203,5 +259,9 @@
private System.Windows.Forms.Button BtnOk;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.PictureBox pbQrCode;
private System.Windows.Forms.Label labelQrCode;
private System.Windows.Forms.Button btnRefreshQrCode;
private System.Windows.Forms.Label labelQrStatus;
}
}

@ -1,4 +1,6 @@
using System;
using System;
using System.Drawing;
using System.Timers;
using System.Windows.Forms;
using LIS.Model;
using PEIS.Entity;
@ -10,6 +12,7 @@ namespace PEIS
public partial class LoginForm : Form
{
private UserModel _userModel = new UserModel();
private System.Timers.Timer _qrCodeTimer;
public LoginForm()
{
@ -20,6 +23,7 @@ namespace PEIS
BtnOk.Click += BtnOk_Click;
KeyDown += Form_KeyDown;
TxtCode.KeyDown += TxtCode_KeyDown;
btnRefreshQrCode.Click += btnRefreshQrCode_Click;
CacheDataModel.CacheData();
}
@ -31,6 +35,118 @@ namespace PEIS
label3.Parent = pictureBox1;
label4.Parent = pictureBox1;
label5.Parent = pictureBox1;
pbQrCode.Parent = pictureBox1;
labelQrCode.Parent = pictureBox1;
btnRefreshQrCode.Parent = pictureBox1;
labelQrStatus.Parent = pictureBox1;
InitializeQrCode();
}
private void InitializeQrCode()
{
if (!Global.IsCAEnabled)
{
pbQrCode.Visible = false;
labelQrCode.Visible = false;
btnRefreshQrCode.Visible = false;
labelQrStatus.Visible = false;
return;
}
LoadQrCode();
}
private void LoadQrCode()
{
try
{
var response = CAHelper.Login("PEIS");
if (response.Success)
{
Global.CASignDataId = response.SignDataId;
pbQrCode.Image = CAHelper.GenerateQrCodeFromString(response.QrCode);
labelQrStatus.Text = "请使用CA证书扫码登录";
StartQrCodePolling();
}
else
{
labelQrStatus.Text = $"二维码获取失败: {response.Message}";
}
}
catch (Exception ex)
{
labelQrStatus.Text = $"网络异常: {ex.Message}";
}
}
private void StartQrCodePolling()
{
stopFlag = false;
_qrCodeTimer?.Stop();
_qrCodeTimer = new System.Timers.Timer(2000);
_qrCodeTimer.Elapsed += QrCodeTimer_Elapsed;
_qrCodeTimer.Start();
}
private void QrCodeTimer_Elapsed(object sender, ElapsedEventArgs e)
{
CheckQrCodeStatus();
}
bool stopFlag = true;
private void CheckQrCodeStatus()
{
try
{
if (stopFlag) return;
var response = CAHelper.GetSignResult(Global.CASignDataId, "PEIS");
if (response.Success && response.IsLoginSuccess)
{
stopFlag = true;
_qrCodeTimer?.Stop();
Global.CAUserId = response.UserId;
// HIS登录验证失败
if (!_userModel.CALogin(Global.CAUserId))
{
Global.MsgErr("登录失败,未找到账户!");
return;
}
// 体检登录验证失败
if (!_userModel.PeisLogin(Global.currentUser))
{
Global.MsgErr("登录失败,体检系统未授权该用户!");
return;
}
// 登录成功
Global.UpdateAppConfig("UserCode", Global.currentUser.Code);
Global.UpdateAppConfig("UserName", Global.currentUser.Name);
DialogResult = DialogResult.OK;
Dispose();
Close();
}
else if (!string.IsNullOrEmpty(response.Message))
{
if (stopFlag) return;
labelQrStatus.Invoke(new Action(() => labelQrStatus.Text = response.Message));
}
}
catch (Exception ex)
{
if (stopFlag) return;
labelQrStatus.Invoke(new Action(() => labelQrStatus.Text = $"查询失败: {ex.Message}"));
}
}
private void btnRefreshQrCode_Click(object sender, EventArgs e)
{
_qrCodeTimer?.Stop();
LoadQrCode();
}
private void Form_Shown(object sender, EventArgs e)
@ -104,6 +220,7 @@ namespace PEIS
// 登录成功
Global.UpdateAppConfig("UserCode", Global.currentUser.Code);
Global.UpdateAppConfig("UserName", Global.currentUser.Name);
DialogResult = DialogResult.OK;
Dispose();
Close();

@ -90,7 +90,7 @@ namespace PEIS.Model.Enrollment
// 删除应用时间
DAOHelp.ExecuteSql($@"update Enrollment_OrgGroup set Checker = NULL, CheckerCode = NULL, CheckTime = NULL WHERE OID = {oeID} AND ID = {groupID}");
// 记录日志
if (delPatient > 0 && delFeeItem > 0)
if (delPatient > 0 || delFeeItem > 0)
{
List<EnrollmentOrgGroup> orgGroups = DAOHelp.GetDataBySQL<EnrollmentOrgGroup>($@"select * from Enrollment_OrgGroup where ID = {groupID} and OID = {oeID}");
EnrollmentOrgGroup group = orgGroups?.Count > 0 ? orgGroups[0] : null;

@ -59,6 +59,18 @@ namespace PEIS.Model
return true;
}
public Boolean CALogin(string msspid)
{
String sql = String.Format($"SELECT a.code AS Code, RTRIM(a.name) AS Name, a.ystype, b.code AS DeptCode, RTRIM(b.name) AS DeptName, b.ksattrib FROM {Global.HisDBName}.YSCODE a(NOLOCK) JOIN {Global.HisDBName}.KSCode b(NOLOCK) ON a.kscode = b.code WHERE a.BJCA_MSSPID = '{msspid}'");
List<User> lstUser = DAOHelp.GetDataBySQL<User>(sql);
if (lstUser.Count == 0)
return false;
Global.currentUser = lstUser[0];
return true;
}
public User QueryUser(string code)
{
return DAOHelp.GetDataBySQL<User>($"select Code,RTRIM(Name) as Name,kscode as DeptCode,RTRIM(ksname) as DeptName from {Global.HisDBName}.yscode where code='{code}'").FirstOrDefault();

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\PdfiumViewer.Native.x86.v8-xfa.2018.4.8.256\build\PdfiumViewer.Native.x86.v8-xfa.props" Condition="Exists('..\packages\PdfiumViewer.Native.x86.v8-xfa.2018.4.8.256\build\PdfiumViewer.Native.x86.v8-xfa.props')" />
<Import Project="..\packages\PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256\build\PdfiumViewer.Native.x86_64.v8-xfa.props" Condition="Exists('..\packages\PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256\build\PdfiumViewer.Native.x86_64.v8-xfa.props')" />
@ -179,6 +179,10 @@
<HintPath>..\packages\PdfiumViewer.2.13.0.0\lib\net20\PdfiumViewer.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="QRCoder, Version=1.8.0.0, Culture=neutral, PublicKeyToken=c4ed5b9ae8358a28, processorArchitecture=MSIL">
<HintPath>..\packages\QRCoder.1.8.0\lib\net40\QRCoder.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.configuration" />
@ -202,6 +206,7 @@
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Base\ViewBase.cs">
@ -331,6 +336,7 @@
<Compile Include="Utils\DAOHelp.cs" />
<Compile Include="Utils\DAOHelp4His.cs" />
<Compile Include="Utils\Global.cs" />
<Compile Include="Utils\CAHelper.cs" />
<Compile Include="Utils\IDCard\IDCardHelper.cs" />
<Compile Include="Utils\IDCard\SW100\SW100.cs" />
<Compile Include="Utils\LogHelper.cs" />

@ -0,0 +1,168 @@
#region CopyRight
/****************************************************************
* ProjectPEIS
* Author
* CLR Version4.0.30319.42000
* CreateTime2023-05-01 14:46:15
* Versionv2.0
*
* DescriptionCA服务调用助手类
*
* History
*
*****************************************************************
* Copyright @ 2023 All rights reserved
*****************************************************************/
#endregion CopyRight
using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using QRCoder;
namespace PEIS.Utils
{
public class CAHelper
{
private static string BaseUrl => Global.CAUrl;
public class LoginResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public string SignDataId { get; set; }
public string QrCode { get; set; }
}
public class GetSignResultResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public string JobStatus { get; set; }
public string SignResult { get; set; }
public string SignCert { get; set; }
public string UserId { get; set; }
public bool IsLoginSuccess { get; set; }
}
public class AutoSignResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public string SignResult { get; set; }
public string SignCert { get; set; }
public string SignDataId { get; set; }
}
public static LoginResponse Login(string clientType = "PEIS")
{
try
{
string url = $"{BaseUrl}/Client/Login?clientType={clientType}";
string response = PostRequest(url, "");
return JsonConvert.DeserializeObject<LoginResponse>(response);
}
catch (Exception ex)
{
return new LoginResponse
{
Success = false,
Message = $"请求失败: {ex.Message}"
};
}
}
public static GetSignResultResponse GetSignResult(string signDataId, string clientType = "PEIS")
{
try
{
string url = $"{BaseUrl}/Client/GetSignResult?clientType={clientType}";
string data = $"{{\"SignDataId\":\"{signDataId}\"}}";
string response = PostRequest(url, data);
return JsonConvert.DeserializeObject<GetSignResultResponse>(response);
}
catch (Exception ex)
{
return new GetSignResultResponse
{
Success = false,
Message = $"请求失败: {ex.Message}"
};
}
}
public static AutoSignResponse AutoSign(string userId, string signToken, string data, string clientType = "PEIS")
{
try
{
string url = $"{BaseUrl}/Client/AutoSign?clientType={clientType}";
string requestData = $"{{\"UserId\":\"{userId}\",\"SignToken\":\"{signToken}\",\"Data\":\"{data}\"}}";
string response = PostRequest(url, requestData);
return JsonConvert.DeserializeObject<AutoSignResponse>(response);
}
catch (Exception ex)
{
return new AutoSignResponse
{
Success = false,
Message = $"请求失败: {ex.Message}"
};
}
}
private static string PostRequest(string url, string data)
{
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
byte[] responseBytes = client.UploadData(url, Encoding.UTF8.GetBytes(data));
return Encoding.UTF8.GetString(responseBytes);
}
}
public static byte[] GetQrCodeImage(string qrCodeBase64)
{
try
{
if (!string.IsNullOrEmpty(qrCodeBase64))
{
return Convert.FromBase64String(qrCodeBase64);
}
return null;
}
catch
{
return null;
}
}
public static Bitmap GenerateQrCodeFromString(string qrContent)
{
try
{
var qr = new QRCodeGenerator();
var data = qr.CreateQrCode(qrContent, QRCodeGenerator.ECCLevel.Q);
var qrCode = new BitmapByteQRCode(data);
byte[] qrBytes = qrCode.GetGraphic(10);
using (var ms = new MemoryStream(qrBytes))
{
using (var tempBmp = new Bitmap(ms))
{
// 强制生成 200x200 正方形(这是核心)
return new Bitmap(tempBmp, 200, 200);
}
}
}
catch
{
return null;
}
}
}
}

@ -89,6 +89,38 @@ namespace PEIS.Utils
public static User currentUser;
/// <summary>
/// CA服务URL(配置在Dict_Config表中,Key为CAUrl)
/// </summary>
public static string CAUrl
{
get
{
return Global._lstConfig.FirstOrDefault(x => x.Key == "CAUrl")?.Value ?? "";
}
}
/// <summary>
/// 是否启用CA签名功能(CAUrl不为空即启用)
/// </summary>
public static bool IsCAEnabled
{
get
{
return !string.IsNullOrEmpty(CAUrl);
}
}
/// <summary>
/// CA自动签Token(登录成功后获取,用于后续自动签名)
/// </summary>
public static string CASignDataId { get; set; }
/// <summary>
/// CA用户ID(登录成功后获取)
/// </summary>
public static string CAUserId { get; set; }
/// <summary>
/// 返回*.exe.cdddonfig文件中appSettings配置节的value项
/// </summary>

@ -696,7 +696,7 @@ namespace PEIS.View.Enrollment
Int64 _groupId = Convert.ToInt64(DgvGroup2.GetRowCellValue(DgvGroup2.GetSelectedRows()[0], "ID").ToString());
String _oename = DgvOrg.GetRowCellValue(DgvOrg.GetSelectedRows()[0], "Name").ToString();
List<EnrollmentCheckCost> _checkCost = DAOHelp.GetDataBySQL<EnrollmentCheckCost>($@"select a.* from Enrollment_CheckCost a left join Enrollment_Patient b on a.EID = b.ID and a.OEID = b.OEID where b.OEID = {_oeid} and b.GroupId = {_groupId} and a.DeleteTime is null ");
List<EnrollmentCheckCost> _checkCost = DAOHelp.GetDataBySQL<EnrollmentCheckCost>($@"select a.* from Enrollment_CheckCost a left join Enrollment_Patient b on a.EID = b.ID where b.OEID = {_oeid} and b.GroupId = {_groupId} and a.DeleteTime is null ");
if (_checkCost.Count > 0)
{
Global.Msg("info", "该团体分组成员已生成订单,无法撤销分组成员的模版应用!");
@ -1534,7 +1534,15 @@ namespace PEIS.View.Enrollment
private void TsmiPrintPerson_Click(object sender, EventArgs e) // 打印个人收费单
{
if (!_lstCheckCost2.Any() || _lstCheckCost2.Where(w => w.CostTime == null && w.CancelTime == null).ToList().Count == 0) return;
if (!_lstCheckCost2.Any()) return;
if (_lstCheckCost2.Where(w => w.CostTime == null && w.CancelTime == null).ToList().Count == 0)
{
if (DialogResult.Yes != Global.Msg("warn", "所有订单已经缴费完毕, 仍要打印个人收费单吗?"))
{
return;
}
}
try
{
@ -1692,7 +1700,7 @@ namespace PEIS.View.Enrollment
if (DgvEnrollment.GetRowCellValue(DgvEnrollment.GetSelectedRows()[0], "ID") == null && _chooseRegItem == null) return;
if (DgvCheckCost2.GetSelectedRows().Count() == 0) return;
EnrollmentCheckCost item = DgvCheckCost2.GetRow(DgvCheckCost2.GetSelectedRows()[0]) as EnrollmentCheckCost;
//TODO:是否已缴费校验
OnChangeCost(item.ID, Convert.ToInt64(DgvOrg.GetRowCellValue(DgvOrg.GetSelectedRows()[0], "ID").ToString()));
OnGetEnrollmentFeeItem(_chooseRegItem.ID);
OnGetCheckCost(Convert.ToInt64(DgvOrg.GetRowCellValue(DgvOrg.GetSelectedRows()[0], "ID").ToString()), _chooseRegItem.ID);

@ -1,4 +1,4 @@
using DevExpress.XtraEditors;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using LIS.Model;
@ -137,6 +137,16 @@ namespace PEIS.View.Exam
if (result != DialogResult.Yes) return;
}
// CA签名处理
if (Global.IsCAEnabled)
{
if (!PerformCASignature())
{
Global.MsgWarn("CA签名失败,无法完结!");
return;
}
}
Finish?.Invoke(this, new Args<bool>()
{
ID = _patient.ID,
@ -1254,5 +1264,89 @@ namespace PEIS.View.Exam
}
}
/// <summary>
/// 执行CA签名
/// </summary>
/// <returns></returns>
private bool PerformCASignature()
{
try
{
// 构建待签名数据字符串
string signData = BuildSignData();
// 如果没有可用的签名token,尝试获取
if (string.IsNullOrEmpty(Global.CASignDataId))
{
var loginResponse = CAHelper.Login("PEIS");
if (!loginResponse.Success)
{
Global.MsgErr($"获取签名token失败: {loginResponse.Message}");
return false;
}
// 等待用户扫码签名
int timeout = 60; // 60秒超时
int count = 0;
while (count < timeout)
{
System.Threading.Thread.Sleep(1000);
var result = CAHelper.GetSignResult(loginResponse.SignDataId, "PEIS");
if (result.Success && !string.IsNullOrEmpty(result.SignResult))
{
Global.CASignDataId = result.SignResult;
Global.CAUserId = result.UserId;
break;
}
count++;
}
if (string.IsNullOrEmpty(Global.CASignDataId))
{
Global.MsgErr("签名超时,请重新操作");
return false;
}
}
// 调用自动签接口
var response = CAHelper.AutoSign(Global.CAUserId, Global.CASignDataId, signData, "PEIS");
if (response.Success)
{
Global.Msg("success", "CA签名成功!");
return true;
}
else
{
Global.MsgErr($"CA签名失败: {response.Message}");
return false;
}
}
catch (Exception ex)
{
Global.MsgErr($"CA签名异常: {ex.Message}");
return false;
}
}
/// <summary>
/// 构建待签名的数据字符串
/// </summary>
/// <returns></returns>
private string BuildSignData()
{
// 关键数据:患者ID、姓名、性别、年龄、体检日期、总检医生等
var data = new System.Text.StringBuilder();
data.Append($"EID={_patient.ID}|");
data.Append($"PatientName={_patient.Name}|");
data.Append($"Sex={_patient.Sex}|");
data.Append($"Age={_patient.Age}|");
data.Append($"ExamDate={_patient.ExamDate?.ToString("yyyy-MM-dd")}|");
data.Append($"DoctorCode={Global.currentUser.Code}|");
data.Append($"DoctorName={Global.currentUser.Name}|");
data.Append($"SignTime={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
return data.ToString();
}
}
}

@ -22,6 +22,7 @@
<package id="PdfiumViewer" version="2.13.0.0" targetFramework="net40" />
<package id="PdfiumViewer.Native.x86.v8-xfa" version="2018.4.8.256" targetFramework="net40" />
<package id="PdfiumViewer.Native.x86_64.v8-xfa" version="2018.4.8.256" targetFramework="net40" />
<package id="QRCoder" version="1.8.0" targetFramework="net40" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />
<package id="System.Net.Http" version="2.0.20710.0" targetFramework="net40" />
</packages>
Loading…
Cancel
Save