Beispiel #1
0
        // 填充读者信息的其他字段(第二阶段)
        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());
        }
Beispiel #2
0
 public void ReturnChannel(BaseChannel <T> channel)
 {
     this.Channels.ReturnChannel(channel);
 }
Beispiel #3
0
        // 第二阶段:填充图书信息的 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);
            }
        }
Beispiel #4
0
        // 跟随事件动态更新列表
        // 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);
             * }
             */
        }
Beispiel #5
0
        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);
                            }
                        }
                    }
                }
            }
        }
Beispiel #6
0
        // 筛选出需要 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}");
                    }
                }
            }
        }
Beispiel #7
0
        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();
            }
        }
Beispiel #8
0
        // 筛选出需要 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();
                }
            }
        }
Beispiel #9
0
 public static void ReturnChannel(BaseChannel <IRfid> channel)
 {
     Base.ReturnChannel(channel);
 }