using ASHermed.SinoInterface.Api.ContractModel;
using ASHermed.SinoInterface.Api.ContractModel.App;
using ASHermed.SinoInterface.Api.ContractModel.Framework.Login;
using ASHermed.SinoInterface.Api.ContractModel.TCTrans.Input;
using ASHermed.SinoInterface.Api.ContractModel.TCTrans.Output;
using ASHermed.SinoInterface.Api.IRepository;
using ASHermed.SinoInterface.Api.IService;
using ASHermed.SinoInterface.ContractModel;
using ASHermed.SinoInterface.IFramework.SingleSignOn;
using ASHermed.SinoInterface.Tools;
using Microsoft.Extensions.Logging;
using NPOI.SS.Formula.Functions;
using PoJun.Util.Maps;
using RBCServicesReference;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using TCConfirmApptReference;
using TCHoldApptReference;
using TCRBAppointmentReference;
using Newtonsoft.Json;
using Ubiety.Dns.Core;
using ASHermed.SinoInterface.Api.ContractModel.App.Model;

namespace ASHermed.SinoInterface.Api.Service
{
    /// <summary>
	/// TC服务
	/// </summary>
	public class TCService : BaseService, ITCService
    {
        #region 初始化
        ILogger<TCService> _logger;
        AppConfigurtaion _appConfigurtaion;
        MemoryCacheHelper _memoryCacheHelper;
        private string _tCRBAppointmentUrl;
        private string _tCRBCServicesUrl;
        private string _tCPAPersonMobileUrl;
        private string _tCPAAdmUrl;
        private string _tCEditUrl;
        private string _tCARCItmMastUrl;
        private string _tCPAPersonUrl;
        private string _tCConfirmApptEditUrl;
        private string _tCCancelApptEditUrl;
        private string _tCGetPatientReportUrl;
        private string _tCUpdatePatientPortalLinkUrl;
        private string _tCClinicalInfoUrl;
        private string _tCCustomCRM;
        private string _tCCustomCRMPictures;
        private string _tCCustomCRMMRPictures;
        private readonly HttpClient _httpClient;
        public TCService(ILogger<TCService> logger, AppConfigurtaion appConfigurtaion, MemoryCacheHelper memoryCacheHelper, IHttpClientFactory httpClientFactory)
        {
            //http://192.168.50.235/trakbase/web/api/TC.ws.RBAppointment.ConfirmAppt.Edit.cls?D
            _logger = logger;
            _appConfigurtaion = appConfigurtaion;
            _memoryCacheHelper = memoryCacheHelper;
            _tCRBAppointmentUrl = "web/api/Custom.SINO.WS.CRM.RBAppointment.cls";
            _tCRBCServicesUrl = "web/api/Custom.SINO.WS.CRM.RBCServices.cls";
            _tCPAPersonMobileUrl = "web/api/Custom.SINO.WS.CRM.PAPersonMobile.cls";
            _tCPAAdmUrl = "web/api/Custom.SINO.WS.CRM.PAAdm.cls";
            _tCEditUrl = "web/api/TC.ws.RBAppointment.HoldAppt.Edit.cls";
            _tCARCItmMastUrl = "web/api/Custom.SINO.WS.CRM.ARCItmMast.cls";
            _tCPAPersonUrl = "web/api/TC.ws.PAPerson.Edit.cls";
            _tCConfirmApptEditUrl = "web/api/TC.ws.RBAppointment.ConfirmAppt.Edit.cls";
            _tCCancelApptEditUrl = "web/api/TC.ws.RBAppointment.CancelAppt.Edit.cls";
            _tCGetPatientReportUrl = "web/api/Custom.SINO.WS.CRM.GetPatientReport.cls";  //trakbase测试
            _tCUpdatePatientPortalLinkUrl = "web/api/Custom.SINO.WS.CRM.PAPersonPatientPortal.cls";
            _tCClinicalInfoUrl = "web/api/Custom.SINO.WS.CRM.ClinicalInfo.cls";
            _tCCustomCRM = "web/api/Custom.SINO.WS.CRM.PAPerson.cls";
            _tCCustomCRMPictures = "web/api/Custom.SINO.WS.CRM.PAPersonPictures.cls";
            _tCCustomCRMMRPictures = "web/api/Custom.SINO.WS.CRM.MRPictures.cls";
            _httpClient = httpClientFactory.CreateClient(HttpClientConst.TCService_CLIENT_NAME);
        }
        #endregion

        /// <summary>
        /// 获取老用户
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="birthday"></param>
        /// <returns></returns>
        public List<PAPerson> GetPat(string phone, string birthday)
        {
            var response = GetPatientByMRN(string.Empty, phone, string.Empty, birthday);
            return response;
        }

        public List<PAPerson> GetPatient(string mrn, string phone, string birthDate)
        {
            var response = GetPatientByMRN(mrn, phone, string.Empty, birthDate);
            return response.FindAll(p => p.PAPMIActive == "Y");
        }

        public bool LockApt(string ubrn, string usrn, string mode)
        {
            _logger.LogInformation("LockApt:ubrn " + ubrn + "状态" + mode);
            return LockAptSave(ubrn, usrn, mode);
        }

        public bool CommitApt(string deptId, string servId, string ubrn, string usrn, string patId)
        {
            try
            {
                _logger.LogInformation("CommitApt:参数 " + deptId + "-" + servId + "-" + ubrn + "-" + patId);
                if (CommitApt(ubrn, usrn, patId))
                {
                    CacheScheduling(deptId, servId);
                    return true;
                }
                return false;
            }
            catch (System.Exception e) { return false; }
        }

        public bool NewCommitApt(string ubrn, string patId)
        {
            try
            {
                _logger.LogInformation("NewCommitApt:参数 " + "-" + ubrn + "-" + patId);
                if (CommitApt(ubrn, ubrn, patId))
                {
                    return true;
                }
                return false;
            }
            catch (System.Exception e) { return false; }
        }

        public bool CommitApt(string ubrn, string usrn, string patId)
        {
            if (ConfirmApptEdit(ubrn, usrn, patId) == 0)
            {
                return false;
            }
            return true;
        }

        public void CacheScheduling(string deptId, string servId)
        {
            // 当天日期
            string today = DateTime.Now.ToString("yyyy-MM-dd");
            string key = today + FullId(deptId, 6) + FullId(servId, 6);
            new Thread(p =>
            {
                string to = DateTime.Now.AddDays(90).ToString("yyyy-MM-dd");
                try
                {
                    GetCPWithSlotsForDateResponse dateResponse = GetCPWithSlotsForDate(today, to, deptId, servId);
                    PutCache(key, dateResponse);
                }
                catch (System.Exception ex)
                {
                    _logger.LogError(ex, "CacheScheduling异常");
                    //ex.printStackTrace();
                }
            }).Start();
        }

        /// <summary>
        /// 填充数据
        /// </summary>
        /// <param name="source"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public string FullId(string source, int length)
        {
            if (source?.Length < length)
            {
                source = "0" + source;
                if (source.Length < length)
                {
                    return FullId(source, length);
                }
                else
                {
                    return source;
                }
            }
            else
            {
                return source;
            }
        }

        public Scheduling GetScheduling(string dateFrom, string dateTo, string deptId, string servId, string careProvId)
        {
            // 当天日期
            string today = DateTime.Now.ToString("yyyy-MM-dd");
            string key = today + FullId(deptId, 6) + FullId(servId, 6);
            var response = _memoryCacheHelper.Get<GetCPWithSlotsForDateResponse>(key);
            if (dateFrom == dateTo || response == null)
            {
                response = GetCPWithSlotsForDate(dateFrom, dateTo, deptId, servId, careProvId);

                CacheScheduling(deptId, servId);

            }

            return TransferScheduling(response, dateFrom, dateTo, careProvId);

        }

        public List<AptSlot> GetAptScheduling(string dateFrom, string dateTo, string deptId, string servId, string careProvId)
        {
            // 当天日期
            string today = DateTime.Now.ToString("yyyy-MM-dd");
            string key = today + FullId(deptId, 6) + FullId(servId, 6);
            //var response = _memoryCacheHelper.Get<GetCPWithSlotsForDateResponse>(key);
            //if (response == null)
            //{
            var response = GetCPWithSlotsForDate(dateFrom, dateTo, deptId, servId, careProvId);
            //CacheScheduling(deptId, servId);
            //}

            return TransferAptScheduling(response, dateFrom, dateTo, careProvId);

        }


        public Scheduling GetSchedulingNew(string dateFrom, string dateTo, string deptId, string servId, string careProvId)
        {
            GetCPWithSlotsForDateResponse response = GetCPWithSlotsForDate(dateFrom, dateTo, deptId, servId, careProvId);
            //CacheScheduling(deptId, servId);
            return TransferScheduling(response, dateFrom, dateTo, careProvId);
        }

        private List<AptSlot> TransferAptScheduling(GetCPWithSlotsForDateResponse dateResponse, string dateFrom, string dateTo, string careProvId)
        {
            List<AptSlot> scheduling = new List<AptSlot>();
            DateTime calNow = GetMinimumTime().AddHours(1);

            var arrayOfSlotDateSlotDate = dateResponse.SlotDates;

            if (arrayOfSlotDateSlotDate != null && arrayOfSlotDateSlotDate.Length > 0)
            {
                List<TCRBAppointmentReference.SlotDate> slotDateList = arrayOfSlotDateSlotDate.ToList();
                AptSlot aptSlot = null;
                foreach (var slotDateItem in slotDateList)
                {
                    // 设置日期
                    if (Convert.ToDateTime(dateFrom) != Convert.ToDateTime(slotDateItem.Date))
                    {
                        continue;
                    }
                    var arrayOfResourceResource = slotDateItem.Resources;
                    if (arrayOfResourceResource != null && arrayOfResourceResource.Length > 0)
                    {
                        foreach (var resourceItem in arrayOfResourceResource)
                        {
                            // 针对两边组织结构不统一可能导致医生不在该科室，从而查到所有医生的排班，需要过滤
                            if (null == careProvId || careProvId != resourceItem.CareProvID)
                            {
                                continue;
                            }

                            var arrayOfSlotSlot = resourceItem.Slots;
                            if (arrayOfSlotSlot != null && arrayOfSlotSlot.Length > 0)
                            {
                                foreach (var slotItem in arrayOfSlotSlot)
                                {
                                    if (DateTime.Now.AddHours(1) > Convert.ToDateTime(dateFrom + " " + slotItem.StartTime))
                                    {
                                        continue;
                                    }
                                    aptSlot = new AptSlot()
                                    {
                                        AptUsrn = slotItem.USRN,
                                        StartTime = slotItem.StartTime,
                                        EndTime = slotItem.EndTime,
                                        DateType = slotItem.IsAfternoon ? 1 : 0
                                    };

                                    string timeStr = dateFrom + " " + aptSlot.StartTime;
                                    DateTime? date = null;
                                    try
                                    {
                                        date = Convert.ToDateTime(timeStr);
                                        if (calNow <= date)
                                        {
                                            scheduling.Add(aptSlot);
                                        }
                                    }
                                    catch (System.Exception e)
                                    {
                                        _logger.LogError(e, "添加resource.Slots时错误");
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return scheduling;
        }
        protected Scheduling TransferScheduling(GetCPWithSlotsForDateResponse dateResponse, string dateFrom, string dateTo, string careProvId)
        {
            Scheduling scheduling = new Scheduling();
            DateTime calNow = GetMinimumTime().AddHours(1);
            //calNow.AddHours(1);
            //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            var arrayOfSlotDateSlotDate = dateResponse.SlotDates;

            if (arrayOfSlotDateSlotDate != null && arrayOfSlotDateSlotDate.Length > 0)
            {
                List<TCRBAppointmentReference.SlotDate> slotDateList = arrayOfSlotDateSlotDate.ToList();

                foreach (var slotDateItem in slotDateList)
                {
                    // 设置日期
                    if (Convert.ToDateTime(dateFrom) > Convert.ToDateTime(slotDateItem.Date) || Convert.ToDateTime(slotDateItem.Date) > Convert.ToDateTime(dateTo))
                    {
                        continue;
                    }
                    TCRBAppointmentReference.SlotDate slotDate = new TCRBAppointmentReference.SlotDate
                    {
                        Date = slotDateItem.Date
                    };
                    ContractModel.App.SlotDate slotDate1 = new ContractModel.App.SlotDate
                    {
                        Date = slotDateItem.Date,
                        ResourceList = new ContractModel.App.Resource[] { }
                    };
                    bool morning = false;
                    bool afternoon = false;
                    var arrayOfResourceResource = slotDateItem.Resources;
                    if (arrayOfResourceResource != null && arrayOfResourceResource.Length > 0)
                    {
                        foreach (var resourceItem in arrayOfResourceResource)
                        {
                            // 针对两边组织结构不统一可能导致医生不在该科室，从而查到所有医生的排班，需要过滤
                            if (null != careProvId && careProvId != resourceItem.CareProvID)
                            {
                                continue;
                            }

                            TCRBAppointmentReference.Resource resource = new TCRBAppointmentReference.Resource()
                            {
                                Slots = new TCRBAppointmentReference.Slot[] { },
                                CareProvID = resourceItem.CareProvID
                                //setSlotList(new ArrayList<>());
                                //setCareProvID(resourceItem.getCareProvID());
                            };
                            ContractModel.App.Resource resource1 = new ContractModel.App.Resource()
                            {
                                SlotList = new ContractModel.App.Slot[] { },
                                CareProvID = resourceItem.CareProvID
                            };

                            var arrayOfSlotSlot = resourceItem.Slots;
                            if (arrayOfSlotSlot != null && arrayOfSlotSlot.Length > 0)
                            {
                                foreach (var slotItem in arrayOfSlotSlot)
                                {
                                    TCRBAppointmentReference.Slot slot = new TCRBAppointmentReference.Slot()
                                    {
                                        USRN = slotItem.USRN,
                                        StartTime = slotItem.StartTime,
                                        EndTime = slotItem.EndTime,
                                        IsAfternoon = slotItem.IsAfternoon,
                                        RBASId = slotItem.RBASId
                                    };
                                    ContractModel.App.Slot slot1 = new ContractModel.App.Slot()
                                    {
                                        Usrn = slotItem.USRN,
                                        StartTime = slotItem.StartTime,
                                        EndTime = slotItem.EndTime,
                                        Section = slotItem.IsAfternoon ? 1 : 0,
                                        RbasId = slotItem.RBASId
                                    };
                                    if (slot1.Section == 0)
                                    {
                                        morning = true;
                                    }
                                    if (slot1.Section == 1)
                                    {
                                        afternoon = true;
                                    }
                                    string timeStr = slotDate.Date + " " + slot.StartTime;
                                    DateTime? date = null;
                                    try
                                    {
                                        date = Convert.ToDateTime(timeStr);
                                        if (calNow <= date)
                                        {
                                            resource.Slots = AddArrays(resource.Slots, slot);
                                            resource1.SlotList = AddArrays(resource1.SlotList, slot1);
                                        }
                                    }
                                    catch (System.Exception e)
                                    {
                                        _logger.LogError(e, "添加resource.Slots时错误");
                                    }
                                }
                                if (resource.Slots == null || resource.Slots.Length <= 0)
                                {
                                    resource.Slots = null;
                                }
                                if (resource1.SlotList == null || resource1.SlotList.Length <= 0)
                                {
                                    resource1.SlotList = null;
                                }
                            }
                            slotDate.Resources = AddArrays(slotDate.Resources, resource);
                            slotDate1.ResourceList = AddArrays(slotDate1.ResourceList, resource1);
                        }
                        if (slotDate.Resources.Length <= 0)
                        {
                            slotDate.Resources = null;
                        }
                        if (slotDate1.ResourceList.Length <= 0)
                        {
                            slotDate1.ResourceList = null;
                        }
                    }
                    if (morning)
                    {
                        slotDate1.DateType = 1;
                    }
                    if (afternoon)
                    {
                        slotDate1.DateType = 2;
                    }
                    if (morning && afternoon)
                    {
                        slotDate1.DateType = 3;
                    }
                    scheduling.SlotDateList.Add(slotDate1);
                }
            }

            return scheduling;
        }

        private T[] AddArrays<T>(T[] arr, T model)
        {
            List<T> list = new List<T>(arr);
            list.Add(model);
            return list.ToArray();
        }

        public DateTime GetMinimumTime()
        {
            //Calendar calNow = Calendar.getInstance();
            //Calendar nine = DateUtil.setTime(9, 0, 0);
            //Calendar fourteen = DateUtil.setTime(14, 0, 0);
            //Calendar eightten = DateUtil.setTime(18, 0, 0);
            DateTime dateTime = DateTime.Now;
            if (DateTime.Now.Hour < 9)
            {
                return Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd") + " 09:00:00");
            }
            else if (dateTime.Hour < 14)
            {
                return dateTime;
            }
            else if (dateTime.Hour < 18)
            {
                dateTime.AddHours(15);
                return dateTime;
            }
            else
            {
                //2020-07-24 14:50:00
                var date = DateTime.Now.ToString("yyyy-MM-dd") + " 09:00:00";
                var time = Convert.ToDateTime(date);
                return time.AddDays(1);
            }
        }


        private void PutCache(string key, GetCPWithSlotsForDateResponse response)
        {
            List<string> keyList = new List<string>();
            var hasKeys = _memoryCacheHelper.GetCacheKeys();
            foreach (var item in hasKeys)
            {
                var value = _memoryCacheHelper.Get<GetCPWithSlotsForDateResponse>(item);
                //string entryKey = entry.getKey();
                var today = DateTime.Now;
                string day = key.Substring(0, 10);
                if (Convert.ToDateTime(day) < today)
                {
                    keyList.Add(item);
                }
            }
            foreach (var item in keyList)
            {
                _memoryCacheHelper.Remove(item);
            }
            _memoryCacheHelper.Set(key, response, 60 * 24);
        }

        public GetCPWithSlotsForDateResponse GetCPWithSlotsForDate(string dateFrom, string dateTo, string deptId, string servId, string careProvId = "")
        {
            _logger.LogInformation("GetCPWithSlotsForDate request:dateFrom:" + dateFrom + "dateTo:" + dateTo + "  deptId:" + deptId + " servId:" + servId + " careProvId:" + careProvId);
            if (string.IsNullOrEmpty(dateFrom) || string.IsNullOrEmpty(dateTo) || string.IsNullOrEmpty(deptId))
            {
                return new GetCPWithSlotsForDateResponse();
            }
            var res = new GetCPWithSlotsForDateResponse();
            var resStr = string.Empty;
            XmlDocument soapEnvelopeXml = new XmlDocument();
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope
    xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
    xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
    xmlns:sino=""http://sino.com.cn"">
   " + GetTCXmlHeader() + @"
    <soapenv:Body>
        <sino:GetCPWithSlotsForDate>
            <sino:Token></sino:Token>
            <sino:DateFrom>" + dateFrom + @"</sino:DateFrom>
            <sino:DateTo>" + dateTo + @"</sino:DateTo>
            <sino:LocationID>" + deptId + @"</sino:LocationID>
            <sino:ServiceID>" + servId + @"</sino:ServiceID>
            <sino:AllowOverbook></sino:AllowOverbook>
            <sino:CareProvID>" + careProvId + @"</sino:CareProvID>
            <sino:Res>?</sino:Res>
        </sino:GetCPWithSlotsForDate>
    </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetCPWithSlotsForDate");
            var response = _httpClient.PostAsync(_tCRBAppointmentUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetCPWithSlotsForDate:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetCPWithSlotsForDateResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetCPWithSlotsForDateResult>") + 30;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                XmlNodeList node = resXml.DocumentElement.ChildNodes;
                foreach (XmlNode item in node)
                {
                    switch (item.Name)
                    {
                        case "Hospital":
                            res.Hospital = item?.InnerText;
                            break;
                        case "HospitalCN":
                            res.HospitalCN = item?.InnerText;
                            break;
                        case "Location":
                            res.Location = item?.InnerText;
                            break;
                        case "SlotDates":
                            List<TCRBAppointmentReference.SlotDate> SlotDates = new List<TCRBAppointmentReference.SlotDate>();
                            foreach (XmlNode item1 in item.SelectNodes("SlotDate"))
                            {
                                TCRBAppointmentReference.SlotDate model = new TCRBAppointmentReference.SlotDate();
                                List<TCRBAppointmentReference.Resource> resources = new List<TCRBAppointmentReference.Resource>();
                                model.Date = item1.SelectSingleNode("Date")?.InnerText;
                                foreach (XmlNode item2 in item1.SelectNodes("Resources/Resource"))
                                {
                                    TCRBAppointmentReference.Resource modelitem = new TCRBAppointmentReference.Resource();
                                    List<TCRBAppointmentReference.Slot> slots = new List<TCRBAppointmentReference.Slot>();
                                    modelitem.ResourceID = item2.SelectSingleNode("ResourceID")?.InnerText;
                                    modelitem.ResourceDesc = item2.SelectSingleNode("ResourceDesc")?.InnerText;
                                    modelitem.CareProvDesc = item2.SelectSingleNode("CareProvDesc")?.InnerText;
                                    modelitem.CareProvID = item2.SelectSingleNode("CareProvID")?.InnerText;
                                    modelitem.EQGroup = item2.SelectSingleNode("EQGroup")?.InnerText;
                                    foreach (XmlNode item3 in item2.SelectNodes("Slots/Slot"))
                                    {
                                        TCRBAppointmentReference.Slot slotmodel = new TCRBAppointmentReference.Slot();
                                        slotmodel.USRN = item3.SelectSingleNode("USRN")?.InnerText;
                                        slotmodel.StartTime = item3.SelectSingleNode("StartTime")?.InnerText;
                                        slotmodel.EndTime = item3.SelectSingleNode("EndTime")?.InnerText;
                                        slotmodel.RBASId = item3.SelectSingleNode("RBASId")?.InnerText;
                                        slotmodel.IsAfternoon = bool.Parse(item3.SelectSingleNode("IsAfternoon")?.InnerText);
                                        slotmodel.IsAfternoonSpecified = bool.Parse(item3.SelectSingleNode("IsAfternoon")?.InnerText);
                                        slots.Add(slotmodel);
                                    }
                                    modelitem.Slots = slots.ToArray();
                                    resources.Add(modelitem);
                                }
                                model.Resources = resources.ToArray();
                                SlotDates.Add(model);
                            }
                            res.SlotDates = SlotDates.ToArray();
                            break;
                    }
                }
            }
            return res;
        }

        public List<ServProj> GetServiceList(string deptId)
        {
            if (string.IsNullOrEmpty(deptId))
            {
                return new List<ServProj>();
            }
            List<ServProj> servProjList = new List<ServProj>();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">
                      " + GetTCXmlHeader() + @"
                       <soapenv:Body>
                          <sino:GetServices>
                             <!--Optional:-->
                             <sino:Token></sino:Token>
                             <!--Optional:-->
                             <sino:ResDesc></sino:ResDesc>
                             <!--Optional:-->
                             <sino:Location>" + deptId + @"</sino:Location>
                             <!--Optional:-->
                             <sino:ServiceType></sino:ServiceType>
                          </sino:GetServices>
                       </soapenv:Body>
                    </soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetServices");
            var response = _httpClient.PostAsync(_tCRBCServicesUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetServices:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<Services>");
                if (begin < 0)
                {
                    return servProjList;
                }
                var end = resStr.IndexOf("</Services>") + 11;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                XmlNodeList node = resXml.DocumentElement.ChildNodes;
                foreach (XmlNode item in node)
                {
                    ServProj model = new ServProj();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "ID":
                                model.Id = item1?.InnerText;
                                break;
                            case "Code":
                                model.Code = item1?.InnerText;
                                break;
                            case "Description":
                                model.EnName = item1?.InnerText;
                                break;
                        }
                    }
                    servProjList.Add(model);
                }
            }
            return servProjList;
        }

        public AppointmentsForPatient GetAppointmentsForPatient(string mrn)
        {
            if (string.IsNullOrEmpty(mrn))
            {
                return new AppointmentsForPatient();
            }
            AppointmentsForPatient res = new AppointmentsForPatient();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope
    xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
    xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
    xmlns:sino=""http://sino.com.cn"">" + GetTCXmlHeader() + @"
    <soapenv:Body>
        <sino:GetAppointmentsForPatient>
            <!--Optional:-->
            <sino:Token>?</sino:Token>
            <!--Optional:-->
            <sino:MRN>" + mrn + @"</sino:MRN>
            <!--Optional:-->
            <sino:DateFrom>" + DateTime.Now.AddMonths(-2).Date.ToString("yyyy-MM-dd") + @"</sino:DateFrom>
            <!--Optional:-->
            <sino:DateTo>" + DateTime.Now.Date.ToString("yyyy-MM-dd") + @"</sino:DateTo>
            <!--Optional:-->
            <sino:MaxRows></sino:MaxRows>
            <!--Optional:-->
            <sino:StartRow></sino:StartRow>
        </sino:GetAppointmentsForPatient>
    </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetAppointmentsForPatient");
            var response = _httpClient.PostAsync(_tCRBAppointmentUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetAppointmentsForPatient:mrn:" + mrn + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetAppointmentsForPatientResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetAppointmentsForPatientResult>") + 34;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                res.TotalRows = int.Parse(resXml.SelectSingleNode("GetAppointmentsForPatientResult/TotalRows")?.InnerText);
                res.RowsReturned = int.Parse(resXml.SelectSingleNode("GetAppointmentsForPatientResult/RowsReturned")?.InnerText);
                XmlNodeList list = resXml.SelectNodes("GetAppointmentsForPatientResult/RBAppointmentRows/RBAppointment");
                foreach (XmlNode item in list)
                {
                    AppointmentsForPatientDetail model = new AppointmentsForPatientDetail();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "APPTAdmNo":
                                model.APPTAdmNo = item1?.InnerText;
                                break;
                            case "APPTPAPMINo":
                                model.APPTPAPMINo = item1?.InnerText;
                                break;
                            case "APPTRBCServ":
                                model.APPTRBCServ = item1?.InnerText;
                                break;
                        }

                    }
                    res.RBAppointment.Add(model);
                }
            }
            return res;
        }

        public EpisodeWithDiagnosesInLastYear GetEpisodeWithDiagnosesInLastYear(string mrn)
        {
            if (string.IsNullOrEmpty(mrn))
            {
                return new EpisodeWithDiagnosesInLastYear();
            }
            EpisodeWithDiagnosesInLastYear res = new EpisodeWithDiagnosesInLastYear();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" 
 xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
   xmlns:sino=""http://sino.com.cn"">
 " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:GetEpisodeWithDiagnosesInLastYear>
         <!--Optional:-->
         <sino:MRN>" + mrn + @"</sino:MRN>
      </sino:GetEpisodeWithDiagnosesInLastYear>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetEpisodeWithDiagnosesInLastYear");
            var response = _httpClient.PostAsync(_tCPAAdmUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetEpisodeWithDiagnosesInLastYear:mrn:" + mrn + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetEpisodeWithDiagnosesInLastYearResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetEpisodeWithDiagnosesInLastYearResult>") + 42;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                res.TotalRows = int.Parse(resXml.SelectSingleNode("GetEpisodeWithDiagnosesInLastYearResult/TotalRows")?.InnerText);
                res.RowsReturned = int.Parse(resXml.SelectSingleNode("GetEpisodeWithDiagnosesInLastYearResult/RowsReturned")?.InnerText);
                XmlNodeList list = resXml.SelectNodes("GetEpisodeWithDiagnosesInLastYearResult/PAADMRows/PAAdm");
                foreach (XmlNode item in list)
                {
                    PAAdm model = new PAAdm();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "PAADMAdmDateLocal":
                                model.PAADMAdmDateLocal = item1?.InnerText;
                                break;
                            case "PAADMAdmTimeLocal":
                                model.PAADMAdmTimeLocal = item1?.InnerText;
                                break;
                            case "PAADMDepCode":
                                model.PAADMDepCode = item1?.InnerText;
                                break;
                            case "PAADMADMNo":
                                model.PAADMADMNo = item1?.InnerText;
                                break;
                            case "PAADMDepDesc":
                                model.PAADMDepDesc = item1?.InnerText;
                                break;
                            case "PAADMDiagnoses":
                                model.PAADMDiagnoses = item1?.InnerText;
                                break;
                            case "PAADMDiagnosesCodes":
                                model.PAADMDiagnosesCodes = item1?.InnerText;
                                break;
                        }

                    }
                    res.PAAdm.Add(model);
                }
            }
            return res;
        }

        public List<EpisodesForPatient> GetEpisodesForPatient(string mrn)
        {
            if (string.IsNullOrEmpty(mrn))
            {
                return new List<EpisodesForPatient>();
            }
            List<EpisodesForPatient> res = new List<EpisodesForPatient>();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" 
 xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
   xmlns:sino=""http://sino.com.cn"">
 " + GetTCXmlHeader() + @"
   <soapenv:Body>
     <sino:GetEpisodesForPatient>
         <!--Optional:-->
         <sino:Token></sino:Token>
         <!--Optional:-->
         <sino:MRN>" + mrn + @"</sino:MRN>
         <!--Optional:-->
         <sino:DateFrom></sino:DateFrom>
         <!--Optional:-->
         <sino:DateTo></sino:DateTo>
         <!--Optional:-->
         <sino:MaxRows></sino:MaxRows>
         <!--Optional:-->
         <sino:StartRow></sino:StartRow>
      </sino:GetEpisodesForPatient>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetEpisodesForPatient");
            var response = _httpClient.PostAsync(_tCPAAdmUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetEpisodesForPatient:mrn:" + mrn + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<PAADMRows>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</PAADMRows>") + 12;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                XmlNodeList list = resXml.SelectNodes("PAADMRows/PAAdm");
                foreach (XmlNode item in list)
                {
                    EpisodesForPatient model = new EpisodesForPatient();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "PAADMAdmID":
                                model.PAADMAdmID = item1?.InnerText;
                                break;
                            case "PAADMDepCode":
                                model.PAADMDepCode = item1?.InnerText;
                                break;
                            case "PAADMAdmDocCode":
                                model.PAADMAdmDocCode = item1?.InnerText;
                                break;
                            case "PAPMINo":
                                model.PAPMINo = item1?.InnerText;
                                break;
                            case "PAADMMainMRADMDR":
                                model.PAADMMainMRADMDR = item1?.InnerText;
                                break;
                            case "PAADMSERDESC":
                                model.PAADMSERDESC = item1?.InnerText;
                                break;
                            case "PAADMDepDesc":
                                model.PAADMDepDesc = item1?.InnerText;
                                break;
                        }

                    }
                    res.Add(model);
                }
            }
            return res;
        }

        public List<PAPerson> GetPatientByMRN(string mrn, string phone, string episodeNo, string birthday)
        {
            List<PAPerson> res = new List<PAPerson>();
            var resStr = string.Empty;
            XmlDocument soapEnvelopeXml = new XmlDocument();
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope
                xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
                xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
                xmlns:sino=""http://sino.com.cn"">
                " + GetTCXmlHeader() + @"
                <soapenv:Body>
                    <sino:GetPatientByMRN>
                        <sino:Token></sino:Token>
                        <sino:MRN>" + mrn + @"</sino:MRN>
                        <sino:MobilePhone>" + phone + @"</sino:MobilePhone>
                        <sino:EpisodeNo>" + episodeNo + @"</sino:EpisodeNo>
                        <sino:DOB>" + birthday + @"</sino:DOB>
                        <sino:NID></sino:NID>
                        <sino:NIDType></sino:NIDType>
                    </sino:GetPatientByMRN>
                </soapenv:Body>
            </soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetPatientByMRN");
            var response = _httpClient.PostAsync(_tCPAPersonMobileUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetPatientByMRN:mrn:" + mrn + "  phone:" + phone + "  birthday:" + birthday + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetPatientByMRNResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetPatientByMRNResult>") + 24;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)).Replace("s01:PAPerson xmlns=\"http://sino.com.cn/\" xmlns:s01=\"http://sino.com.cn\"", "PAPerson").Replace("s01:PAPerson", "PAPerson"));
                XmlNodeList node = resXml.SelectNodes("GetPatientByMRNResult/persons/PAPerson");
                foreach (XmlNode item in node)
                {
                    PAPerson model = new PAPerson();
                    foreach (XmlNode item2 in item.ChildNodes)
                    {
                        switch (item2.Name)
                        {
                            case "PAPERRowId":
                                model.PAPERRowId = item2?.InnerText;
                                break;
                            case "PAPERName":
                                model.PAPERName = item2?.InnerText;
                                break;
                            case "PAPERName2":
                                model.PAPERName2 = item2?.InnerText;
                                break;
                            case "PAPERName3":
                                model.PAPERName3 = item2?.InnerText;
                                break;
                            case "PAPMINo":
                                model.PAPMINo = item2?.InnerText;
                                break;
                            case "PAPERDob":
                                model.PAPERDob = DateTime.Parse(item2?.InnerText);
                                break;
                            case "PAPERSex":
                                model.PAPERSex = item2?.InnerText;
                                break;
                            case "PAPERID":
                                model.PAPERID = item2?.InnerText;
                                break;
                            case "PAPERMobPhone":
                                model.PAPERMobPhone = item2?.InnerText;
                                break;
                            case "PAPERStName":
                                model.PAPERStName = item2?.InnerText;
                                break;
                            case "PAPEREmail":
                                model.PAPEREmail = item2?.InnerText;
                                break;
                            case "PAPERCityCode":
                                model.PAPERCityCode = item2?.InnerText;
                                break;
                            case "PAPERNation":
                                model.PAPERNation = item2?.InnerText;
                                break;
                            case "PAPERDeceased":
                                model.PAPERDeceased = item2?.InnerText;
                                break;
                            case "PAPMIActive":
                                model.PAPMIActive = item2?.InnerText;
                                break;
                            case "PAPERAge":
                                model.PAPERAge = item2?.InnerText;
                                break;
                            case "MRN":
                                model.MRN = item2?.InnerText;
                                break;

                        }

                    }
                    res.Add(model);
                }
            }
            return res;
        }

        /// <summary>
        /// 排班需要先锁号，然后才能预约 TC锁号
        /// </summary>
        /// <param name="ubrn"></param>
        /// <param name="usrn"></param>
        /// <param name="Mode">L : 锁号  U : 解锁 </param>
        /// <returns></returns>
        public bool LockAptSave(string ubrn, string usrn, string Mode)
        {
            try
            {
                if (string.IsNullOrEmpty(ubrn) || string.IsNullOrEmpty(usrn))
                {
                    return false;
                }
                var resStr = string.Empty;
                XmlDocument resXml = new XmlDocument();
                #region xml
                string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://www.intersystems.com/trak/ws"">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Save>
         <ws:rs>
            <ws:APPTUBRN>" + ubrn + @"</ws:APPTUBRN>
            <ws:APPTUSRN>" + usrn + @"</ws:APPTUSRN>
            <ws:Mode>" + Mode + @"</ws:Mode>
         </ws:rs>
         <ws:TUSERNAME>api</ws:TUSERNAME>
         <ws:TPASSWORD>trak456</ws:TPASSWORD>
      </ws:Save>
   </soapenv:Body>
</soapenv:Envelope>";
                #endregion

                _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
                _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
                var response = _httpClient.PostAsync(_tCEditUrl, new JsonContent(xml)).Result;
                _logger.LogInformation("LockAptSave:mrn:" + ubrn + "  response:" + response.ToJson());
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    resStr = response.Content.ReadAsStringAsync().Result;
                    var begin = resStr.IndexOf("<SaveResult>");
                    if (begin < 0)
                    {
                        return false;
                    }
                    var end = resStr.IndexOf("</SaveResult>") + 13;
                    resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                    var res = resXml.SelectSingleNode("SaveResult")?.InnerText;
                    if (res == "1")
                    {
                        return true;
                    }
                }
                return false;
            }
            catch (System.Exception e)
            {
                _logger.LogError(e, "LockAptSave异常:"+ usrn +"  报错:"+ e.Message);
                return false;
            }
        }

        /// <summary>
        /// 新患者录入
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int AddTcNewPat(TcNewPatModel model)
        {
            try
            {
                //<ws:PAPERName3></ws:PAPERName3>
                var resStr = string.Empty;
                XmlDocument soapEnvelopeXml = new XmlDocument();
                XmlDocument resXml = new XmlDocument();
                #region xml
                string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://www.intersystems.com/trak/ws"">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Save>
         <!--Optional:-->
         <ws:token></ws:token>
         <!--Optional:-->
         <ws:rs>
            <ws:PAPERName>" + model.LastName + @"</ws:PAPERName>
            <ws:PAPERName2>" + model.FirstName + @"</ws:PAPERName2>
            <ws:CTSEXDesc>" + (model.Gender == 0 ? "女 Female" : "男 Male") + @"</ws:CTSEXDesc>
            <ws:PAPERMobPhone>" + model.PhoneNo + @"</ws:PAPERMobPhone>
            <ws:PAPERDob>" + model.Birthday + @"</ws:PAPERDob>
            <ws:PAPERID>" + model.CardId + @"</ws:PAPERID>
            <ws:CTNATDesc>" + model.Nationality + @"</ws:CTNATDesc>
            <ws:ASSISDesc>" + model.HowKnowCode + @"</ws:ASSISDesc>
            <ws:PAPERStName>" + model.Address + @"</ws:PAPERStName>
            <ws:CTCITDesc>" + model.City + @"</ws:CTCITDesc>
            <ws:PAPERPreferredContactMethod>" + model.ContactWayCode + @"</ws:PAPERPreferredContactMethod>
            <ws:PAPEREmail>" + model.Email + @"</ws:PAPEREmail>
            <ws:PAPERNokName>" + model.EmergencyName + @"</ws:PAPERNokName>
            <ws:PAPERNokPhone>" + model.EmergencyPhone + @"</ws:PAPERNokPhone>
            <ws:CTRLTDesc>" + model.EmergencyRelationCode + @"</ws:CTRLTDesc>
            <ws:PAPERRemark>" + model.Remark + @" APP自动完善信息 患者证件已上传至Patient document</ws:PAPERRemark>
         </ws:rs>
         <ws:TUSERNAME>api</ws:TUSERNAME>
         <ws:TPASSWORD>trak456</ws:TPASSWORD>
      </ws:Save>
   </soapenv:Body>
</soapenv:Envelope>";
                #endregion
                _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
                _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
                var response = _httpClient.PostAsync(_tCPAPersonUrl, new JsonContent(xml)).Result;
                _logger.LogInformation("AddTcNewPat:model:" + model.ToJson() + "  response:" + response.ToJson());
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    resStr = response.Content.ReadAsStringAsync().Result;
                    var begin = resStr.IndexOf("<SaveResult>");
                    if (begin < 0)
                    {
                        return 0;
                    }
                    var end = resStr.IndexOf("</SaveResult>") + 13;
                    resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                    var res = resXml.SelectSingleNode("SaveResult")?.InnerText;
                    return int.Parse(res);
                }
            }
            catch (System.Exception ex)
            {
                return 0;
            }
            return 0;
        }

        public int AddTcPatInfo(Pub_Pat_Info model, string howKnow = "009")
        {
            try
            {
                //<ws:PAPERName3></ws:PAPERName3>
                var resStr = string.Empty;
                XmlDocument soapEnvelopeXml = new XmlDocument();
                XmlDocument resXml = new XmlDocument();

                var sex = string.Empty;
                switch (model.Gender)
                {
                    case 0:
                        sex = "女 Female";
                        break;
                    case 1:
                        sex = "男 Male";
                        break;
                    case 2:
                        sex = "未知 Unknown";
                        break;
                }

                #region xml
                string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://www.intersystems.com/trak/ws"">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Save>
         <!--Optional:-->
         <ws:token></ws:token>
         <!--Optional:-->
         <ws:rs>
            <ws:PAPERName>" + model.Last_Name + @"</ws:PAPERName>
            <ws:PAPERName2>" + model.First_Name + @"</ws:PAPERName2>
            <ws:CTSEXDesc>" + sex + @"</ws:CTSEXDesc>
            <ws:PAPERMobPhone>" + model.Phone_NO + @"</ws:PAPERMobPhone>
            <ws:PAPERDob>" + model.Birthday + @"</ws:PAPERDob>
            <ws:PAPERID>" + model.Card_ID + @"</ws:PAPERID>";
                if (!string.IsNullOrEmpty(model.Nationality))
                {
                    xml += @"<ws:CTNATDesc>" + model.Nationality + @"</ws:CTNATDesc>";
                }

                xml += @"<ws:ASSISDesc>" + howKnow + @"</ws:ASSISDesc>
         </ws:rs>
         <ws:TUSERNAME>api</ws:TUSERNAME>
         <ws:TPASSWORD>trak456</ws:TPASSWORD>
      </ws:Save>
   </soapenv:Body>
</soapenv:Envelope>";
                #endregion
                _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
                _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
                var response = _httpClient.PostAsync(_tCPAPersonUrl, new JsonContent(xml)).Result;
                _logger.LogInformation("AddTcPatInfo:requestxml:" + xml);
                _logger.LogInformation("AddTcPatInfo:model:" + model.ToJson() + "  response:" + response.ToJson());
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    resStr = response.Content.ReadAsStringAsync().Result;
                    _logger.LogInformation("AddTcPatInfo:responsexml:" + resStr);
                    var begin = resStr.IndexOf("<SaveResult>");
                    if (begin < 0)
                    {
                        return 0;
                    }
                    var end = resStr.IndexOf("</SaveResult>") + 13;
                    resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                    var res = resXml.SelectSingleNode("SaveResult")?.InnerText;
                    return int.Parse(res);
                }
            }
            catch (System.Exception ex)
            {
                return 0;
            }
            return 0;
        }

        public int UpdatePatInfo(PAPerson tcPatInfo, string cardId)
        {
            try
            {
                //<ws:PAPERName3>" + tcPatInfo.PAPERName3 + @"</ws:PAPERName3>
                var resStr = string.Empty;
                XmlDocument soapEnvelopeXml = new XmlDocument();
                XmlDocument resXml = new XmlDocument();
                #region xml
                string xml = @"<soapenv:Envelope
    xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
    xmlns:ws=""http://www.intersystems.com/trak/ws"">
    <soapenv:Header/>
    <soapenv:Body>
        <ws:Save>
            <ws:token></ws:token>
            <ws:rs>
                <ws:ID>" + tcPatInfo.PAPERRowId + @"</ws:ID>
                <ws:PAPERName>" + tcPatInfo.PAPERName + @"</ws:PAPERName>
                <ws:PAPERName2>" + tcPatInfo.PAPERName2 + @"</ws:PAPERName2>
                <ws:CTSEXDesc>" + tcPatInfo.PAPERSex + @"</ws:CTSEXDesc>
                <ws:PAPERMobPhone>" + tcPatInfo.PAPERMobPhone + @"</ws:PAPERMobPhone>
                <ws:PAPERDob>" + tcPatInfo.PAPERDob + @"</ws:PAPERDob>
                <ws:PAPERID>" + cardId + @"</ws:PAPERID></ws:rs>
                <ws:TUSERNAME>api</ws:TUSERNAME>
                <ws:TPASSWORD>trak456</ws:TPASSWORD>
                </ws:Save>
            </soapenv:Body>
        </soapenv:Envelope>";
                #endregion
                _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
                _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
                var response = _httpClient.PostAsync(_tCPAPersonUrl, new JsonContent(xml)).Result;
                _logger.LogInformation("UpdatePatInfo:model:" + tcPatInfo.ToJson() + "  response:" + response.ToJson());
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    resStr = response.Content.ReadAsStringAsync().Result;
                    var begin = resStr.IndexOf("<SaveResult>");
                    if (begin < 0)
                    {
                        return 0;
                    }
                    var end = resStr.IndexOf("</SaveResult>") + 13;
                    resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                    var res = resXml.SelectSingleNode("SaveResult")?.InnerText;
                    return int.Parse(res);
                }
            }
            catch (System.Exception ex)
            {
                return 0;
            }
            return 0;
        }

        public List<GetDrugs> GetDrugs()
        {
            List<GetDrugs> res = new List<GetDrugs>();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" 
 xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
xmlns:sino=""http://sino.com.cn"">
  " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:GetDrugs>
         <!--Optional:-->
         <sino:Token>?</sino:Token>
      </sino:GetDrugs>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion

            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetDrugs");
            var response = _httpClient.PostAsync(_tCARCItmMastUrl, new JsonContent(xml)).Result;
            //_logger.LogInformation("GetDrugs:" + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetDrugsResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetDrugsResult>") + 17;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)).Replace("s01:ARCItmMast xmlns=\"http://sino.com.cn/\" xmlns:s01=\"http://sino.com.cn\"", "ARCItmMast").Replace("s01:ARCItmMast", "ARCItmMast"));
                foreach (XmlNode item in resXml.SelectNodes("GetDrugsResult/Drugs/ARCItmMast"))
                {
                    GetDrugs model = new GetDrugs();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "ARCIMCode":
                                model.ARCIMCode = item1?.InnerText;
                                break;
                            case "PHCDFDescription":
                                model.PHCDFDescription = item1?.InnerText;
                                break;
                            case "ARCIMDesc":
                                model.ARCIMDesc = item1?.InnerText;
                                break;
                            case "PHMNFName":
                                model.PHMNFName = item1?.InnerText;
                                break;
                            case "ARCBGDesc":
                                model.ARCBGDesc = item1?.InnerText;
                                break;
                            case "PACKDescription":
                                model.PACKDescription = item1?.InnerText;
                                break;
                            case "PHCFDesc":
                                model.PHCFDesc = item1?.InnerText;
                                break;
                            case "ROUTEDesc":
                                model.ROUTEDesc = item1?.InnerText;
                                break;
                            case "PHCFRDesc":
                                model.PHCFRDesc = item1?.InnerText;
                                break;
                            case "PHCSDesc":
                                model.PHCSDesc = item1?.InnerText;
                                break;
                            case "CTUOMDesc":
                                model.CTUOMDesc = item1?.InnerText;
                                break;
                            case "PHCDFBaseQty":
                                model.PHCDFBaseQty = item1?.InnerText;
                                break;
                            case "ITPPrice":
                                model.ITPPrice = item1?.InnerText;
                                break;
                        }
                    }
                    res.Add(model);
                }
            }
            return res;
        }

        /// <summary>
        /// 提交预约
        /// </summary>
        /// <param name="ubrn"></param>
        /// <param name="usrn"></param>
        /// <param name="patId"></param>
        /// <returns></returns>
        public int ConfirmApptEdit(string ubrn, string usrn, string patId)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://www.intersystems.com/trak/ws"">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Save>
         <ws:rs>
            <ws:APPTUBRN>" + ubrn + @"</ws:APPTUBRN>
            <ws:APPTUSRN>" + usrn + @"</ws:APPTUSRN>
            <ws:PatientID>" + patId + @"</ws:PatientID>
         </ws:rs>
         <ws:TUSERNAME>api</ws:TUSERNAME>
         <ws:TPASSWORD>trak456</ws:TPASSWORD>
      </ws:Save>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
            var response = _httpClient.PostAsync(_tCConfirmApptEditUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("ConfirmApptEdit: ubrn:" + ubrn + "  response:" + response.StatusCode);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<SaveResult>");
                if (begin < 0)
                {
                    return 0;
                }
                var end = resStr.IndexOf("</SaveResult>") + 13;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return int.Parse(resXml.SelectSingleNode("SaveResult")?.InnerText);
            }
            return 0;
        }

        /// <summary>
        /// 取消预约
        /// </summary>
        /// <param name="ubrn"></param>
        /// <param name="usrn"></param>
        /// <returns></returns>
        public int CancelAppt(string ubrn, string usrn)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
                            xmlns:ws=""http://www.intersystems.com/trak/ws"">
                               <soapenv:Header/>
                               <soapenv:Body>
                                  <ws:Save>
                                     <ws:rs>
                                        <ws:APPTUBRN>" + ubrn + @"</ws:APPTUBRN>
                                        <ws:APPTUSRN>" + usrn + @"</ws:APPTUSRN>
                                     </ws:rs>
                                      <ws:TUSERNAME>api</ws:TUSERNAME>
                                     <ws:TPASSWORD>trak456</ws:TPASSWORD>
                                  </ws:Save>
                               </soapenv:Body>
                            </soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Save");
            var response = _httpClient.PostAsync(_tCCancelApptEditUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("CancelAppt: ubrn:" + ubrn + "  response:" + response.StatusCode);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<SaveResult>");
                if (begin < 0)
                {
                    return 0;
                }
                var end = resStr.IndexOf("</SaveResult>") + 13;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return int.Parse(resXml.SelectSingleNode("SaveResult")?.InnerText);
            }
            return 0;
        }

        /// <summary>
        /// 给患者打pp所属标签
        /// </summary>
        /// <param name="token"></param>
        /// <param name="patientID"></param>
        /// <param name="isPatientPortalInstalled"></param>
        /// <returns></returns>
        public bool UpdatePatientPortalLink(string token, string patientID, bool isPatientPortalInstalled)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope
                                xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
                                xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
                                xmlns:sino=""http://sino.com.cn"">
                               " + GetTCXmlHeader() + @"
                               <soapenv:Body>
                                <sino:UpdatePatientPortalLink>
                                    <!--Optional:-->
                                    <sino:Token>" + token + @"</sino:Token>
                                    <!--Optional:-->
                                    <sino:PatientID>" + patientID + @"</sino:PatientID>
                                    <!--Optional:-->
                                    <sino:IsPatientPortalInstalled>" + isPatientPortalInstalled.ToString().ToLower() + @"</sino:IsPatientPortalInstalled>
                                </sino:UpdatePatientPortalLink>
                            </soapenv:Body>
                            </soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "UpdatePatientPortalLink");
            var response = _httpClient.PostAsync(_tCUpdatePatientPortalLinkUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("UpdatePatientPortalLink: token:" + token + "  patientID:" + patientID + "  isPatientPortalInstalled:" + isPatientPortalInstalled + "  response:" + response.StatusCode);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<UpdatePatientPortalLinkResult>");
                if (begin < 0)
                {
                    return false;
                }
                var end = resStr.IndexOf("</UpdatePatientPortalLinkResult>") + 32;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return bool.Parse(resXml.SelectSingleNode("UpdatePatientPortalLinkResult/Result")?.InnerText);
            }
            return false;
        }

        public List<GetReportList> GetReportList(string mrn)
        {
            List<GetReportList> res = new List<GetReportList>();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope 
xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
                xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
                xmlns:sino=""http://sino.com.cn"">
  " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:GetReportList>
         <sino:PID>" + mrn + @"</sino:PID>
      </sino:GetReportList>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetReportList");
            var response = _httpClient.PostAsync(_tCGetPatientReportUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetReportList: mrn:" + mrn + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<FileList>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</FileList>") + 11;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                foreach (XmlNode item in resXml.SelectNodes("FileList/FileInfo"))
                {
                    GetReportList model = new GetReportList();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "PID":
                                model.PID = item1?.InnerText;
                                break;
                            case "DocumentID":
                                model.DocumentID = item1?.InnerText;
                                break;
                            case "FileType":
                                model.FileType = item1?.InnerText;
                                break;
                            case "FileDes":
                                model.FileDes = item1?.InnerText;
                                break;
                            case "DateCreated":
                                model.DateCreated = item1?.InnerText;
                                break;
                            case "TimeCreated":
                                model.TimeCreated = item1?.InnerText;
                                break;
                            case "LastUpdateUser":
                                model.LastUpdateUser = item1?.InnerText;
                                break;
                            case "DocumentTypeDesc":
                                model.DocumentTypeDesc = item1?.InnerText;
                                break;
                            case "DocumentTypeCode":
                                model.DocumentTypeCode = item1?.InnerText;
                                break;
                        }
                    }
                    res.Add(model);
                }
            }
            return res;
        }

        public string GetFileContent(string documentID, string mrn)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope 
xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
                xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
                xmlns:sino=""http://sino.com.cn"">
   " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:GetFileContent>
         <sino:DocumentID>" + documentID + @"</sino:DocumentID>
         <sino:PID>" + mrn + @"</sino:PID>
      </sino:GetFileContent>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetFileContent");
            var response = _httpClient.PostAsync(_tCGetPatientReportUrl, new JsonContent(xml)).Result;
            _logger.LogInformation("GetFileContent: mrn:" + mrn + "  documentID:" + documentID + "  response:" + response.ToJson());
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetFileContentResult>");
                if (begin < 0)
                {
                    return "";
                }
                var end = resStr.IndexOf("</GetFileContentResult>") + 23;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return resXml.SelectSingleNode("GetFileContentResult/DocumentContent")?.InnerText;
            }
            return "";
        }

        public List<Regcombos> GetClinicalInfo(string episodeNo, int language)
        {
            if (string.IsNullOrEmpty(episodeNo))
            {
                return new List<Regcombos>();
            }
            List<Regcombos> res = new List<Regcombos>();
            var resStr = string.Empty;
            XmlDocument itemxml = new XmlDocument();
            XmlDocument resXml = new XmlDocument();
            #region xml
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">
   " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:GetClinicalInfo>
         <!--Optional:-->
         <sino:Token></sino:Token>
         <!--Optional:-->
         <sino:EpisodeNo>" + episodeNo + @" </sino:EpisodeNo>
         <!--Optional:-->
         <sino:Type></sino:Type>
      </sino:GetClinicalInfo>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetClinicalInfo");
            var response = _httpClient.PostAsync(_tCClinicalInfoUrl, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<GetClinicalInfoResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</GetClinicalInfoResult>") + 24;
                var s = resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end));
                s = s.Replace(" xsi:nil=\"true\"", "");
                resXml.LoadXml(s);
                XmlNodeList list = resXml.SelectNodes("GetClinicalInfoResult/REGCOMBOS/REGCOMBO");
                foreach (XmlNode item in list)
                {
                    Regcombos model = new Regcombos();
                    foreach (XmlNode item1 in item)
                    {
                        switch (item1.Name)
                        {
                            case "REGCODE":
                                model.REGCODE = item1?.InnerText;
                                break;
                            case "COMBOCTYPE":
                                model.COMBOCTYPE = item1?.InnerText;
                                break;
                            case "COMBOCODE":
                                model.COMBOCODE = item1?.InnerText;
                                break;
                            case "COMBODESC":
                                model.COMBODESC = item1?.InnerText;
                                break;
                            case "QUIT":
                                model.QUIT = item1?.InnerText;
                                break;
                            case "CHECKDATE":
                                model.CHECKDATE = item1?.InnerText;
                                break;
                            case "CHECKTIME":
                                model.CHECKTIME = item1?.InnerText;
                                break;
                            case "DateRead":
                                model.DateRead = item1?.InnerText;
                                break;
                            case "TimeRead":
                                model.TimeRead = item1?.InnerText;
                                break;
                            case "UserRead":
                                model.UserRead = item1?.InnerText;
                                break;
                            case "DESCRIPTION":
                                model.Description = item1?.InnerText;
                                break;
                            case "OrderSetCode":
                                model.OrderSetCode = item1?.InnerText;
                                break;
                            case "OrderSetDesc":
                                model.OrderSetDesc = item1?.InnerText;
                                break;
                            case "REGITEMS":
                                itemxml.LoadXml(item1.OuterXml.ToString());
                                List<RegcombosDetail> ls = new List<RegcombosDetail>();
                                foreach (XmlNode item2 in itemxml.SelectNodes("REGITEMS/REGITEM"))
                                {
                                    RegcombosDetail m = new RegcombosDetail();
                                    foreach (XmlNode item3 in item2.ChildNodes)
                                    {
                                        switch (item3.Name)
                                        {
                                            case "ITEMCODE":
                                                m.ITEMCODE = item3?.InnerText;
                                                break;
                                            case "ITEMDES":
                                                m.ITEMDES = item3?.InnerText;
                                                break;
                                            case "DESCRIPTION":
                                                m.DESCRIPTION = item3?.InnerText;
                                                break;
                                            case "LOWERRANGE":
                                                m.LOWERRANGE = item3?.InnerText;
                                                break;
                                            case "RESULTFLAG":
                                                m.RESULTFLAG = item3?.InnerText;
                                                break;
                                            case "UNIT":
                                                m.UNIT = item3?.InnerText;
                                                break;
                                        }
                                    }
                                    ls.Add(m);
                                }
                                model.REGITEMS = ls;
                                break;
                        }
                    }
                    res.Add(model);
                }
            }

            //如果检查检验有数据，那么做特殊处理
            //1:如果是检验L匹配code为80076P（肝功能7项），80061P（血脂4项），80049P（生化6项），80048P（生化7项）那么，将所有为这几项的项目排除掉，直接新建这三种检查，将每一项的item拿出来放在新的检查中
            //2：如果不是上面几种检验，那么根据检验的code从配置电子表格中找到对应的中英文描述，替换上去
            //3：若从电子表格中找不到上述的描述，那么就用OrderSetDesc字段，用#区分中英文，如果没有#号，直接使用字段
            //4：如果检查中存在 Description1 字段中存在 -----  那么通过 ----- 分割2段内容 上半部分标题为：影像描述 Image Description    下半部分标题为：诊断意见 Image Diagnosis(给前端做了)
            //5：检查报告描述存在相通的去重，显示为B超
            if (res.Any())
            {
                //1
                var liverPanel = res.Where(w => w.OrderSetCode == "80076P").ToList();
                var liverPanelitem = new List<RegcombosDetail>();
                var bloodLipidsPanel = res.Where(w => w.OrderSetCode == "80061P").ToList();
                var bloodLipidsPanelitem = new List<RegcombosDetail>();
                var biochemistryPanel = res.Where(w => w.OrderSetCode == "80049P").ToList();
                var biochemistryPanelitem = new List<RegcombosDetail>();
                var OLDPanel = res.Where(w => w.OrderSetCode == "80048P").ToList();
                var OLDPanellitem = new List<RegcombosDetail>();
                if (liverPanel.Any())
                {
                    liverPanel.ForEach(w =>
                    {
                        liverPanelitem.AddRange(w.REGITEMS);
                        res.Remove(w);
                    });
                    var newItem = liverPanel.FirstOrDefault();
                    if (language == 1)
                    {
                        newItem.COMBODESC = "肝功能7项";
                    }
                    else
                    {
                        newItem.COMBODESC = "Liver Panel 7";
                    }
                    newItem.REGITEMS = liverPanelitem;
                    res.Add(newItem);
                }
                if (bloodLipidsPanel.Any())
                {
                    bloodLipidsPanel.ForEach(w =>
                    {
                        bloodLipidsPanelitem.AddRange(w.REGITEMS);
                        res.Remove(w);
                    });
                    var newItem = bloodLipidsPanel.FirstOrDefault();
                    if (language == 1)
                        newItem.COMBODESC = "血脂4项";
                    else
                        newItem.COMBODESC = "Blood Lipids Panel 4";
                    newItem.REGITEMS = bloodLipidsPanelitem;
                    res.Add(newItem);
                }
                if (biochemistryPanel.Any())
                {
                    biochemistryPanel.ForEach(w =>
                    {
                        biochemistryPanelitem.AddRange(w.REGITEMS);
                        res.Remove(w);
                    });
                    var newItem = biochemistryPanel.FirstOrDefault();
                    if (language == 1)
                        newItem.COMBODESC = "生化6项";
                    else
                        newItem.COMBODESC = "Biochemistry Panel 6";
                    newItem.REGITEMS = biochemistryPanelitem;
                    res.Add(newItem);
                }
                if (OLDPanel.Any())
                {
                    OLDPanel.ForEach(w =>
                    {
                        OLDPanellitem.AddRange(w.REGITEMS);
                        res.Remove(w);
                    });
                    var newItem = OLDPanel.FirstOrDefault();
                    if (language == 1)
                        newItem.COMBODESC = "生化6项";
                    else
                        newItem.COMBODESC = "Biochemistry Panel 6";
                    newItem.REGITEMS = OLDPanellitem;
                    res.Add(newItem);
                }
                //2,3
                OrderSetEnum enumdic = new OrderSetEnum();
                res.Where(w => w.COMBOCTYPE == "L" && w.OrderSetCode != "80076P" && w.OrderSetCode != "80061P" && w.OrderSetCode != "80049P" && w.OrderSetCode != "80048P").ToList().ForEach(w =>
                {
                    var ls = enumdic.dic.Where(f => f.Key == w.COMBOCODE);
                    if (ls.Any())
                    {
                        if (language == 1)
                            w.COMBODESC = ls.FirstOrDefault().Value.Split('|')[0];
                        else
                            w.COMBODESC = ls.FirstOrDefault().Value.Split('|')[1];
                    }
                    else
                    {
                        if (language == 1)
                            w.COMBODESC = w.COMBODESC.Split('#').Length > 1 ? w.COMBODESC.Split('#')[1] : w.COMBODESC;
                        else
                            w.COMBODESC = w.COMBODESC.Split('#').Length > 1 ? w.COMBODESC.Split('#')[0] : w.COMBODESC;
                    }
                });
                //5
                var group = res.Where(w => w.COMBOCTYPE == "V").ToList().GroupBy(w => w.Description).ToList();
                var newjiancha = new List<Regcombos>();
                foreach (var item in group)
                {
                    var modells = res.Where(w => w.Description == item.Key).ToList();
                    var model = modells.FirstOrDefault();
                    if (modells.Count() > 1)
                    {
                        model.COMBODESC = "Ultrasonography  B超";
                    }
                    newjiancha.Add(model);
                }
                res = res.Where(w => w.COMBOCTYPE == "L").ToList();
                foreach (var item in newjiancha)
                {
                    res.Add(item);
                }
            }

            return res;
        }

        //通过rowid获取患者其他消息
        public OpenResult PAPersonEditOpen(int id)
        {
            OpenResult res = new OpenResult();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://www.intersystems.com/trak/ws"">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Open>
         <!--Optional:-->
         <!--Optional:-->
  <ws:ID>" + id + @"</ws:ID>
         <!--Optional:-->
         <ws:TUSERNAME>api</ws:TUSERNAME>
         <!--Optional:-->
         <ws:TPASSWORD>trak456</ws:TPASSWORD>
      </ws:Open>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Open");
            var response = _httpClient.PostAsync(_tCPAPersonUrl, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<OpenResult>");
                if (begin < 0)
                {
                    return res;
                }
                var end = resStr.IndexOf("</OpenResult>") + 13;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                foreach (XmlNode item in resXml.SelectNodes("OpenResult"))
                {
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "TENCRYPTPASSWORD":
                                res.TENCRYPTPASSWORD = item1?.InnerText;
                                break;
                            case "AddressChange":
                                res.AddressChange = item1?.InnerText; break;
                            case "AllowAddLanguages":
                                res.AllowAddLanguages = item1?.InnerText; break;
                            case "AllowViewVIP":
                                res.AllowViewVIP = item1?.InnerText; break;
                            case "AnonymousName":
                                res.AnonymousName = item1?.InnerText; break;
                            case "CanEnrollPatient":
                                res.CanEnrollPatient = item1?.InnerText; break;
                            case "CodeTableValidationDate": res.CodeTableValidationDate = item1?.InnerText; break;
                            case "CopyID": res.CopyID = item1?.InnerText; break;
                            case "DoctorChanged": res.DoctorChanged = item1?.InnerText; break;
                            case "FeedbackConsentData": res.FeedbackConsentData = item1?.InnerText; break;
                            case "HiddenCodes": res.HiddenCodes = item1?.InnerText; break;
                            case "HiddenHSCommunityEnrollmentStatus": res.HiddenHSCommunityEnrollmentStatus = item1?.InnerText; break;
                            case "HiddenSexG": res.HiddenSexG = item1?.InnerText; break;
                            case "ID": res.ID = item1?.InnerText; break;
                            case "ManualMRNType": res.ManualMRNType = item1?.InnerText; break;
                            case "MaxGestWeeks": res.MaxGestWeeks = item1?.InnerText; break;
                            case "MinGestWeeks": res.MinGestWeeks = item1?.InnerText; break;
                            case "MultiActiveGP": res.MultiActiveGP = item1?.InnerText; break;
                            case "OutstAmt": res.OutstAmt = item1?.InnerText; break;
                            case "PAPERDeceasedFlag": res.PAPERDeceasedFlag = item1?.InnerText; break;
                            case "PATCF": res.PATCF = item1?.InnerText; break;
                            case "PDSBirthTimeoutFail": res.PDSBirthTimeoutFail = item1?.InnerText; break;
                            case "PatientID": res.PatientID = item1?.InnerText; break;
                            case "RegNumHidden": res.RegNumHidden = item1?.InnerText; break;
                            case "RegionResctrictions": res.RegionResctrictions = item1?.InnerText; break;
                            case "StandardTypeItemYes": res.StandardTypeItemYes = item1?.InnerText; break;
                            case "UpdatePDS": res.UpdatePDS = item1?.InnerText; break;
                            case "Updated": res.Updated = item1?.InnerText; break;
                            case "UserID": res.UserID = item1?.InnerText; break;
                            case "ValidAgr": res.ValidAgr = item1?.InnerText; break;
                            case "aliasconfirm": res.aliasconfirm = item1?.InnerText; break;
                            case "cdate": res.cdate = item1?.InnerText; break;
                            case "hidIncompleteRegistration": res.hidIncompleteRegistration = item1?.InnerText; break;
                            case "noAlias": res.noAlias = item1?.InnerText; break;
                            case "refresh": res.refresh = item1?.InnerText; break;
                            case "ASSISDesc": res.ASSISDesc = item1?.InnerText; break;
                            case "AgeDynamic": res.AgeDynamic = item1?.InnerText; break;
                            case "AgeUnits": res.AgeUnits = item1?.InnerText; break;
                            case "CTNATDesc": res.CTNATDesc = item1?.InnerText; break;
                            case "CTSEXDesc": res.CTSEXDesc = item1?.InnerText; break;
                            case "ChangeRN": res.ChangeRN = item1?.InnerText; break;
                            case "HOSPDesc": res.HOSPDesc = item1?.InnerText; break;
                            case "PAPERAge": res.PAPERAge = item1?.InnerText; break;
                            case "PAPERDob": res.PAPERDob = item1?.InnerText; break;
                            case "PAPEREmail": res.PAPEREmail = item1?.InnerText; break;
                            case "PAPERGestationDays": res.PAPERGestationDays = item1?.InnerText; break;
                            case "PAPERGestationWeeks": res.PAPERGestationWeeks = item1?.InnerText; break;
                            case "PAPERHSCommunityEnrollmentStatus": res.PAPERHSCommunityEnrollmentStatus = item1?.InnerText; break;
                            case "PAPERID": res.PAPERID = item1?.InnerText; break;
                            case "PAPERMobPhone": res.PAPERMobPhone = item1?.InnerText; break;
                            case "PAPERName": res.PAPERName = item1?.InnerText; break;
                            case "PAPERName2": res.PAPERName2 = item1?.InnerText; break;
                            case "PAPERNokName": res.PAPERNokName = item1?.InnerText; break;
                            case "PAPERPrevHACCEligible": res.PAPERPrevHACCEligible = item1?.InnerText; break;
                            case "PAPERUpdateDate": res.PAPERUpdateDate = item1?.InnerText; break;
                            case "PAPERUpdateTime": res.PAPERUpdateTime = item1?.InnerText; break;
                            case "PAPERUserUpdate": res.PAPERUserUpdate = item1?.InnerText; break;
                            case "RegistrationNumber": res.RegistrationNumber = item1?.InnerText; break;
                            case "UserCode": res.UserCode = item1?.InnerText; break;
                            case "PAPERCityCodeDR": res.PAPERCityCodeDR = item1?.InnerText; break;
                            case "PAPERCityCode": res.PAPERCityCode = item1?.InnerText; break;
                            case "PAPERPreferredContactMethod": res.PAPERPreferredContactMethod = item1?.InnerText; break;
                            case "PAPERStName": res.PAPERStName = item1?.InnerText; break;
                            case "CTRLTDesc": res.CTRLTDesc = item1?.InnerText; break;
                            case "PAPERNokPhone": res.PAPERNokPhone = item1?.InnerText; break;
                            case "CTCITDesc": res.CTCITDesc = item1?.InnerText; break;
                            case "PAPERRemark": res.PAPERRemark = item1?.InnerText; break;
                        }
                    }
                }
            }
            return res;
        }

        //新患者录入更新患者
        public bool CustomCRMPAPerson(CustomCRMPAPerson request)
        {
            //<!--Optional:-->
            //< sino:PAPERName3 > " + request.PAPERName3 + @" </ sino:PAPERName3 >
            _logger.LogInformation("CustomCRMPAPerson:request " + request.ToJson());
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            string remarkstr = @"";
            foreach (var item in request.PAPERRemark)
            {
                remarkstr += " <sino:PAPERRemarkItem>" + item.PAPERRemarkItem + "</sino:PAPERRemarkItem> ";
            }
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"" xmlns:sino1=""http://sino.com.cn/"">" + GetTCXmlHeader() + @" <soapenv:Body>
      <sino:Update>
         <!--Optional:-->
         <!--Optional:-->
         <sino:PAPerson>
            <!--Optional:-->
            <!--Optional:-->";
            if (request.PAPERRowId > 0)
            {
                xml += "<sino:PAPERRowId>" + request.PAPERRowId + @"</sino:PAPERRowId>";
            }
            xml += "<sino:PAPERName>" + request.PAPERName + @"</sino:PAPERName>
            <!--Optional:-->
            <sino:PAPERName2>" + request.PAPERName2 + @"</sino:PAPERName2>
            
            <!--Optional:-->
            <sino:PAPERDob>" + request.PAPERDob + @"</sino:PAPERDob>
            <!--Optional:-->
            <sino:PAPERSexDR>" + request.PAPERSexDR + @"</sino:PAPERSexDR>
            <!--Optional:-->
            <sino:PAPERID>" + request.PAPERID + @"</sino:PAPERID>
            <!--Optional:-->
            <sino:PAPERMobPhone>" + request.PAPERMobPhone + @"</sino:PAPERMobPhone>
            <!--Optional:-->
            <sino:PAPERStName>" + request.PAPERStName + @"</sino:PAPERStName>
            <!--Optional:-->
            <sino:PAPERCityCodeDR>" + request.PAPERCityCodeDR + @"</sino:PAPERCityCodeDR>
            <!--Optional:-->
            <sino:PAPEREmail>" + request.PAPEREmail + @"</sino:PAPEREmail>
            <!--Optional:-->
            <sino:PAPERNationDR>" + request.PAPERNationDR + @"</sino:PAPERNationDR>
            <!--Optional:-->
            <sino:PAPERNokName>" + request.PAPERNokName + @"</sino:PAPERNokName>
            <!--Optional:-->
            <sino:PAPERNokPhone>" + request.PAPERNokPhone + @"</sino:PAPERNokPhone>
            <!--Optional:-->
            <sino:PAPERNokCTRLTDR>" + request.PAPERNokCTRLTDR + @"</sino:PAPERNokCTRLTDR>
            <!--Optional:-->
            <sino:PAPERRemark>
               <!--Zero or more repetitions:-->
             " + remarkstr + @"
            </sino:PAPERRemark>
            <!--Optional:-->
            <sino:PAPERPreferredContactMethod>" + request.PAPERPreferredContactMethod + @"</sino:PAPERPreferredContactMethod>
            <!--Optional:-->
            <sino:PAPERHowDidYouLearnUsDR>" + request.PAPERHowDidYouLearnUsDR + @"</sino:PAPERHowDidYouLearnUsDR>
         </sino:PAPerson>
      </sino:Update>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "Update");
            var response = _httpClient.PostAsync(_tCCustomCRM, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<UpdateResult>");
                if (begin < 0)
                {
                    return false;
                }
                var end = resStr.IndexOf("</UpdateResult>") + 15;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return bool.Parse(resXml.SelectSingleNode("UpdateResult/Result")?.InnerText);
            }
            return false;
        }

        public bool CustomCRMPictures(string picparref, string picdesc, string attachmentfileName, string attachment)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">
  " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:CreateNew>
         <!--Optional:-->
         <sino:PAPersonPicture>
            <!--Optional:-->
            <sino:PICParRef>" + picparref + @"</sino:PICParRef>
            <!--Optional:-->
            <sino:PICDesc>" + picdesc + @"</sino:PICDesc>
            <!--Optional:-->
            <sino:PICUserCreated>api</sino:PICUserCreated>
            <!--Optional:-->
            <sino:PICInactive>N</sino:PICInactive>
            <!--Optional:-->
            <sino:PICDocTypeDR>""Request Form Upload""</sino:PICDocTypeDR>
         </sino:PAPersonPicture>
         <!--Optional:-->
         <sino:Attachment>" + attachment + @"</sino:Attachment>
         <!--Optional:-->
         <sino:AttachmentFileName>" + attachmentfileName + @"</sino:AttachmentFileName>
      </sino:CreateNew>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "CreateNew");
            var response = _httpClient.PostAsync(_tCCustomCRMPictures, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<CreateNewResult>");
                if (begin < 0)
                {
                    return false;
                }
                var end = resStr.IndexOf("</CreateNewResult>") + 18;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return bool.Parse(resXml.SelectSingleNode("CreateNewResult/Result")?.InnerText);
            }
            return false;
        }
        /// <summary>
        /// tc体检报告推送PDF
        /// </summary>
        /// <param name="picparref"></param>
        /// <param name="picdesc"></param>
        /// <param name="attachmentfileName"></param>
        /// <param name="attachment"></param>
        /// <returns></returns>
        public bool CustomCRMMRPictures(string picparref, string picdesc, string attachmentfileName, string attachment, string uploadaddr = "")
        {
            if (string.IsNullOrEmpty(uploadaddr))
            {
                uploadaddr = "Patient Questionnaires";
            }
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">
  " + GetTCXmlHeader() + @"
   <soapenv:Body>
      <sino:CreateNew>
         <!--Optional:-->
         <sino:MRPicture>
            <!--Optional:-->
            <sino:PICParRef>" + picparref + @"</sino:PICParRef>
            <!--Optional:-->
            <sino:PICDesc>" + picdesc + @"</sino:PICDesc>
            <!--Optional:-->
            <sino:PICUserCreated>api</sino:PICUserCreated>
            <!--Optional:-->
            <sino:PICInactive>N</sino:PICInactive>
            <!--Optional:-->
            <sino:PICDocTypeDR>" + uploadaddr + @"</sino:PICDocTypeDR>
            <sino:PICVisible>N</sino:PICVisible>
         </sino:MRPicture>
         <!--Optional:-->
         <sino:Attachment>" + attachment + @"</sino:Attachment>
         <!--Optional:-->
         <sino:AttachmentFileName>" + attachmentfileName + @"</sino:AttachmentFileName>
      </sino:CreateNew>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            //_logger.LogInformation("SendFileToTcQuestxml:" + xml);
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "CreateNew");
            var response = _httpClient.PostAsync(_tCCustomCRMMRPictures, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                //_logger.LogInformation("SendFileToTcQuestresstr:" + resStr);
                var begin = resStr.IndexOf("<CreateNewResult>");
                if (begin < 0)
                {
                    return false;
                }
                var end = resStr.IndexOf("</CreateNewResult>") + 18;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return bool.Parse(resXml.SelectSingleNode("CreateNewResult/Result")?.InnerText);
            }
            return false;
        }


        public bool UpdateAppointment(string usrn, string remarks)
        {
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" 
xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
xmlns:sino=""http://sino.com.cn"">
" + GetTCXmlHeader() + @" <soapenv:Body>
      <sino:UpdateAppointment>
        <sino:APPTUSRN>" + usrn + @"</sino:APPTUSRN>
         <sino:APPTRemarks>" + remarks + @"</sino:APPTRemarks>
      </sino:UpdateAppointment>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "UpdateAppointment");
            var response = _httpClient.PostAsync(_tCRBAppointmentUrl, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                var begin = resStr.IndexOf("<UpdateAppointmentResult>");
                if (begin < 0)
                {
                    return false;
                }
                var end = resStr.IndexOf("</UpdateAppointmentResult>") + 26;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                return bool.Parse(resXml.SelectSingleNode("UpdateAppointmentResult/Result")?.InnerText);
            }
            return false;
        }

        public string GetTCXmlHeader()
        {
            return @"<soapenv:Header>
        <wsse:Security mustUnderstand=""true"">
            <wsse:UsernameToken>
                <wsse:Username>api</wsse:Username>
                <wsse:Password>trak456</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>";
        }

        public class JsonContent : StringContent
        {
            public JsonContent(string obj) : base(obj, Encoding.UTF8, "text/xml")
            { }
        }

        /// <summary>
        /// 查询患者
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<GetPatientOutput> GetPatientAsync(GetPatientInput input)
        {
            try
            {
                SetRequestHeaders("SOAPAction", "GetPatientByMRN");

                var requestXml = CreateRequestXml(input, true);
                var httpResponseMessage = await _httpClient.PostAsync(_tCPAPersonMobileUrl, new JsonContent(requestXml));

                if (!httpResponseMessage.IsSuccessStatusCode)
                {
                    _logger.LogError($"tc患者查询出错:request:{input.ToJson()},responseXml-{await httpResponseMessage.Content.ReadAsStringAsync()},error-{httpResponseMessage.ReasonPhrase}");
                    return new GetPatientOutput();
                }

                var responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
                _logger.LogInformation($"GetPatientAsync request:{input.ToJson()} response:{responseContent}");

                var result = DeserializeToEntity<GetPatientOutput>(responseContent, "GetPatientByMRNResult", "PAPerson");

                return result;
            }
            catch (System.Exception e)
            {
                _logger.LogError($"tc患者查询出错:request-{input.ToJson()},error-{e.Message}");
                return new GetPatientOutput();
            }
        }

        /// <summary>
        /// 医生获取排班 多日期
        /// </summary>
        /// <returns></returns>
        public GetSlots GetSlotsForCareProvID(string datefrom, string dateto, int hisDocId)
        {
            GetSlots result = new GetSlots();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            XmlDocument itemxml = new XmlDocument();
            XmlDocument slotxml = new XmlDocument();
            XmlDocument slotitemxml = new XmlDocument();
            XmlDocument slotitemxmldetail = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">
            " + GetTCXmlHeader() + @"
             <soapenv:Body>
      <sino:GetCPWithSlotsForDateByCareProvID>
         <sino:DateFrom>" + datefrom + @"</sino:DateFrom>
         <sino:DateTo>" + dateto + @"</sino:DateTo>
         <sino:CareProvID>" + hisDocId + @"</sino:CareProvID>
      </sino:GetCPWithSlotsForDateByCareProvID>
   </soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetCPWithSlotsForDateByCareProvID");
            var response = _httpClient.PostAsync(_tCRBAppointmentUrl, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                //_logger.LogInformation("SendFileToTcQuestresstr:" + resStr);
                var begin = resStr.IndexOf("<GetCPWithSlotsForDateByCareProvIDResult>");
                if (begin < 0)
                {
                    return result;
                }
                var end = resStr.IndexOf("</GetCPWithSlotsForDateByCareProvIDResult>") + 42;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                foreach (XmlNode item in resXml.SelectNodes("GetCPWithSlotsForDateByCareProvIDResult/LocationList/Location"))
                {
                    GetSlotsItem model = new GetSlotsItem();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "Hospital":
                                model.Hospital = item1?.InnerText;
                                break;
                            case "HospitalCN":
                                model.HospitalCN = item1?.InnerText;
                                break;
                            case "LocationId":
                                model.LocationId = int.Parse(item1?.InnerText);
                                break;
                            case "Location":
                                model.Location = item1?.InnerText;
                                break;
                            case "ServiceList":
                                itemxml.LoadXml(item1.OuterXml.ToString());
                                List<GetSlotsService> ls = new List<GetSlotsService>();
                                foreach (XmlNode item2 in itemxml.SelectNodes("ServiceList/Service"))
                                {
                                    GetSlotsService m = new GetSlotsService();
                                    foreach (XmlNode item3 in item2.ChildNodes)
                                    {
                                        switch (item3.Name)
                                        {
                                            case "ServiceId":
                                                m.ServiceId = int.Parse(item3?.InnerText);
                                                break;
                                            case "ServiceDesc":
                                                m.ServiceDesc = item3?.InnerText;
                                                break;
                                            case "SlotDates":
                                                slotxml.LoadXml(item3.OuterXml.ToString());
                                                List<GetSlotsServiceSlotDate> slot = new List<GetSlotsServiceSlotDate>();
                                                foreach (XmlNode item4 in slotxml.SelectNodes("SlotDates/SlotDate"))
                                                {
                                                    GetSlotsServiceSlotDate mm = new GetSlotsServiceSlotDate();
                                                    foreach (XmlNode item5 in item4.ChildNodes)
                                                    {
                                                        switch (item5.Name)
                                                        {
                                                            case "Date":
                                                                mm.Date = item5.InnerText;
                                                                break;
                                                            case "Resources":
                                                                slotitemxml.LoadXml(item5.OuterXml.ToString());
                                                                List<Resources> resources = new List<Resources>();
                                                                foreach (XmlNode item6 in slotitemxml.SelectNodes("Resources/Resource"))
                                                                {
                                                                    Resources mmm = new Resources();
                                                                    foreach (XmlNode item7 in item6.ChildNodes)
                                                                    {
                                                                        switch (item7.Name)
                                                                        {
                                                                            case "ResourceID":
                                                                                mmm.ResourceID = int.Parse(item7.InnerText);
                                                                                break;
                                                                            case "ResourceDesc":
                                                                                mmm.ResourceDesc = item7.InnerText;
                                                                                break;
                                                                            case "CareProvDesc":
                                                                                mmm.CareProvDesc = item7.InnerText;
                                                                                break;
                                                                            case "CareProvID":
                                                                                mmm.CareProvID = int.Parse(item7.InnerText);
                                                                                break;
                                                                            case "Slots":
                                                                                slotitemxmldetail.LoadXml(item7.OuterXml.ToString());
                                                                                List<Slots> slots = new List<Slots>();
                                                                                foreach (XmlNode item8 in slotitemxmldetail.SelectNodes("Slots/Slot"))
                                                                                {
                                                                                    Slots mmmm = new Slots();
                                                                                    foreach (XmlNode item9 in item8.ChildNodes)
                                                                                    {
                                                                                        switch (item9.Name)
                                                                                        {
                                                                                            case "USRN":
                                                                                                mmmm.USRN = item9.InnerText;
                                                                                                break;
                                                                                            case "StartTime":
                                                                                                mmmm.StartTime = item9.InnerText;
                                                                                                break;
                                                                                            case "EndTime":
                                                                                                mmmm.EndTime = item9.InnerText;
                                                                                                break;
                                                                                            case "RBASId":
                                                                                                mmmm.RBASId = item9.InnerText;
                                                                                                break;
                                                                                            case "IsAfternoon":
                                                                                                mmmm.IsAfternoon = bool.Parse(item9.InnerText);
                                                                                                break;
                                                                                        }
                                                                                    }
                                                                                    slots.Add(mmmm);
                                                                                }
                                                                                mmm.Slots = slots;
                                                                                break;
                                                                        }
                                                                    }
                                                                    resources.Add(mmm);
                                                                }
                                                                mm.Resources = resources;
                                                                break;
                                                        }
                                                    }
                                                    slot.Add(mm);
                                                }
                                                m.SlotDates = slot;
                                                break;
                                        }
                                    }
                                    ls.Add(m);
                                }
                                model.ServiceList = ls;
                                break;
                        }
                    }
                    result.LocationList.Add(model);
                }
                var s = JsonConvert.SerializeObject(result);
            }
            return result;
        }

        /// <summary>
        /// 科室获取排班 多日期
        /// </summary>
        /// <returns></returns>
        public GetSlots GetSlotsForLocationID(string datefrom, string dateto, int hisDeptId)
        {
            GetSlots result = new GetSlots();
            var resStr = string.Empty;
            XmlDocument resXml = new XmlDocument();
            XmlDocument itemxml = new XmlDocument();
            XmlDocument slotxml = new XmlDocument();
            XmlDocument slotitemxml = new XmlDocument();
            XmlDocument slotitemxmldetail = new XmlDocument();
            #region xml   
            string xml = @"<soapenv:Envelope xmlns:sino=""http://sino.com.cn"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
            " + GetTCXmlHeader() + @"
                <soapenv:Body>
<sino:GetCPAllSlotsForDateByLocationID>
<sino:DateFrom>" + datefrom + @"</sino:DateFrom>
<sino:DateTo>" + dateto + @"</sino:DateTo>
<sino:LocationID>" + hisDeptId + @"</sino:LocationID>
</sino:GetCPAllSlotsForDateByLocationID>
</soapenv:Body>
</soapenv:Envelope>";
            #endregion
            _httpClient.DefaultRequestHeaders.Remove("SOAPAction");
            _httpClient.DefaultRequestHeaders.Add("SOAPAction", "GetCPWithSlotsForDateByLocationID");
            var response = _httpClient.PostAsync(_tCRBAppointmentUrl, new JsonContent(xml)).Result;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                resStr = response.Content.ReadAsStringAsync().Result;
                //_logger.LogInformation("SendFileToTcQuestresstr:" + resStr);
                var begin = resStr.IndexOf("<GetCPWithSlotsForDateByLocationIDResult>");
                if (begin < 0)
                {
                    return result;
                }
                var end = resStr.IndexOf("</GetCPWithSlotsForDateByLocationIDResult>") + 42;
                resXml.LoadXml(resStr.Substring(begin, resStr.Length - begin - (resStr.Length - end)));
                foreach (XmlNode item in resXml.SelectNodes("GetCPWithSlotsForDateByLocationIDResult/LocationList/Location"))
                {
                    GetSlotsItem model = new GetSlotsItem();
                    foreach (XmlNode item1 in item.ChildNodes)
                    {
                        switch (item1.Name)
                        {
                            case "Hospital":
                                model.Hospital = item1?.InnerText;
                                break;
                            case "HospitalCN":
                                model.HospitalCN = item1?.InnerText;
                                break;
                            case "LocationId":
                                model.LocationId = int.Parse(item1?.InnerText);
                                break;
                            case "Location":
                                model.Location = item1?.InnerText;
                                break;
                            case "ServiceList":
                                itemxml.LoadXml(item1.OuterXml.ToString());
                                List<GetSlotsService> ls = new List<GetSlotsService>();
                                foreach (XmlNode item2 in itemxml.SelectNodes("ServiceList/Service"))
                                {
                                    GetSlotsService m = new GetSlotsService();
                                    foreach (XmlNode item3 in item2.ChildNodes)
                                    {
                                        switch (item3.Name)
                                        {
                                            case "ServiceId":
                                                m.ServiceId = int.Parse(item3?.InnerText);
                                                break;
                                            case "ServiceDesc":
                                                m.ServiceDesc = item3?.InnerText;
                                                break;
                                            case "SlotDates":
                                                slotxml.LoadXml(item3.OuterXml.ToString());
                                                List<GetSlotsServiceSlotDate> slot = new List<GetSlotsServiceSlotDate>();
                                                foreach (XmlNode item4 in slotxml.SelectNodes("SlotDates/SlotDate"))
                                                {
                                                    GetSlotsServiceSlotDate mm = new GetSlotsServiceSlotDate();
                                                    foreach (XmlNode item5 in item4.ChildNodes)
                                                    {
                                                        switch (item5.Name)
                                                        {
                                                            case "Date":
                                                                mm.Date = item5.InnerText;
                                                                break;
                                                            case "Resources":
                                                                slotitemxml.LoadXml(item5.OuterXml.ToString());
                                                                List<Resources> resources = new List<Resources>();
                                                                foreach (XmlNode item6 in slotitemxml.SelectNodes("Resources/Resource"))
                                                                {
                                                                    Resources mmm = new Resources();
                                                                    foreach (XmlNode item7 in item6.ChildNodes)
                                                                    {
                                                                        switch (item7.Name)
                                                                        {
                                                                            case "ResourceID":
                                                                                mmm.ResourceID = int.Parse(item7.InnerText);
                                                                                break;
                                                                            case "ResourceDesc":
                                                                                mmm.ResourceDesc = item7.InnerText;
                                                                                break;
                                                                            case "CareProvDesc":
                                                                                mmm.CareProvDesc = item7.InnerText;
                                                                                break;
                                                                            case "CareProvID":
                                                                                mmm.CareProvID = int.Parse(item7.InnerText);
                                                                                break;
                                                                            case "Slots":
                                                                                slotitemxmldetail.LoadXml(item7.OuterXml.ToString());
                                                                                List<Slots> slots = new List<Slots>();
                                                                                foreach (XmlNode item8 in slotitemxmldetail.SelectNodes("Slots/Slot"))
                                                                                {
                                                                                    Slots mmmm = new Slots();
                                                                                    foreach (XmlNode item9 in item8.ChildNodes)
                                                                                    {
                                                                                        switch (item9.Name)
                                                                                        {
                                                                                            case "USRN":
                                                                                                mmmm.USRN = item9.InnerText;
                                                                                                break;
                                                                                            case "StartTime":
                                                                                                mmmm.StartTime = item9.InnerText;
                                                                                                break;
                                                                                            case "EndTime":
                                                                                                mmmm.EndTime = item9.InnerText;
                                                                                                break;
                                                                                            case "RBASId":
                                                                                                mmmm.RBASId = item9.InnerText;
                                                                                                break;
                                                                                            case "IsAfternoon":
                                                                                                mmmm.IsAfternoon = bool.Parse(item9.InnerText);
                                                                                                break;
                                                                                        }
                                                                                    }
                                                                                    slots.Add(mmmm);
                                                                                }
                                                                                mmm.Slots = slots;
                                                                                break;
                                                                        }
                                                                    }
                                                                    resources.Add(mmm);
                                                                }
                                                                mm.Resources = resources;
                                                                break;
                                                        }
                                                    }
                                                    slot.Add(mm);
                                                }
                                                m.SlotDates = slot;
                                                break;
                                        }
                                    }
                                    ls.Add(m);
                                }
                                model.ServiceList = ls;
                                break;
                        }
                    }
                    result.LocationList.Add(model);
                }
            }
            var s = JsonConvert.SerializeObject(result);
            return result;
        }

        #region tools

        /// <summary>
        /// 设置请求头
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        private void SetRequestHeaders(string name, string value)
        {
            _httpClient.DefaultRequestHeaders.Remove(name);
            _httpClient.DefaultRequestHeaders.Add(name, value);
        }

        /// <summary>
        /// 创建xml请求内容
        /// </summary>
        /// <typeparam name="TInput"></typeparam>
        /// <param name="obj">请求参数</param>
        /// <param name="isRoot">是否拼接根节点</param>
        /// <returns></returns> 
        private string CreateRequestXml<TInput>(TInput obj, bool isRoot) where TInput : class
        {
            var xmlRequest = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:sino=""http://sino.com.cn"">"
                             + GetTCXmlHeader()
                             + "<soapenv:Body>"
                             + ObjectToXml(obj, isRoot)
                             + @"</soapenv:Body>
                             </soapenv:Envelope>";

            return xmlRequest;
        }

        /// <summary>
        /// 拼接xml
        /// </summary>
        /// <typeparam name="TInput"></typeparam>
        /// <param name="obj">请求参数</param>
        /// <param name="isRoot">是否拼接根节点</param>
        /// <returns></returns> 
        private static string ObjectToXml<TInput>(TInput obj, bool isRoot) where TInput : class
        {
            var type = obj.GetType();

            var builder = new StringBuilder();
            var propertyInfos = type.GetProperties();

            foreach (var propertyInfo in propertyInfos)
            {
                var value = propertyInfo.GetValue(obj)?.ToString();

                if (string.IsNullOrEmpty(value))
                {
                    continue;
                }

                builder.Append($"<sino:{propertyInfo.Name}>");

                builder.Append(value);

                builder.Append($"</sino:{propertyInfo.Name}>");
            }

            if (!isRoot)
            {
                return builder.ToString();
            }

            builder.Insert(0, $"<sino:{type.Name}>");
            builder.Append($"</sino:{type.Name}>");

            return builder.ToString();
        }

        /// <summary>
        /// 响应内容Xml转对象
        /// </summary>
        /// <typeparam name="TOutput"></typeparam>
        /// <param name="suorceXml">xml</param>
        /// <param name="subStringXmlNodeName">从此节点检索子字符串</param>
        /// <param name="replaceXmlNodeName">需要替换掉的字符串</param>
        /// <returns></returns>
        private TOutput DeserializeToEntity<TOutput>(string suorceXml, string subStringXmlNodeName, string replaceXmlNodeName) where TOutput : class
        {
            try
            {
                var begin = suorceXml.IndexOf($"<{subStringXmlNodeName}>", StringComparison.Ordinal);
                var end = suorceXml.IndexOf($"</{subStringXmlNodeName}>", StringComparison.Ordinal) + 24;

                var xml = suorceXml.Substring(begin, suorceXml.Length - begin - (suorceXml.Length - end))
                                   .Replace($"s01:{replaceXmlNodeName} xmlns=\"http://sino.com.cn/\" xmlns:s01=\"http://sino.com.cn\"", replaceXmlNodeName)
                                   .Replace($"s01:{replaceXmlNodeName}", replaceXmlNodeName);

                using (var stringReader = new StringReader(xml))
                {
                    var xmlSerializer = new XmlSerializer(typeof(TOutput));
                    return xmlSerializer.Deserialize(stringReader) as TOutput;
                }
            }
            catch (System.Exception ex)
            {
                _logger.LogError($"XML解析失败:xml-{suorceXml},error-{ex.Message}");
                return default;
            }
        }

        #endregion

    }
    public static class Viod
    {
        public static GetCPWithSlotsForDateList ChangeModel(this GetCPWithSlotsForDateResponse obj)
        {
            return JsonConvert.DeserializeObject<GetCPWithSlotsForDateList>(obj.ToJson());
        }
    }
}
