From 1a1c8e71fcd14858f595029f089b2d4a00202b32 Mon Sep 17 00:00:00 2001
From: ogi <Administrator@S-OGI-PC>
Date: Fri, 05 Dec 2025 09:24:16 +0900
Subject: [PATCH] プロジェクトファイルを追加。

---
 HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs |  599 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 599 insertions(+), 0 deletions(-)

diff --git a/HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs b/HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs
new file mode 100644
index 0000000..5a00719
--- /dev/null
+++ b/HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs
@@ -0,0 +1,599 @@
+using Grpc.Core;
+using HotelPms.Client.Blazor.Dialog;
+using HotelPms.Client.Blazor.Models;
+using HotelPms.Client.Blazor.Util;
+using HotelPms.Data.Common;
+using HotelPms.Share.IO;
+using HotelPms.Share.Util;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Web;
+using MudBlazor;
+using System.Data;
+using static HotelPms.Client.Blazor.Util.SystemEnum;
+using static System.Net.Mime.MediaTypeNames;
+
+namespace HotelPms.Client.Blazor.Pages.UseDetail;
+
+public partial class RoomTypeInput : ComponentBase
+{
+    #region ★★★★★ Parameter ★★★★★
+
+    [Parameter] public ViewModel.UseInput? Data { get; set; }
+
+    /// <summary>
+    /// 親Pageの再表示
+    /// </summary>
+    [Parameter] public Action OnRefresh { get; set; }
+
+    #endregion 
+
+    #region ★★★★★ Declare ★★★★★ 
+    /// <summary>
+    /// 异步锁
+    ///     ■ロック追加前
+    ///     Leave⇒Start
+    ///     Leave⇒Row:1 Col:0 enterPush:False, orgText:, text:1
+    ///     【10:07:06 046】SendAsync begin:10:07:06 046
+    ///     【10:07:06 047】SendAsync Url⇒/HotelPms.Data.GrpcTableCore/GetData
+    ///     Enter⇒Row:0 Col:0 Text:1
+    ///     【10:07:06 095】SendAsync End:10:07:06 095
+    ///     該当部屋タイプが既に存在します。
+    ///     Leave⇒End
+    ///     
+    ///     ■追加後
+    ///     Leave⇒Start
+    ///     Leave⇒Row:1 Col:0 enterPush:False, text:1
+    ///     【10:26:02 811】SendAsync begin:10:26:02 811
+    ///     【10:26:02 811】SendAsync Url⇒/HotelPms.Data.GrpcTableCore/GetData
+    ///     【10:26:02 860】SendAsync End:10:26:02 860
+    ///     該当部屋タイプが既に存在します。
+    ///     Leave⇒End
+    ///     Enter⇒Row:0 Col:0
+    ///     
+    ///     Semaphore(int initialCount, int maximumCount);
+    ///     initialCount代表还分配几个线程,比如是1,那就是还能允许一个线程继续跑锁起来的代码
+    ///     maximumCount代表最大允许数, 比如是1, 那就是进去1个线程, 就会锁起来
+    /// </summary>
+    private System.Threading.SemaphoreSlim slimlock = new SemaphoreSlim(1, 1);
+
+    private int selRow = 0;
+    private int selectedRowNumber = -1;
+    private MudTable<RoomTypeInputRow> mudRoomTypeInputTable;
+
+    private bool keyDownPreventDefault = false;
+    private bool keyPressPreventDefault = false;
+    private bool enterPush = false;
+    private bool arrowUpPush = false;
+
+    private EditGridFocusEventArgs m_CurrentFocusData = new EditGridFocusEventArgs();
+
+    #endregion
+
+    #region ★★★★★ Property ★★★★★ 
+
+    private RoomTypeInputRow m_SelRoomTypeInputRow = null;
+
+    /// <summary>
+    /// 選択されている行
+    /// </summary>
+    public RoomTypeInputRow SelRoomTypeInputRow
+    {
+        get { return m_SelRoomTypeInputRow; }
+        set
+        {
+            m_SelRoomTypeInputRow = value;
+            EnvironmentSetting.Debug($"Change:{m_SelRoomTypeInputRow.ID}");
+        }
+    }
+
+    #endregion
+
+    #region  ★★★★★ Class Event ★★★★★
+
+    protected override void OnInitialized()
+    {
+        //EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】RoomTypeInput.OnInitialized開始:");
+        base.OnInitialized();
+    }
+
+    protected override void OnAfterRender(bool firstRender)
+    {
+        //EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】RoomTypeInput.OnAfterRender開始:{firstRender}");
+        base.OnAfterRender(firstRender);
+    }
+
+    protected override async Task OnAfterRenderAsync(bool firstRender)
+    {
+        await slimlock.WaitAsync();
+        EnvironmentSetting.Debug($"RoomTypeInput.OnAfterRenderAsync開始:{firstRender}");
+        await ShowFocus();
+        EnvironmentSetting.Debug($"RoomTypeInput.OnAfterRenderAsync終了:{firstRender}");
+        slimlock.Release();
+    }
+
+    protected override void OnParametersSet()
+    {
+        //EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】RoomTypeInput.OnParametersSet開始:");
+        base.OnParametersSet();
+    }
+
+    protected override bool ShouldRender()
+    {
+        EnvironmentSetting.Debug($"RoomTypeInput.ShouldRender開始:");
+        return base.ShouldRender();
+    }
+
+    #endregion
+
+    #region ★★★★★ Control Event ★★★★★ 
+
+    private async Task Enter(int index, RoomTypeInputRow data, FocusEventArgs e)
+    {
+        await slimlock.WaitAsync();
+        int rowIdx = GetRowIndex(data);
+        Console.WriteLine($"Enter⇒Row:{rowIdx} Col:{index}");
+        slimlock.Release();
+    }
+
+    private async Task Leave(int index, RoomTypeInputRow data, FocusEventArgs e)
+    {
+        string text = string.Empty;
+        try
+        {
+            await slimlock.WaitAsync();
+            Console.WriteLine($"Leave⇒Start");
+            int rowIdx = GetRowIndex(data);
+            text = data.GetCellText(index);
+            Console.WriteLine($"Leave⇒Row:{rowIdx} Col:{index} enterPush:{enterPush}, text:{text}");
+
+            if (enterPush)
+            {
+                //Enterキーを押した時にも既にチェック済
+                enterPush = false;
+            }
+            else
+            {
+                //値変更したら、イベント発生
+                if (!data.IsValueChanged(index, text))
+                {
+                    //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
+                    return;
+                }
+
+                //通常チェックを行う
+                if (!await IsValid(index, text, data, false))
+                {
+                    return;
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            OperationLog.Instance.WriteLog(ex.Message);
+        }
+        finally
+        {
+            //Refresh();    //UI更新(binding値変更通知)
+            Console.WriteLine($"Leave⇒End");
+            slimlock.Release();
+        }
+    }
+
+    /// <summary>
+    /// ※Backspaceここに来る
+    /// </summary>
+    /// <param name="index"></param>
+    /// <param name="data"></param>
+    /// <param name="e"></param>
+    /// <returns></returns>
+    private async Task KeyDown(int index, RoomTypeInputRow data, KeyboardEventArgs e)
+    {
+        if (e.Key == "ArrowUp")
+        {
+            try
+            {
+                EnvironmentSetting.Debug($"ArrowUp:{index}");
+                if (SetAutoNextFocus(index, false, data))
+                {
+                    //BlazorのBugでEnterのパラメータ変数できない!
+                    //Uncaught Error: System.ArgumentException: There is no event handler associated with this event. EventId: '290'. (Parameter 'eventHandlerId')
+                    //mkArtakMSFT modified the milestones: Next sprint planning, 6.0-preview4 on 20 Mar ← Net6.0-preview4対応だそう
+                    keyDownPreventDefault = true;
+                    arrowUpPush = true;
+                }
+                else
+                {
+                    keyDownPreventDefault = false;
+                    arrowUpPush = false;
+                }
+            }
+            catch (Exception ex)
+            {
+                OperationLog.Instance.WriteLog($"KeyDown:{ex.Message}");
+            }
+            finally
+            {
+                Refresh("KeyDown⇒↑");    //UI更新(binding値変更通知)
+            }
+        }
+        else if (e.Key == "End")
+        {
+            if (data.Cells[index].ShowStyle == EShowStyle.ShowList)
+            {
+                data.ActiveCol = index;
+                if (index == (int)RoomTypeInputRow.ColType.ID)
+                {
+                    using DataTable dt = await  MasterCore.GetRoomTypeList();
+                    var parameters = new DialogParameters { ["Data"] = dt };
+                    var dialog = DialogService.Show<SelectList>($"部屋タイプ一覧", parameters);
+                    var ret = await dialog.Result;
+                    if (!ret.Cancelled)
+                    {
+                        var row = ret.Data as DataRow;
+                        EnvironmentSetting.Debug(row[0].ToString());
+                        data.Cells[index].Text = row[0].ToString();
+                        data.Cells[(int)RoomTypeInputRow.ColType.Name].Text = row[1].ToString();
+                        await KeyPress(index, data, new KeyboardEventArgs { Key = "Enter" });
+                        //Refresh("KeyDown⇒End");
+                    }
+                }
+            }
+        }
+        else if (e.Key == "Delete")
+        {
+            if (index == (int)RoomTypeInputRow.ColType.ID)
+            {
+                int rowIdx = GetRowIndex(data);
+                List<RoomTypeInputRow> list = (Data.RoomTypeList as List<RoomTypeInputRow>);
+                bool isLastRow = rowIdx == (list.Count - 1);
+                if (isLastRow) { return; }
+                SetFocus(rowIdx, (int)RoomTypeInputRow.ColType.ID);
+                EnvironmentSetting.Debug($"削除前件数:{list.Count}");
+                list.Remove(data);
+                EnvironmentSetting.Debug($"削除後件数:{list.Count}");
+                keyDownPreventDefault = false;
+                arrowUpPush = false;
+            }
+        }
+        else
+        {
+            keyDownPreventDefault = false;
+            arrowUpPush = false;
+        }
+    }
+
+    /// <summary>
+    /// ※Backspaceここに来ない
+    /// </summary>
+    /// <param name="index"></param>
+    /// <param name="data"></param>
+    /// <param name="e"></param>
+    /// <returns></returns>
+    private async Task KeyPress(int index, RoomTypeInputRow data, KeyboardEventArgs e)
+    {
+        if (e.Key == "Enter")
+        {
+            try
+            {
+                int rowIdx = GetRowIndex(data);
+                Console.WriteLine($"Row:{rowIdx} Col:{index}");
+                Console.WriteLine("Data:" + CConvert.ToJsonText<RoomTypeInputRow>(data));
+
+                //※その時、Fields[index].Textの値まだ変っていない!!!!!
+                string text = await data.GetInputValue(index, JSRuntime);
+                EnvironmentSetting.Debug($"Return:{index}⇒{text}");
+                keyPressPreventDefault = true;   //イベント中止
+                enterPush = true;   //Enterを押した知らせ
+
+                //値変更したら、イベント発生
+                if (data.IsValueChanged(index, text))
+                {
+                    //通常チェックを行う
+                    if (!await IsValid(index, text, data, true)) { return; }
+                }
+                else
+                {
+                    //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
+                    if (text.Trim().Length == 0)
+                    {
+                        //最終行となるはず
+                    }
+                }
+
+                if (!SetAutoNextFocus(index, true, data)) { return; }
+            }
+            catch (Exception ex)
+            {
+                EnvironmentSetting.Debug(ex.Message);
+            }
+            finally
+            {
+                Refresh("KeyPress⇒Enter");    //UI更新(binding値変更通知)
+            }
+        }
+        else
+        {
+            if (CConvert.IsNumPress(e.Key))
+            {
+                keyPressPreventDefault = false;
+            }
+            else
+            {
+                keyPressPreventDefault = true; //入力禁止(※:IMEモードで入力したものをここでは通らないため、防げない)
+            }
+            enterPush = false;
+        }
+    }
+
+    #endregion
+
+    #region ★★★★★ Private Method ★★★★★ 
+
+    private RenderFragment RenderWidget(string msg) => builder =>
+    {
+        builder.OpenComponent(0, typeof(MessageContext));
+        builder.AddAttribute(1, "Text", msg);
+        builder.CloseComponent();
+    };
+
+    /// <summary>
+    /// フォーカス移動準備
+    /// </summary>
+    /// <param name="row"></param>
+    /// <param name="col"></param>
+    /// <param name="action">EditModeの場合、自動で次のフォーカス移動する</param>
+    private void SetFocus(int row, int col, EditGridFocusEventArgs.ActionType action = EditGridFocusEventArgs.ActionType.Focus)
+    {
+        EnvironmentSetting.Debug($"フォーカス移動準備:開始⇒Row:{row},Col:{col},Action:{action},Enabled:{m_CurrentFocusData.Enabled}");
+        m_CurrentFocusData.Row = row;
+        m_CurrentFocusData.Col = col;
+        m_CurrentFocusData.Action = action;
+        m_CurrentFocusData.Enabled = true;
+        EnvironmentSetting.Debug($"フォーカス移動準備:完了⇒Row:{row},Col:{col},Action:{action},Enabled:{m_CurrentFocusData.Enabled}");
+    }
+
+    /// <summary>
+    /// OnAfterRenderAsync時フォーカスを設定
+    /// </summary>
+    private async Task<bool> ShowFocus()
+    {
+        try
+        {
+            EnvironmentSetting.Debug($"SaleInput.FocusAsync行Before:Row={m_CurrentFocusData.Row},Col={m_CurrentFocusData.Col},Action={m_CurrentFocusData.Action},Enabled={m_CurrentFocusData.Enabled}");
+            if (!m_CurrentFocusData.Enabled)
+            {
+                EnvironmentSetting.Debug($"OnAfterRenderAsync⇒return false");
+                return false;
+            }
+            m_CurrentFocusData.Enabled = false;
+
+            EnvironmentSetting.Debug($"ShowFocus処理:Row={m_CurrentFocusData.Row},Col={m_CurrentFocusData.Col},Action={m_CurrentFocusData.Action},Enabled={m_CurrentFocusData.Enabled}");
+            if (m_CurrentFocusData.Action == EditGridFocusEventArgs.ActionType.Focus && m_CurrentFocusData.Row != -1 && m_CurrentFocusData.Col != -1)
+            {
+                //この時点Grid編集状態ですので、フォーカス可能になる
+                EnvironmentSetting.Debug($"フォーカスへ開始:Row = {m_CurrentFocusData.Row}, Col = {m_CurrentFocusData.Col}");
+                await (Data.RoomTypeList as List<RoomTypeInputRow>)[m_CurrentFocusData.Row].Cells[m_CurrentFocusData.Col].Ref.FocusAsync();  //ここに再度OnAfterRenderAsyncに入るが、EnabledはFalseのため、ShowFocusの動作がしない
+                EnvironmentSetting.Debug($"フォーカスへ完了:Row = {m_CurrentFocusData.Row}, Col = {m_CurrentFocusData.Col}");
+            }
+            return true;
+        }
+        catch (Exception ex)
+        {
+            EnvironmentSetting.Debug(ex.Message);
+            return false;
+        }
+    }
+
+
+
+    private int GetRowIndex(RoomTypeInputRow data)
+    {
+        return (Data.RoomTypeList as List<RoomTypeInputRow>).IndexOf(data);
+    }
+
+    /// <summary>
+    /// フォーカス移動
+    /// </summary>
+    /// <param name="index">列Index</param>
+    /// <param name="isEnter"></param>
+    /// <returns></returns>
+    private bool SetAutoNextFocus(int index, bool isEnter, RoomTypeInputRow data)
+    {
+        try
+        {
+            int rowIdx = GetRowIndex(data);
+            List<RoomTypeInputRow> list = (Data.RoomTypeList as List<RoomTypeInputRow>);
+            if (isEnter)
+            {
+                if (index == (int)RoomTypeInputRow.ColType.ID)
+                {
+                    SetFocus(rowIdx, (int)RoomTypeInputRow.ColType.Count);
+                }
+                else
+                {
+                    if (rowIdx == -1)
+                    {
+                        //削除された場合
+                        //await list[list.Count - 1].RefID.FocusAsync();
+                    }
+                    else
+                    {
+                        if (rowIdx < (list.Count - 1))
+                        {
+                            SetFocus(rowIdx + 1, (int)RoomTypeInputRow.ColType.ID);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (index == (int)RoomTypeInputRow.ColType.ID)
+                {
+                    if (rowIdx > 0) { SetFocus(rowIdx - 1, (int)RoomTypeInputRow.ColType.Count); }
+                }
+                else
+                {
+                    SetFocus(rowIdx, (int)RoomTypeInputRow.ColType.ID);
+                }
+            }
+            return true;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+   
+    /// <summary>
+    /// 入力されたIDが存在したかどうか
+    /// </summary>
+    /// <param name="rowIdx"></param>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    private bool IsExistsID(int rowIdx, int id)
+    {
+        List<RoomTypeInputRow> list = (Data.RoomTypeList as List<RoomTypeInputRow>);
+        int i = 0;
+        foreach (RoomTypeInputRow row in list)
+        {
+            if (i == rowIdx) { continue; }
+            if (CConvert.ToInt(row.ID) == id)
+            {
+                return true;
+            }
+            i++;
+        }
+        return false;
+    }
+
+    /// <summary>
+    /// 業務チェック
+    /// </summary>
+    /// <param name="index"></param>
+    /// <param name="inputText"></param>
+    /// <param name="data"></param>
+    /// <param name="isEnter"></param>
+    /// <returns></returns>
+    private async Task<bool> IsValid(int index, string inputText, RoomTypeInputRow data, bool isEnter)
+    {
+        int rowIdx = GetRowIndex(data);
+        //最終行判断
+        List<RoomTypeInputRow> list = (Data.RoomTypeList as List<RoomTypeInputRow>);
+        bool isLastRow = rowIdx == (list.Count - 1);
+
+        if (index == (int)RoomTypeInputRow.ColType.ID)
+        {
+            int id = CConvert.ToInt(inputText);
+            RoomTypeBase typeBase = await MasterCore.GetRoomTypeBase(id);
+            if (typeBase == null)
+            {
+                if (isEnter)
+                {
+                    Message.Show(RenderMessage("該当データが存在しません。"));
+                }
+                else
+                {
+                    Console.WriteLine("該当データが存在しません。");
+                }
+                data.RestoreText(RoomTypeInputRow.ColType.ID);
+                return false;
+            }
+
+            if (IsExistsID(rowIdx, id))
+            {
+                if (isEnter)
+                {
+                    Message.Show(RenderMessage("該当部屋タイプが既に存在します。"));
+                }
+                else
+                {
+                    Console.WriteLine("該当部屋タイプが既に存在します。");
+                }
+                data.RestoreText(RoomTypeInputRow.ColType.ID);
+                return false;
+            }
+            data.SetCellText((int)RoomTypeInputRow.ColType.Name, typeBase.Name);
+
+            if (isLastRow)
+            {
+                //新規
+                data.SetCellText((int)RoomTypeInputRow.ColType.Count, "1");
+
+                //UseRoomを追加:当日
+                var useRoom = await Data.CreateUseRoom(id, typeBase.Kind);
+                data.DataList.Add(useRoom);
+
+                //一番したの新規行表示
+                list.Add(new RoomTypeInputRow());
+            }
+            else
+            {
+                //部屋タイプ変更(データ更新)
+                foreach (var item in data.DataList)
+                {
+                    item.RoomTypeID = id;
+                    item.RoomKind = typeBase.Kind;
+                }
+
+                //画面表示更新
+                data.SetCellText((int)RoomTypeInputRow.ColType.ID, id.ToString());
+            }
+        }
+        else if (index == (int)RoomTypeInputRow.ColType.Count)
+        {
+            if (isLastRow) { return false; }
+            //0の場合、完全に削除する
+            int orgCount = data.DataList.Count;
+            int newCount = CConvert.ToInt(inputText);
+
+            //UseRoomの±
+            int count = newCount - orgCount;
+            if (count > 0)
+            {
+                for (int i = 0; i < count; i++)
+                {
+                    var useRoom = await Data.CreateUseRoom(data.DataList[0].RoomTypeID, data.DataList[0].RoomKind);
+                    data.DataList.Add(useRoom);
+                }
+            }
+            else
+            {
+                Data.RemoveUseRoom(data.DataList, -count);
+            }
+
+            if (newCount == 0)
+            {
+                list.Remove(data);
+                if (rowIdx >= list.Count)
+                {
+                    SetFocus(list.Count - 1, (int)RoomTypeInputRow.ColType.ID);
+                }
+                else
+                {
+                    SetFocus(rowIdx, (int)RoomTypeInputRow.ColType.ID);
+                }
+                return false;
+            }
+
+            data.SetCellText(index, CConvert.ToInt(inputText).ToString());
+        }
+        return true;
+    }
+
+    #endregion
+
+    #region ★★★★★ Public Method ★★★★★ 
+
+    /// <summary>
+    /// コントロール再表示
+    /// </summary>
+    public void Refresh(string type)
+    {
+        EnvironmentSetting.Debug($"再表示へ開始:{type}");
+        StateHasChanged();
+        EnvironmentSetting.Debug($"再表示へ終了:{type}");
+        if(OnRefresh != null) { OnRefresh(); }
+    }
+
+    #endregion
+}

--
Gitblit v1.10.0