// 填充读者信息的其他字段(第二阶段) async Task <NormalResult> FillPatronDetail(bool force = false) { // 已经填充过了 if (_patron.PatronName != null && force == false) { return(new NormalResult()); } string pii = _patron.PII; if (string.IsNullOrEmpty(pii)) { pii = _patron.UID; } if (string.IsNullOrEmpty(pii)) { return(new NormalResult()); } // return.Value: // -1 出错 // 0 读者记录没有找到 // 1 成功 GetReaderInfoResult result = await Task <GetReaderInfoResult> .Run(() => { return(GetReaderInfo(pii)); }); if (result.Value != 1) { string error = $"读者 '{pii}': {result.ErrorInfo}"; SetPatronError("getreaderinfo", error); return(new NormalResult { Value = -1, ErrorInfo = error }); } SetPatronError("getreaderinfo", ""); if (string.IsNullOrEmpty(_patron.State) == true) { OpenDoor(); } if (force) { _patron.PhotoPath = ""; } // string old_photopath = _patron.PhotoPath; Application.Current.Dispatcher.Invoke(new Action(() => { _patron.SetPatronXml(result.RecPath, result.ReaderXml, result.Timestamp); this.patronControl.SetBorrowed(result.ReaderXml); })); // 显示在借图书列表 List <Entity> entities = new List <Entity>(); foreach (Entity entity in this.patronControl.BorrowedEntities) { entities.Add(entity); } if (entities.Count > 0) { try { BaseChannel <IRfid> channel = RfidManager.GetChannel(); try { await FillBookFields(channel, entities, new CancellationToken()); } finally { RfidManager.ReturnChannel(channel); } } catch (Exception ex) { string error = $"填充读者信息时出现异常: {ex.Message}"; SetGlobalError("rfid", error); return(new NormalResult { Value = -1, ErrorInfo = error }); } } #if NO // 装载图象 if (old_photopath != _patron.PhotoPath) { Task.Run(() => { LoadPhoto(_patron.PhotoPath); }); } #endif return(new NormalResult()); }
public void ReturnChannel(BaseChannel <T> channel) { this.Channels.ReturnChannel(channel); }
// 第二阶段:填充图书信息的 PII 和 Title 字段 async Task FillBookFields(BaseChannel <IRfid> channel, List <Entity> entities, CancellationToken token) { try { foreach (Entity entity in entities) { if (token.IsCancellationRequested) { return; } if (entity.FillFinished == true) { continue; } // 获得 PII // 注:如果 PII 为空,文字中要填入 "(空)" if (string.IsNullOrEmpty(entity.PII)) { if (entity.TagInfo == null) { continue; } Debug.Assert(entity.TagInfo != null); LogicChip chip = LogicChip.From(entity.TagInfo.Bytes, (int)entity.TagInfo.BlockSize, "" // tag.TagInfo.LockStatus ); string pii = chip.FindElement(ElementOID.PII)?.Text; entity.PII = PageBorrow.GetCaption(pii); } // 获得 Title // 注:如果 Title 为空,文字中要填入 "(空)" if (string.IsNullOrEmpty(entity.Title) && string.IsNullOrEmpty(entity.PII) == false && entity.PII != "(空)") { GetEntityDataResult result = await Task <GetEntityDataResult> .Run(() => { return(GetEntityData(entity.PII)); }); if (result.Value == -1) { entity.SetError(result.ErrorInfo); continue; } entity.Title = PageBorrow.GetCaption(result.Title); entity.SetData(result.ItemRecPath, result.ItemXml); } entity.SetError(null); entity.FillFinished = true; } booksControl.SetBorrowable(); } catch (Exception ex) { SetGlobalError("current", ex.Message); } }
// 跟随事件动态更新列表 // Add: 检查列表中是否存在这个 PII,如果存在,则修改状态为 在架,并设置 UID 成员 // 如果不存在,则为列表添加一个新元素,修改状态为在架,并设置 UID 和 PII 成员 // Remove: 检查列表中是否存在这个 PII,如果存在,则修改状态为 不在架 // 如果不存在这个 PII,则不做任何动作 // Update: 检查列表中是否存在这个 PII,如果存在,则修改状态为 在架,并设置 UID 成员 // 如果不存在,则为列表添加一个新元素,修改状态为在架,并设置 UID 和 PII 成员 async Task ChangeEntities(BaseChannel <IRfid> channel, TagChangedEventArgs e) { // 读者。不再精细的进行增删改跟踪操作,而是笼统地看 TagList.Patrons 集合即可 var task = RefreshPatrons(); bool changed = false; List <Entity> update_entities = new List <Entity>(); Application.Current.Dispatcher.Invoke(new Action(() => { if (e.AddBooks != null) { foreach (var tag in e.AddBooks) { var entity = _entities.OnShelf(tag); if (entity != null) { update_entities.Add(entity); } } } if (e.RemoveBooks != null) { foreach (var tag in e.RemoveBooks) { var entity = _entities.OffShelf(tag); if (entity != null) { update_entities.Add(entity); } // changed = true; } } if (e.UpdateBooks != null) { foreach (var tag in e.UpdateBooks) { var entity = _entities.OnShelf(tag); if (entity != null) { update_entities.Add(entity); } } } })); if (update_entities.Count > 0) { // await FillBookFields(channel, update_entities); await Update(channel, update_entities, new CancellationToken()); // Trigger(update_entities); } /* * else if (changed) * { * // 修改 borrowable * booksControl.SetBorrowable(); * }*/ if (update_entities.Count > 0) { changed = true; } /* * { * if (_entities.Count == 0 * && changed == true // 限定为,当数量减少到 0 这一次,才进行清除 * && _patron.IsFingerprintSource) * PatronClear(); * * // 2019/7/1 * // 当读卡器上的图书全部拿走时候,自动关闭残留的模式对话框 * if (_entities.Count == 0 * && changed == true // 限定为,当数量减少到 0 这一次,才进行清除 * ) * CloseDialogs(); * * // 当列表为空的时候,主动清空一次 tag 缓存。这样读者可以用拿走全部标签一次的方法来迫使清除缓存(比如中途利用内务修改过 RFID 标签的 EAS) * // TODO: 不过此举对反复拿放图书的响应速度有一定影响。后面也可以考虑继续改进(比如设立一个专门的清除缓存按钮,这里就不要清除缓存了) * if (_entities.Count == 0 && TagList.TagTableCount > 0) * TagList.ClearTagTable(null); * } */ }
void FillEntity(BaseChannel <IRfid> channel, Entity entity, delegate_speakLocation func_speakLocation) { var info = entity.Tag as ProcessInfo; // 是否强迫获取标签内容 bool force = info.GetTagInfoError == "errorGetTagInfo" || StringUtil.IsInList("verifyEAS", ActionMode); // bool force = info.GetTagInfoError == "errorGetTagInfo"; // testing // 2020/10/7 // 尝试获取 PII if (string.IsNullOrEmpty(entity.PII) || force) { if (InventoryData.UidExsits(entity.UID, out string pii) && force == false) { entity.PII = pii; var set_result = SetTargetCurrentLocation(info); if (set_result.Value == -1 && set_result.ErrorCode == "noCurrentShelfNo") { // 删除这个事项,以便后面可以重新处理 RemoveEntity(entity); } } else { string error = null; if (channel.Started == false) { error = "22 RFID 通道尚未启动"; } else { var get_result = channel.Object.GetTagInfo(entity.ReaderName, entity.UID, Convert.ToUInt32(entity.Antenna), "quick"); /* * // testing * get_result.Value = -1; * get_result.ErrorInfo = "GetTagInfo() error error 1234 error 1345"; */ if (get_result.Value == -1) { SoundMaker.ErrorSound(); // 朗读出错 entity 数量 var count = InventoryData.AddErrorEntity(entity, out bool changed); if (changed == true) { App.CurrentApp.SpeakSequence(count.ToString()); } info.GetTagInfoError = "errorGetTagInfo"; info.ErrorCount++; error = get_result.ErrorInfo; // TODO: 当有一行以上 GetTagInfo() 出错时,要不断发出响声警告。 entity.Error = error; if (info.ErrorCount > 5) { if (func_speakLocation?.Invoke(entity) == true) { info.ErrorCount = 0; } } } else { entity.Error = null; // 把 PII 显示出来 InventoryData.UpdateEntity(entity, get_result.TagInfo, out string type); info.GetTagInfoError = ""; // 层架标 if (type == "location") { info.IsLocation = true; if (string.IsNullOrEmpty(entity.PII) == false) { // 设置当前层架标 SwitchCurrentShelfNo(entity); } } else { var set_result = SetTargetCurrentLocation(info); if (set_result.Value == -1 && set_result.ErrorCode == "noCurrentShelfNo") { // 删除这个事项,以便后面可以重新处理 RemoveEntity(entity); } } // 朗读出错 entity 数量 var count = InventoryData.RemoveErrorEntity(entity, out bool changed); if (changed == true) { App.CurrentApp.SpeakSequence(count.ToString()); } if (StringUtil.IsInList("blankTag", entity.ErrorCode)) { App.CurrentApp.SpeakSequence(entity.Error); } } } } } }
// 筛选出需要 GetTagInfo() 的那些标签 async Task FilterTags(BaseChannel <IRfid> channel, List <TagAndData> tags) { // PII 尚为空的那些 entities List <Entity> empty_piis = new List <Entity>(); // 其他 entities List <Entity> rests = new List <Entity>(); foreach (var tag in tags) { var entity = InventoryData.AddEntity(tag, out bool isNewly); var info = entity.Tag as ProcessInfo; if (info == null) { info = new ProcessInfo(); entity.Tag = info; } if (isNewly) { App.Invoke(new Action(() => { _entities.Add(entity); })); } if (string.IsNullOrEmpty(entity.PII)) { empty_piis.Add(entity); } else { // 对 PII 不为空的,但有任务没有完成的,要加入列表寻求再次被后台处理 rests.Add(entity); /* * if (info.IsLocation == false) * { * InventoryData.AppendList(entity); * InventoryData.ActivateInventory(); * } */ } // 如果发现 PII 不为空的层架标,要用于切换当前 CurrentShelfNo if (info != null && info.IsLocation == true) { SwitchCurrentShelfNo(entity); if (isNewly == false) { App.Invoke(new Action(() => { _entities.MoveToTail(entity); })); } } } // 准备音阶 SoundMaker.InitialSequence(empty_piis.Count); bool speaked = false; // 集中 GetTagInfo() foreach (var entity in empty_piis) { var info = entity.Tag as ProcessInfo; SoundMaker.NextSound(); FillEntity(channel, entity, (e) => { // 说过一次便不再说 if (speaked == true) { return(false); } speaked = SpeakLocation(e); return(speaked); }); // 进入后台队列 if (string.IsNullOrEmpty(entity.PII) == false && info.IsLocation == false) { InventoryData.AppendList(entity); InventoryData.ActivateInventory(); } } // 停止音阶响声 SoundMaker.StopCurrent(); // 其余的也要进入后台队列 foreach (var entity in rests) { var info = entity.Tag as ProcessInfo; if (info.IsLocation == true) { continue; } // 尝试重新赋予目标 location 和 currentLocation,观察参数是否发生变化、重做后台任务 var old_targetLocation = info.TargetLocation; var old_targetShelfNo = info.TargetShelfNo; var old_targetCurrentLocation = info.TargetCurrentLocation; var result = SetTargetCurrentLocation(info); if (result.Value != -1) { if (old_targetLocation != info.TargetLocation || old_targetShelfNo != info.TargetShelfNo || old_targetCurrentLocation != info.TargetCurrentLocation) { // 删除条目,这样可以迫使用新 target 重做后台任务 info.SetTaskInfo("setLocation", null); // 视觉上移动到最末行,让操作者意识到发生了重做后台任务 App.Invoke(new Action(() => { _entities.MoveToTail(entity); })); } } if (string.IsNullOrEmpty(entity.PII) == false && info.IsLocation == false) { InventoryData.AppendList(entity); InventoryData.ActivateInventory(); } } // 2020/11/9 // 执行修改 EAS 任务 foreach (var entity in rests) { var info = entity.Tag as ProcessInfo; // 如果有以前尚未执行成功的修改 EAS 的任务,则尝试再执行一次 if (info != null && info.TargetEas != null && info.ContainTask("changeEAS") == true && info.IsTaskCompleted("changeEAS") == false) { try { if (info.TargetEas == "?") { await InventoryData.VerifyEasAsync(entity); } else { // TODO: 记载轮空和出错的次数。 // result.Value // -1 出错 // 0 标签不在读卡器上所有没有执行 // 1 成功执行修改 await InventoryData.TryChangeEasAsync(entity, info.TargetEas == "on"); } } catch (Exception ex) { WpfClientInfo.WriteErrorLog($"FilterTags() 出现异常: {ExceptionUtil.GetDebugText(ex)}"); App.SetError("processing", $"FilterTags() 出现异常: {ex.Message}"); } } } }
void FillEntity(BaseChannel <IRfid> channel, Entity entity, delegate_speakLocation func_speakLocation) { var info = entity.Tag as ProcessInfo; // 2020/10/7 // 尝试获取 PII if (string.IsNullOrEmpty(entity.PII)) { if (InventoryData.UidExsits(entity.UID, out string pii)) { entity.PII = pii; } else { string error = null; if (channel.Started == false) { error = "RFID 通道尚未启动"; } else { var get_result = channel.Object.GetTagInfo(entity.ReaderName, entity.UID, Convert.ToUInt32(entity.Antenna), "quick"); /* * // testing * get_result.Value = -1; * get_result.ErrorInfo = "GetTagInfo() error error 1234 error 1345"; */ if (get_result.Value == -1) { SoundMaker.ErrorSound(); // 朗读出错 entity 数量 var count = InventoryData.AddErrorEntity(entity, out bool changed); if (changed == true) { App.CurrentApp.SpeakSequence(count.ToString()); } info.State = "errorGetTagInfo"; info.ErrorCount++; error = get_result.ErrorInfo; // TODO: 当有一行以上 GetTagInfo() 出错时,要不断发出响声警告。 entity.Error = error; if (info.ErrorCount > 5) { if (func_speakLocation?.Invoke(entity) == true) { info.ErrorCount = 0; } } } else { entity.Error = null; // 把 PII 显示出来 InventoryData.UpdateEntity(entity, get_result.TagInfo); info.State = ""; // 朗读出错 entity 数量 var count = InventoryData.RemoveErrorEntity(entity, out bool changed); if (changed == true) { App.CurrentApp.SpeakSequence(count.ToString()); } if (StringUtil.IsInList("blankTag", entity.ErrorCode)) { App.CurrentApp.SpeakSequence(entity.Error); } } } } } if (string.IsNullOrEmpty(entity.PII) == false && string.IsNullOrEmpty(info.State)) { info.State = "processing"; // 正在获取册信息 InventoryData.AppendList(entity); InventoryData.ActivateInventory(); } }
// 筛选出需要 GetTagInfo() 的那些标签 void FilterTags(BaseChannel <IRfid> channel, List <TagAndData> tags) { List <Entity> entities1 = new List <Entity>(); List <Entity> all = new List <Entity>(); foreach (var tag in tags) { var entity = InventoryData.AddEntity(tag, out bool isNewly); var info = entity.Tag as ProcessInfo; if (info == null) { info = new ProcessInfo(); entity.Tag = info; } if (isNewly) { App.Invoke(new Action(() => { _entities.Add(entity); })); } if (string.IsNullOrEmpty(entity.PII)) { entities1.Add(entity); } all.Add(entity); } // 准备音阶 SoundMaker.InitialSequence(entities1.Count); bool speaked = false; // 集中 GetTagInfo() foreach (var entity in entities1) { SoundMaker.NextSound(); FillEntity(channel, entity, (e) => { // 说过一次便不再说 if (speaked == true) { return(false); } speaked = SpeakLocation(e); return(speaked); }); } // 停止音阶响声 SoundMaker.StopCurrent(); // 获取题名等 foreach (var entity in all) { var info = entity.Tag as ProcessInfo; if (string.IsNullOrEmpty(entity.PII) == false && string.IsNullOrEmpty(info.State)) { info.State = "processing"; // 正在获取册信息 InventoryData.AppendList(entity); InventoryData.ActivateInventory(); } } }
public static void ReturnChannel(BaseChannel <IRfid> channel) { Base.ReturnChannel(channel); }