From fa3fe4ce3737d2d864681f0a3f98eff464271c8e Mon Sep 17 00:00:00 2001 From: xietao Date: Wed, 3 Jan 2024 22:43:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=81=E7=BB=AD=E6=94=B9=E8=BF=9B=20dp2ssl?= =?UTF-8?q?=20=E4=BA=BA=E8=84=B8=E8=AF=86=E5=88=AB=E5=91=BD=E4=B8=AD?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E8=AF=BB=E8=80=85=E8=AE=B0=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dp2SSL/App.xaml.cs | 15 +- dp2SSL/Controls/PatronControl.xaml | 6 +- dp2SSL/Dialog/AttackManager.cs | 104 ++++++++++++ dp2SSL/Dialog/ProgressWindow.xaml | 4 +- dp2SSL/Dialog/ProgressWindow.xaml.cs | 20 +++ dp2SSL/Dialog/SelectPatronWindow.xaml.cs | 71 ++++++++- dp2SSL/Page/PageBorrow.xaml.cs | 192 +++++++++++++++-------- dp2SSL/Page/PageError.xaml | 5 + dp2SSL/Page/PageSetting.xaml | 7 +- dp2SSL/Page/PageShelf.xaml | 39 +++-- dp2SSL/Page/PageShelf.xaml.cs | 102 ++++++++++-- dp2SSL/Properties/AssemblyInfo.cs | 7 +- dp2SSL/Resources/Patron.Dark.xaml | 6 +- dp2SSL/Resources/Patron.Light.xaml | 2 +- dp2SSL/design.txt | 3 +- dp2SSL/dp2SSL.csproj | 11 +- 16 files changed, 485 insertions(+), 109 deletions(-) create mode 100644 dp2SSL/Dialog/AttackManager.cs diff --git a/dp2SSL/App.xaml.cs b/dp2SSL/App.xaml.cs index aea4a64f2..cc75c3275 100644 --- a/dp2SSL/App.xaml.cs +++ b/dp2SSL/App.xaml.cs @@ -2636,8 +2636,8 @@ public static void Invoke(Action action) public static void ErrorBox( string title, string message, - string color = "red", - string style = "") + string color = "red", + string style = "") { ProgressWindow progress = null; @@ -2659,9 +2659,16 @@ public static void ErrorBox( progress.Show(); })); + // auto_close:xxx 其中 xxx 为延时秒数。:xxx 缺省为 3 秒 + var delay_seconds_string = StringUtil.GetParameterByPrefix(style, "auto_close"); - if (StringUtil.IsInList("auto_close", style)) + if (/*StringUtil.IsInList("auto_close", style)*/ + delay_seconds_string != null) { + int delay_seconds = 3; + if (string.IsNullOrEmpty(delay_seconds_string) == false) + Int32.TryParse(delay_seconds_string, out delay_seconds); + App.Invoke(new Action(() => { progress.MessageText = message; @@ -2674,7 +2681,7 @@ public static void ErrorBox( try { // TODO: 显示倒计时计数? - await Task.Delay(TimeSpan.FromSeconds(1)); + await Task.Delay(TimeSpan.FromSeconds(delay_seconds)); App.Invoke(new Action(() => { progress.Close(); diff --git a/dp2SSL/Controls/PatronControl.xaml b/dp2SSL/Controls/PatronControl.xaml index b6a17c5a7..6d95b1340 100644 --- a/dp2SSL/Controls/PatronControl.xaml +++ b/dp2SSL/Controls/PatronControl.xaml @@ -108,11 +108,11 @@ + Margin="0,4,6,0" FontSize="24" FontWeight="Thin" TextAlignment="Right"/> + Margin="0,4,6,0" FontSize="24" FontWeight="Thin"/> - + LimitCount) + Clean(CleanLength); + + lock (_table.SyncRoot) + { + var entry = _table[title] as AttackEntry; + if (entry == null) + { + // 如果依然超过了限制条目数,只好不再增加新条目 + if (_table.Count > LimitCount) + return; + + entry = new AttackEntry + { + Title = title, + LastTime = DateTime.Now, + Count = 1 + }; + _table[title] = entry; + } + else + { + entry.Count++; + entry.LastTime = DateTime.Now; + } + } + } + + // 检索,查看指定的 title 是否已经存在对应的条目 + public NormalResult Search(string title) + { + lock (_table.SyncRoot) + { + var entry = _table[title] as AttackEntry; + if (entry == null) + return new NormalResult(); + if (entry.Count < AttackCount) + return new NormalResult(); + return new NormalResult { Value = 1 }; + } + } + + // 清理超过一定时间的条目 + public void Clean(TimeSpan length) + { + lock (_table.SyncRoot) + { + List delete_keys = new List(); + DateTime now = DateTime.Now; + foreach (string key in _table.Keys) + { + var entry = _table[key] as AttackEntry; + if (now - entry.LastTime > length) + delete_keys.Add(key); + } + + foreach (string key in delete_keys) + { + // TODO: 可以考虑把条目删除前记载到日志文件 + _table.Remove(key); + } + } + } + } + + class AttackEntry + { + public string Title { get; set; } + + // 最后一次攻击的时间 + public DateTime LastTime { get; set; } + + // 攻击次数 + public long Count { get; set; } + } +} diff --git a/dp2SSL/Dialog/ProgressWindow.xaml b/dp2SSL/Dialog/ProgressWindow.xaml index a57181137..32143a1f7 100644 --- a/dp2SSL/Dialog/ProgressWindow.xaml +++ b/dp2SSL/Dialog/ProgressWindow.xaml @@ -14,7 +14,9 @@ - + diff --git a/dp2SSL/Dialog/ProgressWindow.xaml.cs b/dp2SSL/Dialog/ProgressWindow.xaml.cs index f4558c097..310c5ca9a 100644 --- a/dp2SSL/Dialog/ProgressWindow.xaml.cs +++ b/dp2SSL/Dialog/ProgressWindow.xaml.cs @@ -24,6 +24,10 @@ public partial class ProgressWindow : Window public ProgressWindow() { InitializeComponent(); + + this.Loaded += (s, o) => { + this.mainGrid.Focus(); + }; } private void OkButton_Click(object sender, RoutedEventArgs e) @@ -206,5 +210,21 @@ private void cancelButton_Click(object sender, RoutedEventArgs e) this.Close(); } + + private void Grid_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter + || e.Key == Key.Space) + { + OkButton_Click(this, new RoutedEventArgs()); + return; + } + + if (e.Key == Key.Escape) + { + cancelButton_Click(this, new RoutedEventArgs()); + return; + } + } } } diff --git a/dp2SSL/Dialog/SelectPatronWindow.xaml.cs b/dp2SSL/Dialog/SelectPatronWindow.xaml.cs index cb5003029..044a464ac 100644 --- a/dp2SSL/Dialog/SelectPatronWindow.xaml.cs +++ b/dp2SSL/Dialog/SelectPatronWindow.xaml.cs @@ -12,12 +12,10 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; -// using System.Windows.Shapes; using System.Diagnostics; using System.Xml; using System.IO; -// using Xceed.Wpf.Toolkit; using WindowsInput; using static dp2SSL.LibraryChannelUtil; @@ -74,7 +72,13 @@ void OnEnter() string text = this.password.Password; if (text.Length < 4) { - MessageBox.Show(this, "输入的密码长度必须大于等于 4 字符"); + // MessageBox.Show(this, "输入的密码长度必须大于等于 4 字符"); + App.CurrentApp.Speak($"密码筛选失败"); + App.ErrorBox( + "密码筛选", + "输入的密码长度必须大于等于 4 字符", + "red", + "auto_close:5"); return; } var result = SelectPatronByPassword(text); @@ -83,7 +87,13 @@ void OnEnter() selectButton_Click(this, new RoutedEventArgs()); return; } - MessageBox.Show(this, result.ErrorInfo); + // MessageBox.Show(this, result.ErrorInfo); + App.CurrentApp.Speak($"密码筛选失败"); + App.ErrorBox( +"密码筛选", +result.ErrorInfo, +"red", +"auto_close:5"); return; } @@ -104,6 +114,9 @@ private void SelectPatronWindow_Loaded(object sender, RoutedEventArgs e) _ = Task.Factory.StartNew(async () => { + // 清理以前较旧的攻击条目 + attackManager.Clean(attackManager.CleanLength); + using (CancellationTokenSource cancel = CancellationTokenSource.CreateLinkedTokenSource(_cancel.Token, App.CancelToken)) { var result = await FillPatronCollectionDetailAsync( @@ -346,6 +359,12 @@ NormalResult SelectPatronByPassword(string password) this.passwordArea.IsEnabled = true; } + if (HasAttacked() == true) + return new NormalResult + { + Value = -1, + ErrorInfo = "因失败次数太多,相关人脸信息已经进入保护状态,请稍后再重试操作 ..." + }; try { // this.listView.SelectedItem = null; @@ -382,11 +401,14 @@ NormalResult SelectPatronByPassword(string password) } if (hits.Count == 0) + { + MemoryAttack(); return new NormalResult { Value = 0, ErrorInfo = "没有匹配的读者" }; + } if (hits.Count == 1) { @@ -395,6 +417,7 @@ NormalResult SelectPatronByPassword(string password) } Debug.Assert(hits.Count > 1); + MemoryAttack(); return new NormalResult { Value = hits.Count, @@ -598,6 +621,46 @@ void OnVisibleChanged() this.mainGrid.ColumnDefinitions[1].Width = new GridLength(330); } } + + static AttackManager attackManager = new AttackManager(); + + void MemoryAttack() + { + foreach (var patron in _patrons) + { + attackManager.Increase(patron.PII); + } + } + + // 检测是否因为以前攻击而处在监控期间 + public static bool HasAttacked(List barcode_list) + { + foreach (var barcode in barcode_list) + { + var result = attackManager.Search(barcode); + if (result.Value == 1) + return true; + } + + return false; + } + + bool HasAttacked() + { + List barcodes = new List(); + foreach(var patron in _patrons) + { + barcodes.Add(patron.PII); + } + + return HasAttacked(barcodes); + } + + public static void CleanAttackManager() + { + // 清理以前较旧的攻击条目 + attackManager.Clean(attackManager.CleanLength); + } } public class PatronCollection : ObservableCollection diff --git a/dp2SSL/Page/PageBorrow.xaml.cs b/dp2SSL/Page/PageBorrow.xaml.cs index fe28c10c5..06975e5f1 100644 --- a/dp2SSL/Page/PageBorrow.xaml.cs +++ b/dp2SSL/Page/PageBorrow.xaml.cs @@ -140,12 +140,12 @@ private async void PatronControl_InputFace(object sender, EventArgs e) if (result.Value == -1) { if (result.ErrorCode != "cancelled") - SetGlobalError("face", result.ErrorInfo); + SetGlobalError("faceInput", result.ErrorInfo); DisplayError(ref videoRecognition, result.ErrorInfo); return; } - SetGlobalError("face", null); + SetGlobalError("faceInput", null); } finally { @@ -176,41 +176,68 @@ private async void PatronControl_InputFace(object sender, EventArgs e) && result.Hits.Length > 1) { var barcodes = result.Hits.OrderByDescending(o => o.Score).Select(o => o.Patron).ToList(); - - List names = new List(); - if (App.FaceInputMultipleHits.Contains("列表选择")) - names.Add("从列表中选择"); - if (App.FaceInputMultipleHits.Contains("密码筛选")) - names.Add("输入密码筛选"); - - string title = $"人脸识别命中 {barcodes.Count} 个读者,请{StringUtil.MakePathList(names, " 或 ")} ..."; - - var select_result = SelectOnePatron( - title, - barcodes); - if (select_result.Value != 1) + + SelectPatronWindow.CleanAttackManager(); + if (SelectPatronWindow.HasAttacked(barcodes) == true) + { + App.CurrentApp.Speak($"人脸信息被保护 ..."); + result = new RecognitionFaceResult { Value = -1, - ErrorInfo = select_result.ErrorInfo, - ErrorCode = select_result.ErrorCode, + ErrorInfo = "为防范密码攻击,您的人脸信息处于被保护状态,请稍后再重试 ..." }; + } else - result = new RecognitionFaceResult - { - Value = 1, - Score = result.Hits - .Where(o => o.Patron == select_result.strBarcode) - .Select(o => o.Score) - .FirstOrDefault(), - Patron = select_result.strBarcode - }; + { + App.CurrentApp.Speak($"人脸识别命中 {result.Hits.Length} 个读者,请选择 ..."); + + List names = new List(); + if (App.FaceInputMultipleHits.Contains("列表选择")) + names.Add("从列表中选择"); + if (App.FaceInputMultipleHits.Contains("密码筛选")) + names.Add("输入密码筛选"); + + string title = $"人脸识别命中 {barcodes.Count} 个读者,请{StringUtil.MakePathList(names, " 或 ")} ..."; + + var select_result = SelectOnePatron( + this, + title, + barcodes); + if (select_result.Value != 1) + result = new RecognitionFaceResult + { + Value = -1, + ErrorInfo = select_result.ErrorInfo, + ErrorCode = select_result.ErrorCode, + }; + else + result = new RecognitionFaceResult + { + Value = 1, + Score = result.Hits + .Where(o => o.Patron == select_result.strBarcode) + .Select(o => o.Score) + .FirstOrDefault(), + Patron = select_result.strBarcode + }; + } } if (result.Value == -1) { if (result.ErrorCode != "cancelled") - SetGlobalError("face", result.ErrorInfo); + { + // SetGlobalError("faceInput", result.ErrorInfo); + _ = Task.Run(() => + { + App.ErrorBox( + "人脸识别", + result.ErrorInfo, + "red", + "auto_close:10"); + }); + } return; } @@ -225,13 +252,15 @@ private async void PatronControl_InputFace(object sender, EventArgs e) Welcome(fill_result.Value == -1); } - internal class SelectOnePatronResult : NormalResult + public class SelectOnePatronResult : NormalResult { public string strBarcode { get; set; } public string strResult { get; set; } } - SelectOnePatronResult SelectOnePatron(string dialog_title, + public static SelectOnePatronResult SelectOnePatron( + MyPage owner, + string dialog_title, IEnumerable barcode_list) { string dialog_result = ""; @@ -244,11 +273,11 @@ SelectOnePatronResult SelectOnePatron(string dialog_title, var ask = new SelectPatronWindow(); ask.Closed += (s1, e1) => { - RemoveLayer(); + owner.RemoveLayer(); }; - AddLayer(); // Closed 事件会 RemoveLayer() + owner.AddLayer(); // Closed 事件会 RemoveLayer() - this.MemoryDialog(ask); + owner.MemoryDialog(ask); PatronCollection patrons = new PatronCollection(); foreach (var barcode in barcode_list) @@ -293,7 +322,7 @@ SelectOnePatronResult SelectOnePatron(string dialog_title, //ask.CancelButtonVisible = true; ask.ShowDialog(); - this.ForgetDialog(ask); + owner.ForgetDialog(ask); dialog_result = ask.PressedButton; selected_patron = ask.SelectedPatron; @@ -1707,9 +1736,18 @@ void GetPatronFromFingerprint() } } #endif - // 填充读者信息的其他字段(第二阶段) async Task FillPatronDetailAsync(bool force = false) { + return await Task.Run(async () => + { + return await _fillPatronDetailAsync(force); + }); + } + + + // 填充读者信息的其他字段(第二阶段) + async Task _fillPatronDetailAsync(bool force = false) + { #if NO if (_cancelRefresh == null || _cancelRefresh.IsCancellationRequested) @@ -1762,6 +1800,8 @@ async Task FillPatronDetailAsync(bool force = false) result = await SipChannelUtil.GetReaderInfoAsync(oi, pii); } else + { +#if REMOVED result = await Task.Run(() => { @@ -1773,6 +1813,15 @@ async Task FillPatronDetailAsync(bool force = false) string oi_pii = _patron.GetOiPii(strict); // 严格模式,必须有 OI return LibraryChannelUtil.GetReaderInfo(string.IsNullOrEmpty(oi_pii) ? pii : oi_pii); }); +#endif + // 2021/4/2 改为用 oi+pii + bool strict = !_patron.IsFingerprintSource; + // 2021/4/15 + if (ChargingData.GetBookInstitutionStrict() == false) + strict = false; + string oi_pii = _patron.GetOiPii(strict); // 严格模式,必须有 OI + result = LibraryChannelUtil.GetReaderInfo(string.IsNullOrEmpty(oi_pii) ? pii : oi_pii); + } if (result.Value != 1) { @@ -1785,33 +1834,56 @@ async Task FillPatronDetailAsync(bool force = false) if (force) _patron.PhotoPath = ""; - // string old_photopath = _patron.PhotoPath; - App.Invoke(new Action(() => + //App.Invoke(new Action(() => + //{ + try { - try + _patron.MaskDefinition = ShelfData.GetPatronMask(); + _patron.SetPatronXml(result.RecPath, result.ReaderXml, result.Timestamp); + + App.Invoke(() => { - _patron.MaskDefinition = ShelfData.GetPatronMask(); - _patron.SetPatronXml(result.RecPath, result.ReaderXml, result.Timestamp); this.patronControl.SetBorrowed(result.ReaderXml); + }); - // 2024/1/2 - _patron.BorrowItemsVisible = _patron.BorrowingCount > 0; - } - catch (Exception ex) - { - // 2021/8/31 - _patron.SetError(ex.Message); - WpfClientInfo.WriteErrorLog($"SetBorrowed() 出现异常: {ExceptionUtil.GetDebugText(ex)}"); - SetGlobalError("patron", $"SetBorrowed() 出现异常: {ex.Message}"); - } - })); + // 2024/1/2 + _patron.BorrowItemsVisible = _patron.BorrowingCount > 0; + } + catch (Exception ex) + { + // 2021/8/31 + _patron.SetError(ex.Message); + WpfClientInfo.WriteErrorLog($"SetBorrowed() 出现异常: {ExceptionUtil.GetDebugText(ex)}"); + SetGlobalError("patron", $"SetBorrowed() 出现异常: {ex.Message}"); + } + //})); - // 显示在借图书列表 +#if NO + // 装载图象 + if (old_photopath != _patron.PhotoPath) + { + Task.Run(()=> { + LoadPhoto(_patron.PhotoPath); + }); + } +#endif + } + finally + { + _patron.Waiting = false; + } + + // 显示在借图书列表 + // 此时 _patron 控件的等待动画已经结束 + { + /* List entities = new List(); foreach (Entity entity in this.patronControl.BorrowedEntities) { entities.Add(entity); } + */ + var entities = this.patronControl.BorrowedEntities.ToList(); if (entities.Count > 0) { try @@ -1837,21 +1909,9 @@ await FillBookFieldsAsync( return new NormalResult { Value = -1, ErrorInfo = error }; } } -#if NO - // 装载图象 - if (old_photopath != _patron.PhotoPath) - { - Task.Run(()=> { - LoadPhoto(_patron.PhotoPath); - }); - } -#endif - return new NormalResult(); - } - finally - { - _patron.Waiting = false; } + + return new NormalResult(); } #if NO @@ -4352,7 +4412,7 @@ public static int UploadFile( } #endif -#endregion + #endregion #if OLDVERSION diff --git a/dp2SSL/Page/PageError.xaml b/dp2SSL/Page/PageError.xaml index 13fd93f14..53b701da5 100644 --- a/dp2SSL/Page/PageError.xaml +++ b/dp2SSL/Page/PageError.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:dp2SSL" xmlns:fa="http://schemas.fontawesome.io/icons/" + xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Title="PageError"> @@ -29,8 +30,12 @@ --> - + - + @@ -32,22 +33,38 @@ - - - - + + diff --git a/dp2SSL/Page/PageShelf.xaml.cs b/dp2SSL/Page/PageShelf.xaml.cs index a43cd58b5..ca5afd8d3 100644 --- a/dp2SSL/Page/PageShelf.xaml.cs +++ b/dp2SSL/Page/PageShelf.xaml.cs @@ -546,7 +546,7 @@ await Task.Run(async () => RfidManager.ClearCache(); // 注:将来也许可以通过(RFID 以外的)其他方式输入图书号码 if (string.IsNullOrEmpty(RfidManager.Url)) - this.SetGlobalError("rfid", "尚未配置 RFID 中心 URL"); + SetGlobalError("rfid", "尚未配置 RFID 中心 URL"); await InitialShelfEntitiesAsync(App.StartNetworkMode, IsSilently() || IsFileSilently()); @@ -560,14 +560,14 @@ await InitialShelfEntitiesAsync(App.StartNetworkMode, } catch (Exception ex) { - this.SetGlobalError("initial", $"InitialShelfEntitiesAsync() 出现异常: {ex.Message}"); + SetGlobalError("initial", $"InitialShelfEntitiesAsync() 出现异常: {ex.Message}"); WpfClientInfo.WriteErrorLog($"InitialShelfEntitiesAsync() 出现异常: {ExceptionUtil.GetDebugText(ex)}"); } }); } catch (Exception ex) { - this.SetGlobalError("initial", $"InitialShelfEntities() 出现异常: {ex.Message}"); + SetGlobalError("initial", $"InitialShelfEntities() 出现异常: {ex.Message}"); WpfClientInfo.WriteErrorLog($"InitialShelfEntities() 出现异常: {ExceptionUtil.GetDebugText(ex)}"); } } @@ -1751,7 +1751,7 @@ async Task Update( #endif // 设置全局区域错误字符串 - void SetGlobalError(string type, string error) + static void SetGlobalError(string type, string error) { /* if (error != null && error.StartsWith("未")) @@ -3381,12 +3381,25 @@ static string GetNowString() public delegate void Delegate_welcome(); + async Task FillPatronDetailAsync( + Delegate_welcome func_welcome, + bool force = false) + { + return await Task.Run(async () => + { + return await _fillPatronDetailAsync( + func_welcome, + force); + }); + } + + // TODO: 参考 PageBorrow 中 FillPatronDetailAsync() 函数,更大范围使用独立线程,以加快响应敏捷性 // 填充读者信息的其他字段(第二阶段) // resut.Value // -1 出错 // 0 没有填充 // 1 成功填充 - async Task FillPatronDetailAsync( + async Task _fillPatronDetailAsync( Delegate_welcome func_welcome, bool force = false) { @@ -4870,16 +4883,16 @@ private async void PatronControl_InputFace(object sender, EventArgs e) }); try { - result = await RecognitionFaceAsync(""); + result = await RecognitionFaceAsync(App.FaceInputMultipleHits == "使用第一个" ? "" : "multiple_hits"); if (result.Value == -1) { if (result.ErrorCode != "cancelled") - SetGlobalError("face", result.ErrorInfo); + SetGlobalError("faceInput", result.ErrorInfo); DisplayError(ref _videoRecognition, result.ErrorInfo); return; } - SetGlobalError("face", null); + SetGlobalError("faceInput", null); } finally { @@ -4890,6 +4903,77 @@ private async void PatronControl_InputFace(object sender, EventArgs e) })); } + // 命中多个的选择 + if (App.FaceInputMultipleHits != "使用第一个" + && result.Hits != null + && result.Hits.Length > 1) + { + var barcodes = result.Hits.OrderByDescending(o => o.Score).Select(o => o.Patron).ToList(); + + SelectPatronWindow.CleanAttackManager(); + if (SelectPatronWindow.HasAttacked(barcodes) == true) + { + App.CurrentApp.Speak($"人脸信息被保护 ..."); + + result = new RecognitionFaceResult + { + Value = -1, + ErrorInfo = "为防范密码攻击,您的人脸信息处于被保护状态,请稍后再重试 ..." + }; + } + else + { + App.CurrentApp.Speak($"人脸识别命中 {result.Hits.Length} 个读者,请选择 ..."); + + List names = new List(); + if (App.FaceInputMultipleHits.Contains("列表选择")) + names.Add("从列表中选择"); + if (App.FaceInputMultipleHits.Contains("密码筛选")) + names.Add("输入密码筛选"); + + string title = $"人脸识别命中 {barcodes.Count} 个读者,请{StringUtil.MakePathList(names, " 或 ")} ..."; + + var select_result = PageBorrow.SelectOnePatron( + this, + title, + barcodes); + if (select_result.Value != 1) + result = new RecognitionFaceResult + { + Value = -1, + ErrorInfo = select_result.ErrorInfo, + ErrorCode = select_result.ErrorCode, + }; + else + result = new RecognitionFaceResult + { + Value = 1, + Score = result.Hits + .Where(o => o.Patron == select_result.strBarcode) + .Select(o => o.Score) + .FirstOrDefault(), + Patron = select_result.strBarcode + }; + } + } + + if (result.Value == -1) + { + if (result.ErrorCode != "cancelled") + { + // SetGlobalError("faceInput", result.ErrorInfo); + _ = Task.Run(() => + { + App.ErrorBox( + "人脸识别", + result.ErrorInfo, + "red", + "auto_close:10"); + }); + } + return; + } + GetMessageResult message = new GetMessageResult { Value = 1, @@ -5095,7 +5179,7 @@ async Task RecognitionFaceAsync(string style) ErrorInfo = result.ErrorInfo, ErrorCode = result.ErrorCode }; - return FaceManager.RecognitionFace(""); + return FaceManager.RecognitionFace(style); }); } finally diff --git a/dp2SSL/Properties/AssemblyInfo.cs b/dp2SSL/Properties/AssemblyInfo.cs index 5f9251302..6f4814ce1 100644 --- a/dp2SSL/Properties/AssemblyInfo.cs +++ b/dp2SSL/Properties/AssemblyInfo.cs @@ -51,8 +51,8 @@ // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.9.9")] // 1.5.* -[assembly: AssemblyFileVersion("1.9.9.0")] // 1.5.0.0 +[assembly: AssemblyVersion("1.9.10")] // 1.5.* +[assembly: AssemblyFileVersion("1.9.10.0")] // 1.5.0.0 // 1.0 2019/2/21 第一个版本 // 1.1 2019/2/26 可以显示版本号了 @@ -175,3 +175,6 @@ // 超高频国标格式标签“不存在 PII” bug 已经修正 // 1.9.6 (2023/12/28) 图书显示区域和读者信息显示区域支持触摸屏手指卷动内容 // 1.9.7 (2024/1/2) 人脸识别增加命中多个记录的功能 +// 1.9.8 (2024/1/3) 人脸识别命中多个,输入密码过滤的时候,遇到密码攻击,增加了保护机制。对 PageBorrow 和 PageShelf 两处都做到了 +// PageShelf 界面整理。右侧读者信息显示区的卷滚条正确显示了,区域内可以用手指触摸卷动 +// PageBorrow 和 PageShelf 两个页面中的读者信息区填充处理过程以单独的线程实现,增加了敏捷度 diff --git a/dp2SSL/Resources/Patron.Dark.xaml b/dp2SSL/Resources/Patron.Dark.xaml index 4ff90548a..56d5eb75c 100644 --- a/dp2SSL/Resources/Patron.Dark.xaml +++ b/dp2SSL/Resources/Patron.Dark.xaml @@ -11,12 +11,12 @@ - + - + - + \ No newline at end of file diff --git a/dp2SSL/Resources/Patron.Light.xaml b/dp2SSL/Resources/Patron.Light.xaml index 22b85661f..3e5db1942 100644 --- a/dp2SSL/Resources/Patron.Light.xaml +++ b/dp2SSL/Resources/Patron.Light.xaml @@ -10,7 +10,7 @@ - + diff --git a/dp2SSL/design.txt b/dp2SSL/design.txt index 9f9eebb43..377a8e310 100644 --- a/dp2SSL/design.txt +++ b/dp2SSL/design.txt @@ -45,5 +45,6 @@ https://stackoverflow.com/questions/37283340/how-can-i-combine-touch-and-mouse-e https://stackoverflow.com/questions/37285335/why-my-mouse-event-handlers-are-not-working-when-i-have-touch-event-handlers - +https://www.cnblogs.com/ListenFly/p/3581735.html +WPF之无法触发KeyDown或者KeyUp键盘事件 diff --git a/dp2SSL/dp2SSL.csproj b/dp2SSL/dp2SSL.csproj index 64b0dbc00..79af89c12 100644 --- a/dp2SSL/dp2SSL.csproj +++ b/dp2SSL/dp2SSL.csproj @@ -36,7 +36,7 @@ dp2 V3 true publish.htm - 48 + 50 1.8.63.%2a false true @@ -566,6 +566,7 @@ + SelectPatronWindow.xaml @@ -1047,22 +1048,22 @@ False + DataFile + True - DataFile - True File False + DataFile + True - DataFile - True File